Juega con la API de Docker con Golang | Go Theme Month

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 psharí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.ContainerListOptionsmodificando la Allpropiedad 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 lso 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

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

Supongo que te gusta

Origin juejin.im/post/6944730766052065288
Recomendado
Clasificación