備忘録としてまとめる。
TL;DR
container.image
に指定するimageに現状alpineベースは使えないのでslimベースを使う- services側に指定するimageはalpineベースのimageも利用可能
- container.imageに指定された場合はHOMEが
/github/home
に置換されるのでそれを考慮してロジックを書く gcloudコマンドを使いたい場合はgoogle/cloud-sdk:slim
imageを使うとVMにaptベースで入れるより1分半ほど早くなる- 08/25の現在ではVMに最初からgcloudコマンドが入っている、08/23の暗黙的更新で入るようになった模様
背景
ワークフローの中で gcloud container clusters get-credentials
をしているので、apt経由でgcloud sdkのセットアップをしていた。
install部分で1m30s - 2m30sほどかかってしまい、この時間を短縮したかった。
そのため、 google/cloud-sdk
のalpineベースのimageを利用しようとしたらハマったのでcontainerの挙動を調査した。
GitHub Actionsのcontainerのプロセス
自動で行われるプロセスのInitalize containers
と Stop containers
について。
今回はcontainer.imageに google/cloud-sdk:slim
を指定している前提。
バージョン確認
$ /usr/bin/docker version --format '{{.Server.APIVersion}}' '1.40' Docker daemon API version: '1.40' $ /usr/bin/docker version --format '{{.Client.APIVersion}}' '1.40' Docker client API version: '1.40'
とりあえず出してるだけ?
コンテナ環境の準備
$ /usr/bin/docker ps --all --quiet --no-trunc --filter "label=29fe0f" $ /usr/bin/docker network prune --force --filter "label=29fe0f" $ /usr/bin/docker network create --label 29fe0f github_network_f081154afaeb49f8a7d58af20922dbb4 20455dfa0b2cb1d5c8f711753389843afe129706b6e913f987aecfeef0ef68cd
動作しているコンテナに今から使おうとしているラベルが使われていないかを表示し、
使おうとしているラベルのネットワークをforce optionをつけて削除実行。
その後にこれからの実行で使うネットワークを作成する。
作成したネットワークは実行されているjobの中で使い回され、middlewareの連携に使われる(e.g. MySQL, Redis)。
イメージの準備
$ /usr/bin/docker pull google/cloud-sdk:slim slim: Pulling from google/cloud-sdk ... Digest: sha256:0ceb5c90f22070d2cb9a7ca9839ff83daf2ae3003cacd25bfababb659874e200 Status: Downloaded newer image for google/cloud-sdk:slim docker.io/google/cloud-sdk:slim $ /usr/bin/docker inspect --format="{{index .Config.Labels \"github.actions.runner.node.path\"}}" google/cloud-sdk:slim $ /usr/bin/docker create --name 56ec245c1e0d43f9905adf5cc005fa58_googlecloudsdkslim_77abfc --label 29fe0f --workdir /__w/check-event-for-gh-actions/check-event-for-gh-actions --network github_network_f081154afaeb49f8a7d58af20922dbb4 -e "HOME=/github/home" -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work":"/__w" -v "/home/runner/runners/2.157.0/externals":"/__e":ro -v "/home/runner/work/_temp":"/__w/_temp" -v "/home/runner/work/_actions":"/__w/_actions" -v "/opt/hostedtoolcache":"/__t" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" --entrypoint "/__e/node12/bin/node" google/cloud-sdk:slim -e "setInterval(function(){}, 24 * 60 * 60 * 1000);" c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 $ /usr/bin/docker start c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 $ /usr/bin/docker ps --all --filter id=c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 --filter status=running --no-trunc --format "{{.ID}} {{.Status}}" c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 Up Less than a second
このあたりからGitHub Actions特有の操作が入っていて色々ハマりポイントがあった。
まずimageをpullしてくる。
その後
docker inspect --format="{{index .Config.Labels \"github.actions.runner.node.path\"}}" google/cloud-sdk:slim
で ConfigLabels
の値を確認している。
cloud-sdk
imageでは空が返ってくるだけだが、inspectしたimageの形式が以下のようであれば何らかの値が返ってくる。
[ { "Id": "sha256:digest", ..., "Config": { "Labels": { "github.actions.runner.node.path": "something" } }, ..., } ]
使っているイメージではLabelsに上記のような値が入っているものはないので、入っていた場合はどういう処理になるのかは未調査。
次に
docker create \ --name 56ec245c1e0d43f9905adf5cc005fa58_googlecloudsdkslim_77abfc \ --label 29fe0f \ --workdir /__w/check-event-for-gh-actions/check-event-for-gh-actions \ --network github_network_f081154afaeb49f8a7d58af20922dbb4 \ -e "HOME=/github/home" \ -v "/var/run/docker.sock":"/var/run/docker.sock" \ -v "/home/runner/work":"/__w" \ -v "/home/runner/runners/2.157.0/externals":"/__e":ro \ -v "/home/runner/work/_temp":"/__w/_temp" \ -v "/home/runner/work/_actions":"/__w/_actions" \ -v "/opt/hostedtoolcache":"/__t" \ -v "/home/runner/work/_temp/_github_home":"/github/home" \ -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" \ --entrypoint "/__e/node12/bin/node" \ google/cloud-sdk:slim \ -e "setInterval(function(){}, 24 * 60 * 60 * 1000);"
でcontainerを作成している。上記は見やすいようにフォーマットしている。
色々と設定された状態でコンテナが作られるが、やっていることはいい感じに設定しながらコンテナを起動し続けるようにしてくれているだけ。
自分が大きくハマったのは以下の2点の挙動。
- HOMEが
/github/home
に上書きされている - runs-onで指定されたホストのnodeがentrypointで使用されている
まず、HOMEに関しては cloud-sdk
imageがimage内で持っているHOMEが /root
だったのでそれを基準に手元で検証していた。
実際にactionsのほうで実行すると、HOMEがずれており意図せぬ挙動になった上、sshもできないのでHOMEが原因と気づくまでに時間がかかった。
次にnode周りの実行についてだが、nodeで実行しているのは--eval
の引数として setInterval(function(){}, 24 * 60 * 60 * 1000);
を実行している。
これをしている意図としてはコンテナが即座に終了しないように保持し続けるのが目的だと推測できる。
その対応をnodeを使って実行するためにruns-onで指定されたホストにインストールされたnodeをvolumeでマウントして実行しようとしている。
こういうことをしようとすると、例えば runs-on: ubuntu-latest
のときにalpineイメージを実行しようとするとubuntu側からマウントされたnodeがalpine側で使えないので落ちる。
最初GitHub Actionsでcontainer周りを触ったときにalpineベースのimageを使おうとしていたのでこの問題を引いてcontainerは使えないものと思い込んでいた。
ubuntuでマウントされたnodeを使えるimageであればよいので、slimベースのimageを使うことで解決した。
image sizeが小さいほどpull時間が短くなりCIの実行が早くなるのでalpineベースを使いたいが、slimベースでもaptでgcloud sdkを入れるよりはだいぶ早くなった。
作成したcontainerを維持したいだけならshellで書けばいいだけだと思うので、updateでぜひnode依存を取り払ってほしい。
もしalpineベースでも実行できた人がいたら教えてくれるとありがたい…。
$ /usr/bin/docker start c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 $ /usr/bin/docker ps --all --filter id=c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 --filter status=running --no-trunc --format "{{.ID}} {{.Status}}" c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 Up Less than a second
最後に作ったコンテナの起動とちゃんと動いているかの確認をしている。
コンテナの破棄(Stop containers)
$ /usr/bin/docker rm --force c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 c4cb2d68eb23ea352a5ab62c9fef4788ef19f49896918b9bebde1c285a8d3298 Remove container network: github_network_f081154afaeb49f8a7d58af20922dbb4 $ /usr/bin/docker network rm github_network_f081154afaeb49f8a7d58af20922dbb4 github_network_f081154afaeb49f8a7d58af20922dbb4 Cleaning up orphan processes
container
を使用している場合は自動的にコンテナとnetworkの破棄が行われる(よくやるやつ)。
servicesについて
VMベースとcontainerベースがある。
jobs: vm-job: runs-on: ubuntu-latest services: redis: image: redis ports: - 6379/tcp - uses: actions/checkout@v1 - run: something env: REDIS_HOST: localhost REDIS_PORT: ${{ job.services.redis.ports[6379] }} container-job: runs-on: ubuntu-latest container: image: something services: redis: image: redis ports: - 6379:6379 steps: - uses: actions/checkout@v1 - run: something env: REDIS_HOST: redis REDIS_PORT: ${{ job.services.redis.ports[6379] }}
より詳細なexampleは公式を参照すると良さそう。
GitHub - actions/example-services: Example workflows using service containers
挙動については Initalize containers
と Stop containers
にまとめられている。
vmの場合はコンテナを立ち上げてportのmappingを行い、localhost上にredisがいるように見えている。
e.g. localhost:6379
$ usr/bin/docker create --name 9c34e4a1c0b844aaa939b31977869d67_redis_756ef3 --label 29fe0f --workdir /__w/example-services/example-services --network github_network_075e98bbff874715ae6b3d2cf196e483 --network-alias redis -p 6379/tcp -e "HOME=/github/home" -v "/home/runner/work":"/__w" -v "/home/runner/runners/2.157.0/externals":"/__e":ro -v "/home/runner/work/_temp":"/__w/_temp" -v "/home/runner/work/_actions":"/__w/_actions" -v "/opt/hostedtoolcache":"/__t" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" redis 76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2 $ /usr/bin/docker start 76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2 76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2 $ /usr/bin/docker ps --all --filter id=76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2 --filter status=running --no-trunc --format "{{.ID}} {{.Status}}" 76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2 Up Less than a second $ /usr/bin/docker port 76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2 6379/tcp -> 0.0.0.0:32768 /usr/bin/docker inspect --format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}" 76d070f99216dc7457a9839bd9702b67f80c5ea41a6507ec9655ef96520ca3d2
containerの場合は同じネットワーク上にredisを立ち上げておき、serviceで指定した名前をHOST名として接続できる。
e.g. redis:6379
$ usr/bin/docker create --name 286235f7d8134c71a9ca342a1f56102b_redis_29007b --label 29fe0f --workdir /__w/example-services/example-services --network github_network_8d140662e9cc4c1ca6f4e69f6afbf640 --network-alias redis -p 6379:6379 -e "HOME=/github/home" -v "/home/runner/work":"/__w" -v "/home/runner/runners/2.157.0/externals":"/__e":ro -v "/home/runner/work/_temp":"/__w/_temp" -v "/home/runner/work/_actions":"/__w/_actions" -v "/opt/hostedtoolcache":"/__t" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" redis 80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516 $ /usr/bin/docker start 80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516 80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516 $ /usr/bin/docker ps --all --filter id=80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516 --filter status=running --no-trunc --format "{{.ID}} {{.Status}}" 80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516 Up Less than a second $ /usr/bin/docker port 80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516 6379/tcp -> 0.0.0.0:6379 $ /usr/bin/docker inspect --format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}" 80c0e46c00714d01f8875de12dbff24c637dfaa4dd18adec9fcd3e46269da516
VM、containerどちらの場合も container.image
で指定される場合と違ってentrypointの上書きやコンテナを維持するための--evalの指定がない。
そのため、serviceで指定するimageについてはalpine系のimageを利用しても問題なさそう。
dindについて
dind: runs-on: ubuntu-latest container: image: docker:stable-dind steps: - run: docker -v
で試してみたが使えないので現状できなさそう。
Error response from daemon: Container de125048c3bfb37fb0ac805da204b6b2365aa87a70228d56cc01b9bfac9bb864 is not running ##[error]Process completed with exit code 1.
おそらく docker:stable-dind
image内で--eval
が成功していない気がする。
このあたり何が起きているか調べる術がないので難しい…。