0時に寝て7時に起きた。前日はバテてだらだらしていたので寝過ぎた。

案ずるよりもツールできた

先週末に docker/compose 関連のライブラリ調査 を終えて実際のツール作りをしていた。本当は日曜日に作ってしまおうと思いつつ休んでしまった。なぜか今日はメンバーが全員お休みでチームで私しか働いていなかった。年度末で有休消化しているのかな?問い合わせ対応やメンバーのサポートが不要だったので1日中、自分の開発に集中できた。そして開発に集中できた結果、一通りツールの機能の開発を終えられた。火曜日までには仕上げたいと思っていたのでぎりぎり間に合った。

最終的に testcontainers-go の compose モジュールを使うのは断念して compose cli のみ go 標準の os/exec パッケージを使ってプロセスを fork するようにした。また docker image をコンテナレジストリから取得するときに認証が必要な場合、最初の docker login すると credentials store にパスワード (またはトークン) 情報が記録される。設定情報は $HOME/.docker/config.json からも確認できる。この仕組みを使ってコンテナレジストリへのログインを自動化できる。私の環境では macbook に docker desktop をインストールしているが、普通に使っていると次のように credentials が保存されてその内容を確認できる。

$ docker-credential-desktop list | jq .
{
  "https://index.docker.io/v1/": "t2y1979",
  "https://index.docker.io/v1/access-token": "t2y1979",
  "https://index.docker.io/v1/refresh-token": "t2y1979"
}
$ echo "https://index.docker.io/v1/access-token" | docker-credential-desktop get
{"ServerURL":"https://index.docker.io/v1/access-token","Username":"t2y1979","Secret":"***"}

これと同じことを docker のライブラリで行うには次のようにする。取得したい docker image の uri を参照すればコンテナレジストリがわかる。そこからこの cli でやっているようなことを順番にやっていけばよい。これらのユーティリティは3つのリポジトリで管理されていて、この雰囲気をみただけでもこのモジュール分割が本当に適切なんやろか?とか思ったりもする。

func getRegistryAuthFromImage(
	ctx context.Context, imageURI string,
) (string, error) {
	ref, err := reference.ParseNormalizedNamed(imageURI)
	if err != nil {
		return "", fmt.Errorf("failed to parse image uri: %w", err)
	}
	repo, err := registry.ParseRepositoryInfo(ref)
	if err != nil {
		return "", fmt.Errorf("failed to parse repository: %w", err)
	}
	dcli, err := command.NewDockerCli()
	if err != nil {
		return "", fmt.Errorf("failed to create docker cli: %w", err)
	}
	auth := command.ResolveAuthConfig(ctx, dcli, repo.Index)
	encoded, err := command.EncodeAuthToBase64(auth)
	if err != nil {
		return "", fmt.Errorf("failed to encode auth: %w", err)
	}
	return encoded, nil
}