I need to know Docker Daemon API version and setup the environment variable of DOCKER_API_VERSION when I have to create Docker client with NewEnvClient(), if not I will get an error about:
Error response from daemon: client version 1.36 is too new. Maximum supported API version is 1.35
If you are executing your code in the same docker host you can use the following approach to get the API version. It execute docker version command and get the API version from that output.
package main
import (
"os/exec"
"bytes"
"os"
"github.com/docker/docker/client"
"golang.org/x/net/context"
"github.com/docker/docker/api/types"
"strings"
)
func main() {
cmd := exec.Command("docker", "version", "--format", "{{.Server.APIVersion}}")
cmdOutput := &bytes.Buffer{}
cmd.Stdout = cmdOutput
err := cmd.Run()
if err != nil {
panic(err)
}
apiVersion := strings.TrimSpace(string(cmdOutput.Bytes()))
// TODO: (optional) verify the api version is in the correct format(a.b)
os.Setenv("DOCKER_API_VERSION", apiVersion)
// execute docker commands
ctx := context.Background()
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
_, err = cli.ImagePull(ctx, "alpine", types.ImagePullOptions{})
if err != nil {
panic(err)
}
}
Related
I am trying to create docker container from my golang application using Docker Engine SDKs and Docker API
this is the command i want to implement in my application:
docker run --name rinkeby-node ethereum/client-go --rinkeby --syncmode full
this is the code i am using
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
imageName := "ethereum/client-go"
out, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
if err != nil {
panic(err)
}
defer out.Close()
io.Copy(os.Stdout, out)
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: imageName,
}, nil, nil, nil, "containerName")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
panic(err)
}
fmt.Println(resp.ID)
now i want to specify the syncmode to full and the network to rinkeby
The --syncmode full and --rinkeby flags are the CMD arguments.
So when calling you're calling ContainerCreate method inside of container.Config add this:
Cmd: []string{"--syncmode", "full", "--rinkeby"}
For a complete example see this
I want to pull a docker image from my local system.
Image name is : example
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
imageName := "example:latest"
out, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
if err != nil {
panic(err)
}
current code is giving me something like this :
panic: Error response from daemon: pull access denied for example, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
Is it possble to pass local docker image to this method, if yes, how ?
First, you can build image locally with tag 'localhost/example:latest'
$ docker build -t "localhost/example:latest" .
Than, you can prepend localhost to image name, so it will try local registry to pull image, so, you can try this:
package main
import (
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main(){
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
imageName := "localhost/example:latest" // <- localhost prepended!
out, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
if err != nil {
panic(err)
}
fmt.Println(out)
}
I am using the Go Docker Client to attempt to build an image from a Dockerfile whose contents are defined in code.
According to the 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.
So I want to create the build context in code, write it to a tar file, then send that to the Docker Daemon to be built. To do this I can use the ImageBuild function and pass in the tar file (build context) as an io.ReadCloser. As long as my Dockerfile is at the root of that compressed archive, it should find it and build it.
However, I get the common error:
Error response from daemon: Cannot locate specified Dockerfile: Dockerfile
Which obviously means that it can't find the Dockerfile at the root of the archive. I am unsure why. I believe the way I am doing this adds a Dockerfile to the root of the tar archive. The daemon should see this. What am I misunderstanding here?
code snippet to reproduce
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 file
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
)
Add a zero in front of 777 for octal numeral system: 0777, 0o777, or 0O777
Use reader := bytes.NewReader(buf.Bytes()) not tar.NewReader(&buf)
Use client.WithAPIVersionNegotiation() for newer versions too.
Try this working version:
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)
}
}
Output for docker image ls after 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
Output for docker run alpine-echo:1.2.4:
this is from the archive
Note: You may need to edit FROM alpine:3.10.3 for your specific version.
I use golang to develop application . I want get container in application.I hava tired by shell.But I want to get container by go. thanks
You can use docker/client
https://godoc.org/github.com/docker/docker/client
Example code:
# listcontainers.go
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
for _, container := range containers {
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
}
}
Then execute it like this
DOCKER_API_VERSION=1.35 go run listcontainers.go
More about docker engine SDKs and API
https://docs.docker.com/develop/sdk/
I am trying to use Docker's tutorial in recreating a docker run. Here is the following code from online tutorial
package main
import (
"io"
"os"
"github.com/docker/docker/client"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"golang.org/x/net/context"
)
func main() {
ctx := context.Background()
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
_, err = cli.ImagePull(ctx, "alpine", types.ImagePullOptions{})
if err != nil {
panic(err)
}
resp, err := cli.ContainerCreate(ctx, &container.Config{
Image: "alpine",
Cmd: []string{"echo", "hello world"},
}, nil, nil, "")
if err != nil {
panic(err)
}
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
panic(err)
}
if _, err = cli.ContainerWait(ctx, resp.ID); err != nil {
panic(err)
}
out, err := cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true})
if err != nil {
panic(err)
}
io.Copy(os.Stdout, out)
}
The problem I see with this is, if 'alpine' docker, is not available locally, it doesn't pull the latest and ends up throwing an error.
e.g
XXXXX$ go run go_docker.go
panic: Error: No such image: alpine
goroutine 1 [running]:
panic(0x27ffa0, 0xc4202afa50)
/usr/local/go/src/runtime/panic.go:500 +0x1a1
main.main()
/Users/rvenkatesh/go_coding/raghu_test_code/go_docker.go:30 +0x592
exit status 2
But when I run the commandline equivalent, I see
XXXX$ docker run alpine echo hello world
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
627beaf3eaaf: Pull complete
Digest:sha256:58e1a1bb75db1b5a24a462dd5e2915277ea06438c3f105138f97eb53149673c4
Status: Downloaded newer image for alpine:latest
hello world
I tried looking through Go client, do I need to tweak anything with ImagePull function? Any help here would be appreciated!
Here is the link to the docs https://docs.docker.com/engine/api/getting-started/
Update: I had tested the same tutorial for python version, and it worked just fine. I wonder if the Golang page needs update.
Was having the same issue, the "Pull" didn't seem to be working. Found a Fix though.
1) Modify your pull line to
pullstat, err = cli.ImagePull(ctx, "alpine", types.ImagePullOptions{})
and add
io.Copy(os.StdOut,pullstat)
after the ImagePull
I haven't tried doing an
io.Copy(nil,pullstat)
but that's on my list of things to try next.
Image.Pull returns an io.Reader which you must read and close; if you do not the connection will be closed before the image is pulled.
You can just discard the contents of it and close it, then the pull will work.
The docker client is open source and written in Go, so you can see exactly how they've implemented their version. I believe the relevant code is in the container/create.go pullImage function.