Open11

testcontainers

bells17bells17

対応コンテナランタイム

  • docker
  • podman

ryuk的にはdockerのみ対応に見えるので実質dockerのみ対応?

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/provider.go#L110-L125

testcontainers側はdockerもpodmanも同じプロバイダ実装を利用できてるのでryukでも行ける?

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/reaper.go#L226

bind mountで /var/run/docker.sock にmountしてるのでpodmanでもDocker APIとinterfaceが同じなら行けそう

https://github.com/testcontainers/moby-ryuk/blob/0.7.0/main.go#L118-L121

ryukでもDocker SDK側の環境変数設定とかを使ってホストを切り替えできそうだけど、testcontainers側で /var/run/docker.sock に決め打ちでmountしてるみたい

https://github.com/testcontainers/moby-ryuk/blob/0.7.0/main.go#L118-L121

bells17bells17

ryuk

https://github.com/testcontainers/moby-ryuk/tree/0.7.0

まとめ

  • 起動後に待ち受けるTCPポートに来たリクエストを保存
  • 一定時間待機
  • 待機後に保存した各条件にマッチする各種コンテナリソースをpruneするプログラム
  • コンテナでも利用可能(DockerのGo SDK経由でpruneなどを実行)
  • testcontainersから起動したテスト用コンテナのリソースを削除するために利用される

プログラム内容

  • 起動後指定のTCPポートで待ち受け
  • 待ち受けたポートのリクエストを保存
  • 一定時間経過後(デフォルトでは60秒)もしくはリクエストから一定時間経過後(デフォルトでは10秒)に処理を開始
  • メイン処理を実行(内容は下記):
    • リクエスト毎に container.ListOptions に変換
    • container.ListOptions 条件に一致する下記のリソースを削除(prune)する
      • コンテナ
      • イメージ
      • ネットワーク
      • ボリューム
    • リソース別の削除件数を出力して終了

コンテナ

https://hub.docker.com/r/testcontainers/ryuk

ryukはコンテナでも利用可能
(というよりはコンテナがメインに見える)

ドキュメント

https://golang.testcontainers.org/features/garbage_collector/

https://golang.testcontainers.org/features/configuration/#customizing-ryuk-the-resource-reaper

bells17bells17

testcontainers-go

モジュールを使ってコンテナを作る

下記のドキュメントのサイドバーに利用可能なモジュール一覧と使い方がある

https://golang.testcontainers.org/modules/

もしくは実装を直接見る

https://github.com/testcontainers/testcontainers-go/tree/v0.30.0/modules

モジュール外のコンテナを作る

基本下記のドキュメントにあるようにGenericContainerを使用する

https://golang.testcontainers.org/features/creating_container/#genericcontainer

複数のコンテナを動かしたければParallelContainersを使う
(もしくは後述するDocker Composeを使う)

https://golang.testcontainers.org/features/creating_container/#parallel-running

内部的にはGenericContainerRequestのリストなだけ

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/parallel.go

ラベル

session idを含めたコンテナなどに設定されるラベルはこちら

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/internal/core/labels.go#L7-L23

例えばコンテナに設定するラベルはこちら

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L1053-L1058

セッションIDはこのあたりでハッシュ値が生成される

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/internal/core/bootstrap.go#L85-L92

ライフサイクルフック

コンテナの起動などのタイミングで処理を挟むことができる

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L1079-L1088

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L1053-L1058

一覧はこちらにある

https://golang.testcontainers.org/features/creating_container/#lifecycle-hooks

ちなみに

PostReadies - hooks that are executed after the container is ready

って書いてるけど実装上PostStartsの後にPostReadies実行してるだけなので、特にreadyになったとかを確認してるのかはよくわからない

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L210-L225

↓このhookがデフォルトで設定されることでreadyになるのを待機できるらしい

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/lifecycle.go#L200-L225

イメージのpull

イメージのpullはこちらで行っている

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L1246-L1285

pullの際には下記のライブラリを使ってExponential backoffが行われるので、1度pullに失敗してもリトライしてくれる

https://github.com/cenkalti/backoff

Stop

Stop処理はこんな感じ

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L230-L265

Terminate

Terminate処理はこんな感じ
コンテナと(testcontainersでビルドしたイメージの場合)イメージの削除は行っている感じ

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L267-L297

Wait

下記の種類のwaitを使ってコンテナの起動などを待機できるらしい

https://golang.testcontainers.org/features/wait/introduction/

方法としてはライフサイクルフックのところにも書いたフックによって実現してる

既存のwait種別だと機能が足りないのであれば下記のinterfaceを満たした実装を作れば独自のwait strategyを作れそう

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/wait/wait.go#L16-L19

例えば health の wait strategy の場合は下記のように実装されている

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/wait/health.go#L63-L92

ファイルコピー

下記のページにあるファイルをコンテナにコピーするやつ

https://golang.testcontainers.org/features/files_and_mounts/

下記にライフサイクルフックで実現されている

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/lifecycle.go#L127-L161

ネットワーク

ネットワークについてはこのページで書かれてる以上に特筆すべき点が特に無い

https://golang.testcontainers.org/features/creating_networks/

強いて言えば下記のようにネットワークを指定することで作ったネットワークをコンテナ側に反映できるくらい?

req := testcontainers.ContainerRequest{
		Networks: []string{"foo"},
	}

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L1100-L1116

docker build

https://golang.testcontainers.org/features/build_from_dockerfile/

Dockerfileからイメージのビルドは別に特別なことは何もなくただビルドしてるだけ

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/docker.go#L876-L921

Docker Compose

Docker Composeが使えるモジュール

https://golang.testcontainers.org/features/docker_compose/

普通にDocker ComposeのSDKを使ってるだけ
強いて言えばryukとかラベルの追加とかを行ってるのあたりは特徴と言えるかも

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/modules/compose/compose.go#L124-L132

LogConsumer

https://golang.testcontainers.org/features/follow_logs/

ドキュメントにある通りログを収集したりできる機能
(interfaceがあるだけなので何かやりたかったらLogConsumerを自分で実装する必要あり)

実装例をみたければテストにある

https://github.com/testcontainers/testcontainers-go/blob/v0.30.0/logconsumer_test.go#L26-L55

起動後のコマンド実行

https://golang.testcontainers.org/features/override_container_command/