Играем с Docker API с Golang | Месяц Go Theme

Go
Играем с Docker API с Golang | Месяц Go Theme

Docker предоставляет API для взаимодействия с демоном Docker (называемый Docker Engine API), и мы можем создавать и расширять приложения и решения Docker, используя официальный Go SDK.

Установить SDK

SDK можно установить с помощью следующей команды:

go get github.com/docker/docker/client

Управление локальным докером

В этом разделе будет рассказано, как использовать API Golang + Docker для управления локальным Docker.

запустить контейнер

Первый пример покажет, как запустить контейнер, эквивалентный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)
}

Запуск контейнеров в фоновом режиме

Вы также можете запускать контейнеры в фоновом режиме, что эквивалентно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)
}

Посмотреть список контейнеров

Список запущенных контейнеров, таких как использованиеdocker psТакой же:

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

еслиdocker ps -a, мы можем изменитьtypes.ContainerListOptionsсерединаAllДля этой цели служат атрибуты:

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

Остановить все запущенные контейнеры

В приведенном выше примере мы можем получить список контейнеров, поэтому в этом случае мы можем пойти и остановить все запущенные контейнеры.

Примечание. Не запускайте приведенный ниже код на рабочем сервере.

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

Получить журналы указанного контейнера

Указав ID контейнера, мы можем получить логи контейнера с соответствующим 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)
}

Посмотреть список зеркал

Получить все локальные зеркала, эквивалентныеdocker image lsили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)
    }
}

вытащить изображение

Вытяните указанное изображение, что эквивалентно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)
}

Вытащить частное изображение

В дополнение к общедоступным образам мы обычно используем некоторые частные образы, которые могут быть частными образами на DockerHub или самостоятельными репозиториями образов, такими какharbor. В настоящее время нам нужно предоставить соответствующие учетные данные, чтобы иметь возможность получить изображение.

Стоит отметить, что при использовании Go SDK API Docker учетные данные передаются открытым текстом, поэтому, если это самодельный репозиторий образов, обязательно используйте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 с помощью API Golang + 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Когда вам нужно указать адрес удаленного Docker, вы можете управлять удаленным Docker как локальным Docker:

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

Суммировать

Уже есть много продуктов, которые могут управлять Docker, и они делают это таким образом, например:portainer.

Оригинальная ссылка:Доступно на 8scat.com/posts/play-…