If you are using go modules and want to use the client from docker/docker in your code you would do something like this:
1package main
2
3import (
4 "context"
5 "fmt"
6
7 "github.com/docker/docker/api/types"
8 "github.com/docker/docker/client"
9)
10
11func main() {
12 c, err := client.NewClientWithOpts(client.FromEnv)
13 if err != nil {
14 fmt.Println(err)
15 return
16 }
17
18 containers, err := c.ContainerList(context.Background(), types.ContainerListOptions{})
19 if err != nil {
20 fmt.Println(err)
21 return
22 }
23
24 for _, container := range containers {
25 fmt.Println(container.ID)
26 }
27}
If you then try and build your code you will be greeted with a nice error message:
./main.go:12:15: undefined: client.NewClientWithOpts
./main.go:12:40: undefined: client.FromEnv
What just happened? If you look at your go.mod
file you would see something like this:
require (
...
github.com/docker/docker v1.13.1 // indirect
...
)
It its great wisdom, go mod
decided to take the v1.13.1
tag because this is the latest tag that happens to be semver valid. The problem with this tag is that it was created in 2017. And client.NewClientWithOpts
did not exist in 2017.
Here’s how to fix this shenanigans: add github.com/docker/docker master
in your go.mod file and execute go mod tidy
. If you now look at your go.mod
file you will see something like this:
github.com/docker/docker v17.12.0-ce-rc1.0.20200508181053-298ba5b13150+incompatible
I am unsure why it takes the v17.12.0-ce-rc1
tag but the 298ba5b13150
sha is indeed the sha of the latest commit on docker/docker at this time
If you now try to build the code above it will work as expected.
Note: you could have also changed your code to create a client with c, err := client.NewEnvClient()
and the code would have worked, this is because the docker team made it so that even an older client can talk to the latest engine, and this is kinda awesome.
Why this happens? The reason is twofold:
docker/docker
uses calver (calendar versions)go mod
uses semver (semantic versions)This means that even if docker/docker
released a bunch of new versions since 2017, its way of naming tags (latest tag right now is v19.03.8
) makes it incompatible with the way go mod
thinks you should name your tags. Fortunately there is a solution, I just wished life was easier sometimes.