Docker Engine SDKでコンテナ一覧を取得する

Docker Engine SDKを使ってコンテナ一覧の取得とフィルタリングを行いました。
2020.07.31

はじめに

最近Goの勉強がてらDocker Engine SDKを使って、コンテナを操作するCLIツールを作っているのでそのメモです。

今回SDKを使って行ったのは以下の処理です。

  • ローカルのコンテナ一覧を取得する
  • コンテナをdocker-composeのプロジェクトごとにグループ化する

環境

この記事のサンプルで使ったGolangとSDKのバージョンは下記の通りです。

クライアントの生成

Docker APIの接続先としてDOCKER_HOSTなどの環境変数を参照するクライアントを生成するサンプルコードは以下になります。(サンプルにあったクライアントの生成はビルドできなくなっていました)

import (
	"context"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/client"
)

func main() {
	ctx := context.Background()
	cli, err := client.NewEnvClient()

	if err != nil {
		panic(err)
	}
}

コンテナ一覧取得

コンテナ一覧取得は以下のようなコードになります。

containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
		All:     true
})

ここでContainerListの引数は以下の構造体です。各項目の役割はdocker psのオプションに準じます。

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

フィルタ

docker ps コマンドと同様にフィルタの指定ができます。特定のラベルの値を指定する場合は下記のようになります。

下記の例ではラベルcom.docker.compose.projectに値some_projectがセットされているコンテナに絞り込みます。

// ラベル"com.docker.compose.project=some_project"がついているコンテナ
// (docker-composeにより起動されたコンテナには`"com.docker.compose"`で始まるラベルが付与されている)
labelFilters := filters.NewArgs()
labelFilters.Add("label", "com.docker.compose.project=some_project")
containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
	All:     true,
	Filters: labelFilters,
})

ラベルの値に関わらず、ラベルが付与されているという条件を表すには以下のようになります。

labelFilters := filters.NewArgs()
labelFilters.Add("label", "com.docker.compose.project")

ラベルを使ったグループ化

ContainerListの結果はコンテナ間の関係に関わらずフラットになっています。結果をdocker-composeのプロジェクト単位にグループ化するにはコンテナのラベル値を使って以下のようになります。(自明ですが・・・)

この例ではプロジェクト名をキー、コンテナのリストを値にもつマップを生成しています。

import (
	"context"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/client"
)

type ServiceContainerMap map[string][]types.Container

func ListContainerListGroupByService() (ServiceContainerMap, error) {
	ctx := context.Background()
	cli, err := client.NewEnvClient()

	if err != nil {
		return nil, err
	}
	//ラベルありのコンテナを取得
	labelFilters := filters.NewArgs()
	labelFilters.Add("label", "com.docker.compose.project")
	containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
		All:     true,
		Filters: labelFilters,
	})
	if err != nil {
		return nil, err
	}

	//プロジェクトでグループ化
	containersByProject := map[string][]types.Container{}
	for _, container := range containers {
		label := container.Labels["com.docker.compose.project"]
		cons := containersByProject[label]
		if cons == nil {
			cons = []types.Container{}
		}
		cons = append(cons, container)
		containersByProject[label] = cons
	}
	return containersByProject, nil
}

まとめ

Docker Engine SDKを使ってコンテナ一覧の取得とフィルタリングを行いました。