我正在使用Go Docker Client来尝试根据内容由代码定义的Dockerfile
构建图像。
根据Docker Daemon API Documentation
输入流必须是tar存档...
...归档文件必须在归档文件的根目录中包含一个构建说明文件,通常称为Dockerfile。
所以我想在代码中创建构建上下文,将其写入tar文件,然后将其发送到要构建的Docker Daemon。为此,我可以使用ImageBuild function并将tar文件(构建上下文)作为io.ReadCloser
传递。只要我的Dockerfile
位于该压缩存档的根目录下,它就应该找到并构建它。
但是,我遇到了常见错误:
Error response from daemon: Cannot locate specified Dockerfile: Dockerfile
这显然意味着它无法在档案的根目录下找到Dockerfile。我不确定为什么。我相信我这样做的方式会在tar归档文件的根目录中添加一个Dockerfile
。守护程序应该看到这一点。我在这里误会什么?
要复制的代码段
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
)
答案 0 :(得分:2)
在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
。