Docker のベースイメージを GitHub で自動的に更新する


かつて Docker Hub にベースイメージが更新されたタイミングで自動的にビルドする機能があったと記憶しているのですが、Autobuilds が free plan で使えなくなったため、GitHub Actions と Dependabot を利用して更新する方法を検討しました。

テスト環境として nginx:stable をベースイメージとする Dockerfileビルドして Docker Hub にプッシュするワークフローを用意します。そのまま、このワークフローの定期実行をスケジュールすることで、最新のベースイメージが反映されたイメージを維持できますが、 更新がない時の不要なビルドによるコストと、下記の自動的な無効化を回避するために、Dependabot を採用します。

パブリックリポジトリでは、60日間にリポジトリにアクティビティがなかった場合、スケジュールされたワークフローは自動的に無効化されます。

使用制限、支払い、管理 - GitHub Docs

最初に、Dockerfile を監視する dependabot.yml を用意します。nginx:stable は、現在の stable バージョンである nginx:1.20.2 と同じイメージを示しており、バージョンアップに合わせて、新しいイメージに変更されていきます。nginx 自体はバージョン番号が同じであれば内容も同一ですが、Docker イメージの場合、ベースイメージの debian や、パッケージ等の nginx 以外の更新によっても、イメージが更新される点に注意してください。Dependabot には、その時点で指しているイメージを教える必要があるため、次のようにダイジェスト値を追加します。

github.com

ダイジェスト値の取得は CLI です。

$ docker inspect --format='{{index .RepoDigests 0}}' nginx:stable
nginx@sha256:cba27ee29d62dfd6034994162e71c399b08a84b50ab25783eabce64b1907f774

また、nginx:1.20 のようにバージョンを指定する場合も同様にダイジェスト値を追加できます。

以上で、Dependabot がベースイメージのバージョンアップを検知した際に、自動的にプルリクエストを作成するようになります。

github.com

しかしながら、この状態だとプルリクエストができる度に人間がマージをする必要があります。

仮に、ベースイメージとして nginx:1.20 を指定した場合、1.20.x の最新のバージョンが使用されますが、nginx はセマンティックバージョニングに従っていると思われるので、後方互換性を伴うバグ修正によるパッチバージョンの変更は、自動的にマージすることにします。

自動マージのワークフロー例を参考にして、以下のファイルを作成します。steps.dependabot-metadata.outputs.update-type は定義されないようなので、条件から外しています。

github.com

結果、Dependabot によるプルリクエストと同時に、ワークフローが実行され、自動マージされました。

github.com

検証が不十分なのですが、自動マージの場合、ビルドをするワークフローが push や pull_request イベントではトリガーされなかったため、workflow_run イベントを追加しています。

ベースイメージの自動的な更新は完了しましたが、Dockerfile で apt や yum 等の Dependabot で監視できないパッケージをインストールしている場合は、それらのバージョンアップに気づくことができません。

github.com

そのようなイメージを確実に更新し続けるためには、前述のとおりビルドのワークフローを定期実行し、何らかの方法でスケジュールの無効化を回避する必要があると考えます。