使用 Go 客户端发送 Docker 上下文为 Tar 找不到 Docker 文件
Send Docker Context as Tar with Go Client can't find Dockerfile
我正在使用 Go Docker Client 尝试从 Dockerfile
构建图像,其内容在代码中定义。
根据 Docker Daemon API Documentation
The input stream must be a tar archive...
...The archive must include a build instructions file, typically called Dockerfile at the archive’s root.
所以我想在代码中创建构建上下文,将其写入 tar 文件,然后将其发送到要构建的 Docker 守护进程。为此,我可以使用 ImageBuild function 并将 tar 文件(构建上下文)作为 io.ReadCloser
传递。只要我的 Dockerfile
位于该压缩存档的根目录下,它就应该找到并构建它。
但是,我得到了常见错误:
Error response from daemon: Cannot locate specified Dockerfile: Dockerfile
这显然意味着它无法在存档的根目录下找到 Docker 文件。我不确定为什么。我相信我这样做的方式会在 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
)
在 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
。
我正在使用 Go Docker Client 尝试从 Dockerfile
构建图像,其内容在代码中定义。
根据 Docker Daemon API Documentation
The input stream must be a tar archive...
...The archive must include a build instructions file, typically called Dockerfile at the archive’s root.
所以我想在代码中创建构建上下文,将其写入 tar 文件,然后将其发送到要构建的 Docker 守护进程。为此,我可以使用 ImageBuild function 并将 tar 文件(构建上下文)作为 io.ReadCloser
传递。只要我的 Dockerfile
位于该压缩存档的根目录下,它就应该找到并构建它。
但是,我得到了常见错误:
Error response from daemon: Cannot locate specified Dockerfile: Dockerfile
这显然意味着它无法在存档的根目录下找到 Docker 文件。我不确定为什么。我相信我这样做的方式会在 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
)
在
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
。