Play with Docker API with Golang | Go Theme Month

Docker provides an API for interacting with the Docker daemon (called the Docker Engine API), and we can build and extend Docker applications and solutions using the official Go SDK.

Install SDK

The SDK can be installed with the following command:

go get github.com/docker/docker/client
复制代码

Manage local Docker

This section will introduce how to use Golang + Docker API to manage local Docker.

run the container

The first example will show how to run the container equivalent to docker run docker.io/library/alpine echo "hello world":

package main

import (
    "context"
    "io"
    "os"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/client"
    "github.com/docker/docker/pkg/stdcopy"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    reader, err := cli.ImagePull(ctx, "docker.io/library/alpine", types.ImagePullOptions{})
    if err != nil {
        panic(err)
    }
    io.Copy(os.Stdout, reader)

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

    statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
    select {
    case err := <-errCh:
        if err != nil {
            panic(err)
        }
    case <-statusCh:
    }

    out, err := cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true})
    if err != nil {
        panic(err)
    }

    stdcopy.StdCopy(os.Stdout, os.Stderr, out)
}
复制代码

Running containers in the background

You can also run containers in the background, equivalent to docker run -d bfirsh/reticulate-splines:

package main

import (
    "context"
    "fmt"
    "io"
    "os"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    imageName := "bfirsh/reticulate-splines"

    out, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
    if err != nil {
        panic(err)
    }
    io.Copy(os.Stdout, out)

    resp, err := cli.ContainerCreate(ctx, &container.Config{
        Image: imageName,
    }, nil, nil, "")
    if err != nil {
        panic(err)
    }

    if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
        panic(err)
    }

    fmt.Println(resp.ID)
}
复制代码

View a list of containers

List running containers as you docker pswould :

package main

import (
    "context"
    "fmt"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    containers, err := cli.ContainerList(ctx, types.ContainerListOptions{})
    if err != nil {
        panic(err)
    }

    for _, container := range containers {
        fmt.Println(container.ID)
    }
}
复制代码

If so docker ps -a, we can do this by types.ContainerListOptionsmodifying the Allproperty in :

// type ContainerListOptions struct {
// 	Quiet   bool
// 	Size    bool
// 	All     bool
// 	Latest  bool
// 	Since   string
// 	Before  string
// 	Limit   int
// 	Filters filters.Args
// }

options := types.ContainerListOptions{
    All: true,
}
containers, err := cli.ContainerList(ctx, options)
if err != nil {
    panic(err)
}
复制代码

Stop all running containers

With the above example, we can get a list of containers, so in this case, we can go and stop all running containers.

Note: Do not run the code below on a production server.

package main

import (
    "context"
    "fmt"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    containers, err := cli.ContainerList(ctx, types.ContainerListOptions{})
    if err != nil {
        panic(err)
    }

    for _, container := range containers {
        fmt.Print("Stopping container ", container.ID[:10], "... ")
        if err := cli.ContainerStop(ctx, container.ID, nil); err != nil {
            panic(err)
        }
        fmt.Println("Success")
    }
}
复制代码

Get the logs of the specified container

By specifying the ID of the container, we can get the logs of the container with the corresponding ID:

package main

import (
    "context"
    "io"
    "os"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    options := types.ContainerLogsOptions{ShowStdout: true}

    out, err := cli.ContainerLogs(ctx, "f1064a8a4c82", options)
    if err != nil {
        panic(err)
    }

    io.Copy(os.Stdout, out)
}
复制代码

View mirror list

Get all local images, equivalent to docker image lsor docker images:

package main

import (
    "context"
    "fmt"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    images, err := cli.ImageList(ctx, types.ImageListOptions{})
    if err != nil {
        panic(err)
    }

    for _, image := range images {
        fmt.Println(image.ID)
    }
}
复制代码

pull image

Pull the specified image, which is equivalent to docker pull alpine:

package main

import (
    "context"
    "io"
    "os"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    out, err := cli.ImagePull(ctx, "alpine", types.ImagePullOptions{})
    if err != nil {
        panic(err)
    }

    defer out.Close()

    io.Copy(os.Stdout, out)
}
复制代码

Pull private image

In addition to public images, we usually use some private images, which can be private images on DockerHub or self-hosted image repositories, such as harbor . At this time, we need to provide the corresponding credentials to be able to pull the image.

It is worth noting that when using the Go SDK of the Docker API, the credentials are transmitted in clear text, so if it is a self-built image repository, be sure to use it HTTPS!

package main

import (
    "context"
    "encoding/base64"
    "encoding/json"
    "io"
    "os"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    authConfig := types.AuthConfig{
        Username: "username",
        Password: "password",
    }
    encodedJSON, err := json.Marshal(authConfig)
    if err != nil {
        panic(err)
    }
    authStr := base64.URLEncoding.EncodeToString(encodedJSON)

    out, err := cli.ImagePull(ctx, "alpine", types.ImagePullOptions{RegistryAuth: authStr})
    if err != nil {
        panic(err)
    }

    defer out.Close()
    io.Copy(os.Stdout, out)
}
复制代码

保存容器成镜像

我们可以将一个已有的容器通过 commit 保存成一个镜像:

package main

import (
    "context"
    "fmt"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        panic(err)
    }

    createResp, err := cli.ContainerCreate(ctx, &container.Config{
        Image: "alpine",
        Cmd:   []string{"touch", "/helloworld"},
    }, nil, nil, "")
    if err != nil {
        panic(err)
    }

    if err := cli.ContainerStart(ctx, createResp.ID, types.ContainerStartOptions{}); err != nil {
        panic(err)
    }

    statusCh, errCh := cli.ContainerWait(ctx, createResp.ID, container.WaitConditionNotRunning)
    select {
    case err := <-errCh:
        if err != nil {
            panic(err)
        }
    case <-statusCh:
    }

    commitResp, err := cli.ContainerCommit(ctx, createResp.ID, types.ContainerCommitOptions{Reference: "helloworld"})
    if err != nil {
        panic(err)
    }

    fmt.Println(commitResp.ID)
}
复制代码

管理远程的 Docker

当然,除了可以管理本地的 Docker, 我们同样也可以通过使用 Golang + Docker API 管理远程的 Docker。

远程连接

默认 Docker 是通过非网络的 Unix 套接字运行的,只能够进行本地通信(/var/run/docker.sock),是不能够直接远程连接 Docker 的。

我们需要编辑配置文件 /etc/docker/daemon.json,并修改以下内容(把 192.168.59.3 改成你自己的 IP 地址),然后重启 Docker:

# vi /etc/docker/daemon.json
{
  "hosts": [
    "tcp://192.168.59.3:2375",
    "unix:///var/run/docker.sock"
  ]
}

systemctl restart docker
复制代码

修改 client

创建 client 的时候需要指定远程 Docker 的地址,这样就可以像管理本地 Docker 一样管理远程的 Docker 了:

cli, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation(),
    client.WithHost("tcp://192.168.59.3:2375"))
复制代码

总结

现在已经有很多可以管理 Docker 的产品,它们便是这样进行实现的,比如:portainer

原文链接:k8scat.com/posts/play-…

Guess you like

Origin juejin.im/post/6944730766052065288