docker - 使用 Go 客户端将 Docker 上下文作为 Tar 发送找不到 Dockerfile
问题描述
我正在使用Go Docker 客户端尝试从其Dockerfile
内容在代码中定义的图像构建图像。
根据Docker Daemon API Documentation
输入流必须是 tar 存档...
...存档必须包含一个构建指令文件,通常在存档的根目录中称为 Dockerfile。
所以我想在代码中创建构建上下文,将其写入一个 tar 文件,然后将其发送到要构建的 Docker 守护进程。为此,我可以使用ImageBuild 函数并将 tar 文件(构建上下文)作为io.ReadCloser
. 只要 myDockerfile
位于该压缩存档的根目录,它就应该找到并构建它。
但是,我得到了常见的错误:
Error response from daemon: Cannot locate specified Dockerfile: Dockerfile
这显然意味着它无法在存档的根目录中找到 Dockerfile。我不确定为什么。我相信我这样做的方式会Dockerfile
在 tar 存档的根目录中添加一个。守护进程应该看到这一点。我在这里有什么误解?
重现的代码片段
var buf bytes.Buffer
tarWriter := tar.NewWriter(&buf)
contents := "FROM alpine\nCMD [\"echo\", \"this is from the archive\"]"
if err := tarWriter.WriteHeader(&tar.Header{
Name: "Dockerfile",
Mode: 777,
Size: int64(len(contents)),
Typeflag: tar.TypeReg,
}); err != nil {
panic(err)
}
if _, err := tarWriter.Write([]byte(contents)); err != nil {
panic(err)
}
if err := tarWriter.Close(); err != nil {
panic(err)
}
reader := tar.NewReader(&buf)
c, err := client.NewEnvClient()
if err != nil {
panic(err)
}
_, err = c.ImageBuild(context.Background(), reader, types.ImageBuildOptions{
Context: reader,
Dockerfile: "Dockerfile",
})
if err != nil {
panic(err)
}
go.mod 文件
module docker-tar
go 1.12
require (
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v1.13.1
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/pkg/errors v0.8.1 // indirect
golang.org/x/net v0.0.0-20191112182307-2180aed22343 // indirect
)
解决方案
777
在八进制数字系统前面添加一个零:0777
,0o777
, 或0O777
reader := bytes.NewReader(buf.Bytes())
不使用tar.NewReader(&buf)
也用于
client.WithAPIVersionNegotiation()
较新的版本。试试这个工作版本:
package main
import (
"archive/tar"
"bytes"
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
var buf bytes.Buffer
tarWriter := tar.NewWriter(&buf)
contents := `FROM alpine:3.10.3
CMD ["echo", "this is from the archive"]
`
header := &tar.Header{
Name: "Dockerfile",
Mode: 0o777,
Size: int64(len(contents)),
Typeflag: tar.TypeReg,
}
err := tarWriter.WriteHeader(header)
if err != nil {
panic(err)
}
_, err = tarWriter.Write([]byte(contents))
if err != nil {
panic(err)
}
err = tarWriter.Close()
if err != nil {
panic(err)
}
c, err := client.NewClientWithOpts(client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
fmt.Println(c.ClientVersion())
reader := bytes.NewReader(buf.Bytes()) // tar.NewReader(&buf)
ctx := context.Background()
buildOptions := types.ImageBuildOptions{
Context: reader,
Dockerfile: "Dockerfile",
Tags: []string{"alpine-echo:1.2.4"},
}
_, err = c.ImageBuild(ctx, reader, buildOptions)
if err != nil {
panic(err)
}
}
docker image ls
之后的输出go run .
:
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine-echo 1.2.4 d81774f32812 26 seconds ago 5.55MB
alpine 3.10.3 b168ac0e770e 4 days ago 5.55MB
输出docker run alpine-echo:1.2.4
:
this is from the archive
注意:您可能需要FROM alpine:3.10.3
针对您的特定版本进行编辑。
推荐阅读
- python - Python:exec()参数中的函数不起作用
- c++ - 如何创建正确的嵌套循环?
- php - 从愿望清单中获得最佳分配
- javascript - 使用 UIkit 和 NextJs 时如何修复“警告:道具类名不匹配”
- python - JWT 授权和令牌泄漏
- c# - 以安全的方式使用 C# WPF 关闭 SerialPort 对象
- apache-flink - 如何使用单个 Flink 应用程序提交多个 Flink 作业
- java - 我可以创建可以创建为类型数组 [大小] 的自定义 Java 数组吗?
- node.js - 为什么在查找查询中传递 req.params 在节点 js/mongo 中不起作用
- kubernetes - 错误:连接中断:在 Kubernetes 中使用 Jenkins 时出现 java.nio.channels.ClosedChannelException