
依存ライブラリやGitHub Actions、Terraform Providerのバージョン管理をしていると、よく出てくるのが次の考え方です。
新しいバージョンが出たら、常に最新版へ上げればいいのでは?
一見すると合理的です。
実際、古いバージョンを長期間使い続けるより、継続的にアップデートした方が、脆弱性や非互換の問題を後回しにしにくくなります。
ただし、実際の開発運用では、
「バージョンを固定しない」ことと「常に新しい状態を保つ」ことは別です。
むしろ、
バージョンは固定し、Dependabotで自動的に更新PRを作る
という運用の方が、安全性と更新頻度を両立しやすくなります。
今回は、実際の開発チームで出た「pinするべきか、しないべきか」という議論をベースに、Dependabotをどう使うべきか整理します。
あるプロジェクトで、GitHub ActionsやTerraform Providerのバージョンを更新する話が出ました。
その中で、
理想的には何もpinしない方がいい。新しいバージョンが出たら常にアップグレードすればいいのでは?
という意見が出ました。
この考え方自体は間違っていません。
目標としては、
依存関係を古いまま放置しない
というのが正しいです。
ただし、その目標を実現する方法として「pinしない」を選ぶと、別の問題が出てきます。
そこで出てきたのが、
「pinしない」のではなく、「pin + automated bumps」にしよう
という考え方です。
つまり、
バージョンは固定する。しかし、更新作業は自動化する。
これがDependabotを使う理由です。
たとえばGitHub Actionsでは、次のような指定をすることがあります。
uses: actions/checkout@v4
これは分かりやすく、一般的な書き方です。
ただし、v4 のようなタグは、厳密には「特定のコードそのもの」を表しているわけではありません。
タグが別のコミットを指すように変更されれば、同じ @v4 という記述でも、実際に実行されるコードが変わる可能性があります。
CI/CDで実行されるActionは、ビルド環境やデプロイ権限にアクセスすることがあります。
そのため、これはサプライチェーンセキュリティの観点でも重要です。
より厳密に管理するなら、特定のコミットSHAに固定します。
uses: actions/checkout@<commit-sha>
こうすると、同じ設定から実行されるコードが勝手に変わることはありません。
ただし問題があります。
固定しただけでは、そのバージョンは永遠に古くなっていきます。
そこでDependabotを使います。
新しいバージョンが出たら、
という流れにします。
つまり、
固定することで再現性を確保し、Dependabotで鮮度を維持する
という考え方です。
ここが重要です。
バージョンを固定すると、
「古いバージョンを使い続けることになるのでは?」
と思うかもしれません。
しかし、Dependabotを使えばそうなりません。
例えば現在のバージョンが1.2.3だったとします。
1.2.3
新しく1.2.4が出ると、DependabotがPRを作ります。
1.2.3 → 1.2.4
そのPRをレビューしてマージします。
さらに1.3.0が出れば、
1.2.4 → 1.3.0
というPRが作られます。
つまり、実際には常に最新版を追うことができます。
違うのは、
勝手に最新版へ切り替わるのではなく、Pull Requestというレビュー可能な変更として更新される
という点です。
これが大きな違いです。
Terraform Providerでも、似た議論があります。
例えばAWS Providerを次のように指定するとします。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
~> 6.0 は、AWS Provider 6系を使うという制約です。
ここで重要なのは、Terraformでは実際に使用するProviderバージョンは .terraform.lock.hcl に記録されるという点です。
つまり、
versions.tf などに書くversion constraintは、
どのバージョンまで許可するか
を決めます。
一方でlock fileは、
実際にどのバージョンを使うか
を固定します。
この2つは役割が違います。
たとえばAWS Provider 6系を使っている状態で、将来7系がリリースされたとします。
制約がなければ、次回の更新時に7系が入ってくる可能性があります。
しかし、メジャーバージョンアップには破壊的変更が含まれる可能性があります。
その結果、
などが起きる可能性があります。
インフラでは特に、
「次にapplyしたら突然大量変更が出た」
という状態を避ける必要があります。
そのため、
version = "~> 6.0"
のようにメジャーバージョンを制約しておきます。
その上でDependabotにアップデートPRを作らせます。
Terraformで重要なのは、アップデートそのものより、
アップデートによってインフラにどんな変更が出るか
です。
そのためProvider更新は、
という流れにすると安全です。
特にAWS Providerのメジャーバージョンアップでは、このフローが重要です。
単純に、
6.x → 7.x
と最新版へ更新するのではなく、
変更内容をコードレビューとplanレビューの両方で確認する
ということです。
Dependabotは、GitHubが提供している依存関係管理の自動化機能です。
主に次の機能があります。
リポジトリがどのパッケージやライブラリに依存しているのかをGitHubが把握します。
Dependabotの脆弱性検知の基礎になる機能です。
利用中の依存関係に既知の脆弱性がある場合、GitHub上で通知します。
脆弱性を修正できるバージョンがある場合、自動的にPull Requestを作成します。
脆弱性の有無に関係なく、新しいバージョンが出たときにアップデートPRを作ります。
実務で「pin + automated bumps」を実現する中心的な機能は、このversion updatesです。
通常のバージョンアップデートを自動化する場合、リポジトリに次のファイルを置きます。
.github/dependabot.yml
例えばGitHub Actionsを毎週確認する場合はこうします。
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
Terraformも監視できます。
version: 2
updates:
- package-ecosystem: "terraform"
directory: "/"
schedule:
interval: "weekly"
Gradleなら次のように設定できます。
version: 2
updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "weekly"
複数のecosystemを1ファイルにまとめることもできます。
もちろん、人間が定期的に最新版を確認して更新することもできます。
ただ、これは長期的にはかなり漏れやすい運用です。
プロジェクト開始直後は、
「毎月確認しよう」
と思っていても、
などの理由で、徐々に更新されなくなります。
Dependabotを使えば、
更新を人間の記憶に依存しない運用
にできます。
これはかなり大きなメリットです。
今回の議論では、もう1つ面白いポイントがありました。
当初は、
バージョンをpinするときは、「なぜこのバージョンなのか」をコメントとして残そう
という案がありました。
これは悪い考えではありません。
ただ、Dependabotを使う場合は、必ずしもすべてのpinにコメントを書く必要はありません。
なぜなら、
更新履歴そのものがPull Requestとして残るからです。
例えば、
Bump hashicorp/aws from 6.12.0 to 6.13.0
というPRがあれば、
がGitHub上に残ります。
コードコメントに背景を書き続けるよりも、PR履歴の方が正確な場合もあります。
ここまでを整理すると、「pinしない」運用にはいくつか問題があります。
1つは、意図しないタイミングで依存関係が変わることです。
昨日まで動いていたCIが、コードを変更していないのに今日突然壊れる、といった現象が起きる可能性があります。
もう1つは、変更点が見えにくいことです。
Dependabot経由なら、
v1 → v2
という変更がPRとして明示されます。
しかし、参照先が自動的に変化する場合、その変更がコードレビューに現れません。
ソフトウェア開発では、
いつ何が変わったかを追跡できること
も重要です。
注意点もあります。
Dependabotを導入すれば、自動的にすべて安全になるわけではありません。
Dependabotはあくまで、
アップデート候補を自動で提示する仕組み
です。
PRが作られたからといって、そのまま自動マージすればよいとは限りません。
特に、
などは、変更内容を確認した方がよいです。
重要なのは、
自動更新ではなく、自動PR化
という考え方です。
最終的に、依存関係管理の基本形は次のようになります。
Version pin
↓
Dependabot
↓
Pull Request
↓
CI / Terraform plan
↓
Human review
↓
Merge
これなら、
というバランスを取れます。
今回の議論で一番重要なのはここだと思います。
最新版を積極的に使うこと自体は正しい。
ただし、
最新版へ自動的に切り替わることが正しいとは限りません。
理想的なのは、
常に新しいバージョンを追う。ただし、変更は必ずPull Requestとして可視化する。
という状態です。
そのための仕組みとして、Dependabotはかなり使いやすいです。
Dependabotを使う理由は、単に「アップデートが面倒だから」ではありません。
本質的には、
依存関係の更新を、レビュー可能で追跡可能な開発プロセスにするため
です。
「pinすると古くなる」という問題は、Dependabotで解決できます。
「最新版を使うと突然壊れる」という問題は、pinとPRレビューで抑えられます。
そのため実務では、
pin + Dependabot + CI
という組み合わせが扱いやすいです。
バージョンを固定することと、常に新しい状態を保つことは矛盾しません。
むしろDependabotを間に入れることで、
固定して安全性を確保しながら、継続的に最新版へ追従する
という運用が可能になります。
coiai
この記事もおすすめ
株式会社coiaiは、「想像できることを美しく実現」を掲げ、XR・Web・アプリ・システム開発およびDX支援を行う会社です。 創業2022年、東京都練馬区に本社を置き、要件のヒアリングからPoC(概念実証)、本番運用まで一貫して伴走します。 まずはお気軽にご相談ください。
主なご相談内容
詳しい会社情報は会社概要ページでご覧いただけます。