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 ps
would :
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.ContainerListOptions
modifying the All
property 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 ls
or 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。