Docker proporciona una API para interactuar con el demonio de Docker (llamado Docker Engine API), y podemos crear y ampliar aplicaciones y soluciones de Docker utilizando el Go SDK oficial.
Instalar SDK
El SDK se puede instalar con el siguiente comando:
go get github.com/docker/docker/client
复制代码
Administrar Docker local
Esta sección presentará cómo usar Golang + Docker API para administrar Docker local.
ejecutar el contenedor
El primer ejemplo mostrará cómo ejecutar el contenedor equivalente a 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)
}
复制代码
Ejecutar contenedores en segundo plano
También puede ejecutar contenedores en segundo plano, equivalente a 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)
}
复制代码
Ver una lista de contenedores
Enumere los contenedores en ejecución como lo docker ps
haría :
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)
}
}
复制代码
Si es así docker ps -a
, podemos hacer esto types.ContainerListOptions
modificando la All
propiedad en:
// 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)
}
复制代码
Detener todos los contenedores en ejecución
Con el ejemplo anterior, podemos obtener una lista de contenedores, por lo que, en este caso, podemos ir y detener todos los contenedores en ejecución.
Nota: No ejecute el código siguiente en un servidor de producción.
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")
}
}
复制代码
Obtener los registros del contenedor especificado
Al especificar el ID del contenedor, podemos obtener los registros del contenedor con el ID correspondiente:
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)
}
复制代码
Ver lista de espejos
Obtenga todas las imágenes locales, equivalentes a docker image ls
o 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)
}
}
复制代码
tirar de la imagen
Tire de la imagen especificada, que es equivalente a 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)
}
复制代码
Extraer imagen privada
Además de las imágenes públicas, generalmente usamos algunas imágenes privadas, que pueden ser imágenes privadas en DockerHub o repositorios de imágenes autohospedados, como puerto . En este momento, necesitamos proporcionar las credenciales correspondientes para poder extraer la imagen.
Vale la pena señalar que cuando se usa Go SDK de la API de Docker, las credenciales se transmiten en texto claro, por lo que si se trata de un repositorio de imágenes autoconstruido, ¡asegúrese de usarlo 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。