Paul Sitoh

I'm a software engineer who enjoys coding principally in Go and where necessary other languages.

Creating and running docker container via Go SDK

20 Aug 2021 » go, docker

About this post

In this post, I’ll briefly describe the steps involved in using the Docker Go SDK to create and run a Docker container.

I am going to replicate a Docker cli command for running a container using the Docker Go SDK. The cli command pattern is

$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

For the purpose of this post, I am going to replicate this specific command:

docker run --name my_container --network=my-network -v /opt:/opt -p 80:80 ubuntu:latest

The purpose of replicating the cli is to illustrate aspects of the Go SDK pertaining to the creation and running of container. It is not to advocate the replacement of Docker cli commands. There are more meaningful use cases for the Go SDK but it is beyond the scope of this post. I’ll leave you to imagine the kind of use cases for Go SDK.

Running a container using Go SDK

The first step in creating and running a container is instantiating a docker client. This is as follows:

cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
   log.Fatal(err)
}

Having created the docker client, the next step is to create a container from an image. In this post, I am creating a container from the latest ubuntu image.

The requirements for our running container are as follows:

  • assigned the container the name my_container;

  • associate the container to the network name my-network;

  • mount the host volume name /opt to the volume in the container name /opt;

  • map the host port 80 to a port (i.e. 80) exposed by the container.

The step to implement these requirements in Go SDK are as follows:

config := &container.Config{
  Image: "ubuntu:latest",
  ExposedPorts: nat.PortSet{
    nat.Port("80"): {},
  },
}

hostConfig := &container.HostConfig{
   PortBindings: map[nat.Port][]nat.PortBinding{
     nat.Port("80"): []nat.PortBinding{
        {
          HostIP:   "0.0.0.0",
          HostPort: "80",
        },
     },
   }
   Mounts:[]mount.Mount{
      {
        Type: mount.TypeVolume
        Source: "/opt",
        Target: "/opt",
      },
   },
}

netConfig := &network.NetworkingConfig{
  EndpointsConfig: map[string]*network.EndpointSettings{
    "network": {
      NetworkID: "my-network",
    },
  },
}

These Go SDK codes are the equivalent of Docker run cli options at the start of this post.

To create the container based on the options mentioned above, the equivalent Go SDK command is as follows:

resp, _ := cli.ContainerCreate(context.TODO(), config, hostConfig, netConfig, nil, name)

The argument with nil value is an advanced option related to the platform specification. It is not commonly used. If you wish to learn more, please refer to the Official Documentation for details.

Finally, to run the container as a background process, execute this command:

cli.ContainerStart(context.TODO(), resp.ID, types.ContainerStartOptions{})

Summing up

In this post, I have covered the most common and basic Docker container operation. To learn more about the operations mentioned in this post, please refer to the API specification for ContainerCreate and ContainerStart.

There are more advance Docker container related operations but they generally follow the pattern described in this post. If you like to learn more, please refer to https://pkg.go.dev/github.com/ph/moby/client.