Docker(Moby)golang镜像构建日志是base64编码的



我正在寻找从基于Golang的客户端使用docker客户端库发送的dockerd(buildkit/moby(镜像构建请求中提取镜像构建日志的帮助。

我可以请求图像构建良好,并接收json消息的日志流,然后将它们解码为Jsonmessage实例。但是来自构建器的实际日志行似乎是base64编码在每个json消息的aux字段中。

我可以很容易地解码base64,但它们似乎包括奇怪的终端控制字符和可能错误编码的数据,这让我怀疑它们是否真的是我应该解包的某种结构的base64编码。

让我困惑的是,在显示docker buildx build的构建进度时处理日志时,我在docker ce或moby代码中找不到任何似乎基于64解码"aux"有效载荷的内容。

据我所知,buildx代码对aux负载没有做任何特殊的事情:https://github.com/docker/docker-ce/blob/523cf7e71252013fbb6a590be67a54b4a88c1dae/components/cli/cli/command/image/build_buildkit.go#L325

例如,精简的构建代码,如:

image := Image{Name:      "test"}
contextreader, err := archive.TarWithOptions(buildConf.Build.Context, &archive.TarOptions{})
if err != nil {
return err
}
imageBuildResponse, err := b.client.ImageBuild(
ctx,
contextreader,
types.ImageBuildOptions{
Version:     types.BuilderBuildKit,
Context:     contextreader,
Dockerfile:  dockerfile,
})
if err != nil {
return err
}
defer imageBuildResponse.Body.Close()

buf := bytes.NewBuffer(nil)
imageID := ""
writeAux := func(msg jsonmessage.JSONMessage) {
if msg.ID == "moby.image.id" {
var result types.BuildResult
if err := json.Unmarshal(*msg.Aux, &result); err != nil {
panic("don't do this in your real code")
}
imageID = result.ID
return
}
return err
}
err := jsonmessage.DisplayJSONMessagesStream(imageBuildResponse.Body, buf, os.Stderr.Fd(), false /* not terminal */, writeAux)
if err != nil {
if jerr, ok := err.(*jsonmessage.JSONError); ok {
// If no error code is set, default to 1
if jerr.Code == 0 {
jerr.Code = 1
}
return fmt.Errorf("error while building image: %s", jerr.Message)
}
}

会像一样将json有效负载写入stderr

{"id":"moby.buildkit.trace","aux":"Cn0KR3NoYTI1NjozZThhMzMxYmRkZGFjNWZkYmNjOGVhMDFmYWFhYmM3MjA0MDkwMmYwNjdmYzRhOGY0NDJmMmIzYWVlN2RkNGIyGiRbaW50ZXJuYWxdIGxvYWQgcmVtb3RlIGJ1aWxkIGNvbnRleHQqDAiYw8KaBhCykpCqAg=="}
{"id":"moby.buildkit.trace","aux":"CokBCkdzaGEyNTY6M2U4YTMzMWJkZGRhYzVmZGJjYzhlYTAxZmFhYWJjNzIwNDA5MDJmMDY3ZmM0YThmNDQyZjJiM2FlZTdkZDRiMhokW2ludGVybmFsXSBsb2FkIHJlbW90ZSBidWlsZCBjb250ZXh0KgwImMPCmgYQspKQqgIyCgiZw8KaBhD08F0="}

这里的base64字符串不能作为有效的utf-8进行解码,它们也不能作为ISO-8859-1进行解码。例如,使用utf-8控制台编码:

$ base64 -d <<<'Cn0KR3NoYTI1NjozZThhMzMxYmRkZGFjNWZkYmNjOGVhMDFmYWFhYmM3MjA0MDkwMmYwNjdmYzRhOGY0NDJmMmIzYWVlN2RkNGIyGiRbaW50ZXJuYWxdIGxvYWQgcmVtb3RlIGJ1aWxkIGNvbnRleHQqDAiYw8KaBhCykpCqAg=='
}
Gsha256:3e8a331bdddac5fdbcc8ea01faaabc72040902f067fc4a8f442f2b3aee7dd4b2�$[internal] load remote build context*
                                        ������

它看起来可能是一个结构体,但就我而言,我找不到是什么解码和处理它

所以我当然是在写So问题的时候找到答案的。。。

build_buildkit.go中的writeAux函数调用了tracer实例的write方法,该方法完成了实际工作。我一定是瞎了眼。

这些消息是来自github.com/moby/buildkit/api/services/control包的StatusResponse的序列化实例。它们是从base64解码的字节序列中解组并检查的。如果您想要日志并跳过其他所有内容,只需查找具有非空Logs成员数组的实例,例如上面的writeAux函数中的类似内容:

} else if msg.ID == "moby.buildkit.trace" {
// Process the message like
// https://github.com/docker/docker-ce/blob/523cf7e71252013fbb6a590be67a54b4a88c1dae/components/cli/cli/command/image/build_buildkit.go#L386
// the 'tracer.write' method in build_buildkit.go
var resp controlapi.StatusResponse
var dt []byte
// ignoring all messages that are not understood
if err := json.Unmarshal(*msg.Aux, &dt); err != nil {
return
}
if err := (&resp).Unmarshal(dt); err != nil {
return
}
for _, v := range resp.Vertexes {
fmt.Printf("layer: %+v", v)
}
for _, v := range resp.Statuses {
fmt.Printf("status: %+v", v)
}
for _, v := range resp.Logs {
fmt.Printf("log: msg.Msg)
}
}

json.Unmarshalcontrolapi.StatusResponse.Unmarshal为您进行base64解码和解包。

最新更新