Skip to Content

Containerアクション

Containerアクションは、後続のステップのためにコンテナを起動し、実行が終わると削除します。テスト対象のAPIが必要とするデータベースやメールサーバーを、ワークフローの中で用意できます。

外部アクションとしてmozership/probe-container で公開しています。ワークフローが初めて使うときにProbeがダウンロードし、固定したコミットのaction.ymlが示すSHA-256と一致する実行ファイルだけを実行します。実行の終了後にアクションを呼び出すProbe v1.27.0以降と、dockerコマンドが必要です。同じ引数を受け付ける別のランタイムも使えます。

基本的な構文

ワークフローでは40文字のコミットSHAでアクションを固定します。各リリース のノートの先頭に、コピーして使うアクションとコミットがあります。このページの例では、actionsで一度だけ名前を付けています。

name: Orders actions: container: github.com/mozership/probe-container@cd5c071a029cc1c6d4afe31750bf33ec6d9aa5b8 # v0.1.0 jobs: - name: orders steps: - name: Start Postgres id: pg uses: container with: image: postgres:17 env: POSTGRES_PASSWORD: "{{vars.pg_password}}" ports: [5432] wait: port: 5432 outputs: addr: res.addr - name: The schema is empty to begin with uses: db with: dsn: "postgres://postgres:{{vars.pg_password}}@{{outputs.pg.addr}}/postgres?sslmode=disable" query: SELECT count(*) AS n FROM pg_tables WHERE schemaname = 'public' test: res.rows[0].n == 0

ステップは、コンテナを起動した時点で終わります。waitがあれば、準備ができるまで待ってから終わります。コンテナはそのジョブと他のジョブの後続のステップのために動き続け、実行が終わると匿名ボリュームとともに削除されます。実行が成功しても、失敗しても、Ctrl+Cで止めても同じです。そのために書くものはありません。

パラメータ

パラメータ型必須デフォルト説明
imageStringはい-起動するイメージ
commandListいいえイメージのコマンドコンテナで実行するコマンド。[redis-server, --appendonly, "yes"]のように、1語を1要素として書きます
envMapいいえ-コンテナの環境変数。名前と値の組で書きます
portsListいいえ-マシンから届くようにするコンテナのポート。ポートを参照してください
volumesListいいえ-マウントするもの。/abs/path/init.sql:/docker-entrypoint-initdb.d/init.sql:roのように、ランタイムの--volumeが受け付ける形で書きます
networkStringいいえランタイムのデフォルトコンテナをつなぐネットワーク。既にあるものを指定します。アクションはネットワークを作りません
nameStringいいえランタイムが付ける名前コンテナの名前。同時に動く2つの実行が同じ名前のコンテナを持つことはできないので、必要がなければ指定しません
pullStringいいえmissingイメージを取得する条件。missing、always、neverのいずれか
waitMapいいえ-ステップが終わる前にコンテナが満たす条件。待機を参照してください
keepBooleanいいえfalse実行が終わってもコンテナを残します。コンテナを残すを参照してください

これら以外のキーをwithに書くと、何も起動しないうちにステップが失敗します。action.ymlがこれらをparamsとして宣言しているので、probe checkはそのようなキーを行番号とともに報告します。

アクションはenvの値を結果にもログにも出さず、変数の名前だけを出します。値はランタイムに引数として渡すので、コンテナの起動中はマシンのプロセス一覧から見え、起動後はランタイムが表示するコンテナの情報からも見えます。

ポート

portsの各要素は、コンテナのポートです。

要素公開先
5432127.0.0.1の空いているポート。結果がその番号を返します
53/udp同じく空いているポート。TCP以外のプロトコル(udpまたはsctp)で公開します
"8080:80"、"0.0.0.0:8080:80"要素に書いた場所。ランタイムの--publishが受け付ける形で書きます

ポートだけを書く形を使ってください。ランタイムが空いているポートを選ぶので、同じマシンで動く2つの実行や、1つの実行の2つのジョブがぶつかりません。ポートがネットワークに開くこともありません。公開先は結果から読みます。

待機

waitがないと、ステップはコンテナを起動した時点で終わります。その時点では、中で動くものの準備はまだできていません。waitは、準備ができるまでステップを終わらせません。

キー型説明
portNumberportsにあるTCPのポート。接続を受け付け、保ち続けることを待ちます。ランタイムは、コンテナの中で何も待ち受けていなくても公開したポートで接続を受け付け、すぐに閉じます。そのため、受け付けられただけの接続は数えません
logString正規表現 。コンテナがそれまでに標準出力と標準エラーに書いた内容の全体と照合します。全体と照合するので、(?s)ready.*readyと書けば、2回書かれる行を待てます
healthcheckBooleantrueにすると、イメージのヘルスチェックが通るまで待ちます。ヘルスチェックのないイメージではステップが失敗します
timeoutDuration待つ時間。90sのような形か、秒数で書きます。デフォルトは60sです

複数を指定すると、すべてが満たされるまで待ちます。イメージの取得にかかる時間は、タイムアウトに含まれません。

待っている間にコンテナが止まるか、時間内に準備ができないと、ステップは失敗します。エラーの末尾には、コンテナのログの最後の数行が付きます。コンテナは、実行が終わるときに他のコンテナとともに削除されます。

データベースのように、応答できるようになる前から接続を受け付けるサーバーは、ログかヘルスチェックで待つほうが確実です。

steps: - name: Start Postgres, and wait until it is up for good uses: container with: image: postgres:17 env: POSTGRES_PASSWORD: "{{vars.pg_password}}" ports: [5432] wait: # The image starts the server once to set it up, and then again. log: "(?s)ready to accept connections.*ready to accept connections" timeout: 90s

レスポンスオブジェクト

プロパティ型説明
res.idStringコンテナのID
res.nameStringコンテナの名前。同じnetworkにある別のコンテナは、この名前で接続します
res.portsObjectportsの各要素に対する、マシン側のポート。コンテナのポートをキーにして、res.ports["5432"]のように読みます。TCP以外のプロトコルではres.ports["53/udp"]です
res.hostStringportsの最初の要素に届くアドレス。要素が別のアドレスを指定していなければ127.0.0.1です
res.portIntegerportsの最初の要素に対する、マシン側のポート
res.addrStringres.hostとres.portを合わせたもの。127.0.0.1:51110の形です
reqObjectコンテナの起動に使った内容。envは変数の名前だけです
rtDurationステップにかかった時間
statusInteger0

res.host、res.port、res.addrは、ステップにportsがあるときだけ返ります。

起動できないコンテナや準備ができないコンテナは、結果ではなくエラーになります。そのため、testの内容にかかわらずステップは失敗します。

コンテナを残す

テストが失敗したときなど、実行のあとでコンテナの中を調べたい場合は、コンテナを残せます。

  • PROBE_CONTAINER_KEEP=1 probe workflow.ymlは、ワークフローを書き換えずに、その実行のコンテナをすべて残します。
  • ステップにkeep: trueを書くと、そのステップのコンテナだけを残します。

実行が終わると、アクションは残したコンテナと、それを削除するコマンドを表示します。

[WARN] actions.probe-container: kept containers of the run: run_id=88041310b4926f7b count=1 remove="docker rm --force --volumes $(docker ps --all --quiet --filter label=probe.run_id=88041310b4926f7b)" [WARN] actions.probe-container: kept container: name=sleepy_dubinsky image=postgres:17 ports=127.0.0.1:51110->5432/tcp

アクションが起動するコンテナには、実行のIDを値とするラベルprobe.run_idが付きます。残すコンテナにはprobe.keep=trueも付きます。docker ps --all --filter label=probe.run_idで、すべての実行が残したコンテナを一覧できます。

残るもの

Probeは実行が終わるとアクションを呼び出し、アクションはその実行のラベルが付いたコンテナをすべて削除します。コンテナが残るのは、次の場合だけです。

  • ステップまたは環境変数が、コンテナを残すよう指定している。
  • kill -9などでProbeが強制終了され、後始末まで進めなかった。
  • ランタイムが25秒以内にコンテナを削除できなかった。この場合、Probeが警告を表示します。

名前付きのボリュームとネットワークは、アクションが作ったものではないので残ります。

ランタイム

アクションはdockerを実行します。PROBE_CONTAINER_RUNTIMEには、podmanやnerdctlのように同じ引数を受け付ける別のコマンドか、そのパスを指定できます。

PROBE_CONTAINER_RUNTIME=podman probe workflow.yml

ランタイムはステップではなく環境変数で指定します。ランタイムはワークフローではなくマシンに属するものであり、実行の後始末は、ステップが使ったのと同じランタイムで行う必要があるためです。

アクションはイメージをビルドせず、既にあるコンテナの中で何かを実行することもありません。どちらも、shellのステップからランタイムを直接呼べば行えます。

ガードの下での動作

アクションはどのガードも守りません。コンテナの中で動くものや、それが接続するホストは、アクションが制限できるものではないためです。--read-onlyまたは--allow-hostの下では、--allow-actionでアクションを指定しない限り、ステップは拒否されます。

ガードを参照してください。

関連項目

  • 外部アクション - Probeが外部アクションを解決し、照合する仕組み
  • 実行の後始末 - Probeが実行の終了後にアクションを呼び出す仕組み
  • Database - MySQL、PostgreSQL、SQLiteへのクエリ
  • Redis - RedisまたはValkeyのサーバーでのコマンド
更新日時