How you can’t use Docker’s Go client

I wanted to build a tool which simplify and make faster command executions in docker containers. Here it is, where we can have three word to run a command in a docker container. So I want to tell a funny story about how I got into Docker’s Go client library.

Disclaimer: I’m not stupid and don’t want to blame anybody, I just wanted to make fun of how I found the solution!

Update 1: I found a related issue.

I read about how I can work with the Docker’s Go library, so as many Go developers I wanted to see what’s inside the GoDoc. So as it is shown in the example it looks like this:

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)
}
}

That’s looks easy. Let’s import the package then.
go get github.com/docker/docker

Hm…

Let’s see what we can have instead of this.

Looks similar. Let’s use the client.NewEnvClient(), but it’s ran into issues. So I started to dig into the code. I thought it would be something like the DOCKER_HOST environment variable, so I started to search for that. And yes, I found it.

host := os.Getenv("DOCKER_HOST")

Cool. Let’s look what’s inside this environment variable.

$ echo $DOCKER_HOST$

It’s empty. This answers everything. But what should I put into this environment variable? I have searched for that and quickly found the best solution the human race can imagine: localhost:2375. Localhost what? I’m not stupid, so I used telnet.

$ telnet localhost 2375
Trying ::1...
telnet: connect to address ::1: Connection refused

Connection refused, oh you don’t say. But wait, there is a DefaultDockerHost. Then I will go with this, so I will use the client.NewClient(...). But it wants extra parameters like version, http.Client and http headers. There is a DefaultVersion as well. Cool, let’s pass them and create an http.Client, however the default host is unix://var/run/docker.sock, but I will pass that http.Client if it wants it.

$ go run main.go 
panic: unable to verify TLS configuration, invalid transport <nil>

I’m an experienced Go developer. &tls.Config{InsecureSkipVerify: true}
Let’s try it again.

$ go run main.go 
panic: error during connect: Get https://%2Fvar%2Frun%2Fdocker.sock/v1.25/containers/json?limit=0: dial tcp: lookup /var/run/docker.sock: no such host

Frankly, I’m not surprised. Let’s skip this dump step, I don’t want to look stupid. After I have removed the http.Client I finally got the cli and the code above worked properly.

Finally.

Don’t be so happy. That was only the connection. I want to run a command inside a Docker container. I search for that. Nothing relevant found, so let’s see the code.

Cool, but what should I use?

ExecAttach: Attaches a connection to an exec process in the server.
ExecStart: Starts an exec process already created in the docker host.
ExecCreate: Creates a new exec configuration to run an exec process.
ExecInspect: Returns information about a specific exec process on the docker host.

That’s not that hard, Create and Start. Nobody makes mistakes with that.

May I ask for a response? Let’s dig into the code once more. AHA!

So we know that the response which I want will be closed. Let’s see what else we have. I don’t exactly know what attach means in a programming language library, but it returns something at least. HijackResponse, hm. I’m ok with it, but it’s maybe because of the lack of my English. I don’t know what is this. No worries, comments will describe it.

Anyway, there is a Reader in it. Finally I will get some response.

I added the Cmd on both places just to make sure. Let’s try and finish it. Thanks for the ioutil.ReadAll I could read the response and I could finish it.

$ go run main.goResponse: 

I can’t believe it. What else can I add to get some F*** response?

Yes, sure, attach it.

Thank you for being here.

--

--

--

Gopher, Rustacean, Hobby Hacker

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Checklist For A Reliable Load-Test

Python Collections Module

HOW TO INTEGRATE YOUR ANDROID PROJECT IN HUAWEI PUSH KIT SERVICE FOR SENDING PUSH NOTIFICATIONS

How to Find a Coding Mentor Using LinkedIn

Einstein Bots for Employees, the Easy Way

ARTS Week 6

Why Must Scrum Masters Balance ‘Working with What They Have’ and ‘Pushing The Envelope’?

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
PumpkinSeed

PumpkinSeed

Gopher, Rustacean, Hobby Hacker

More from Medium

Use exec.Command to execute a command with a pipe

How to Check nil Interface in Golang?

How to upgrade Golang Compiler from version 1.13.5 to version 1.17.1

Replacing a computer component is just like replacing a Go-Compiler

Go: then interfaces is not very equal