概要
Webアプリケーション開発のソースコードは、その特性上、多くの外部ライブラリに依存します。
使用者が多いパッケージほど更新頻度が高いため、追従するためには外部パッケージの定期的なアップデートが必要になります。
外部パッケージを定期的に更新していないと、
-
アップデート時の差分が大きくなり、リスクが高くなる
-
使用中のバージョンのサポートが打ち切られる
-
古いバージョンにロックインしてしまう
などの問題が発生し、事業インパクトを与える問題に発展しかねません。
ただ、人力での外部パッケージの定期更新作業は面倒です。また、施策を回すための開発より優先度が低くなるため、必要に駆られるまでは後回しにされやすい。
本記事は、外部パッケージのメジャーアップデート検知&更新の自動化を扱った内容となります。
筆者は、業務ではバージョン管理ツールとしてGitLabを使用しています。本記事では外部パッケージのメジャーアップデート検知にRenovate、定期実行ツールとしてGitLab CIを使ったgoパッケージの自動更新のセットアップ方法を扱います。
Renovateとは
パッケージの依存関係の更新を自動で検知し、対象ブランチにmerge
or pull request
してくれるツールです。
対象はgo modulesの他にも、
- npmパッケージ
- Gem
- pip
など、他にもさまざまな言語のパッケージ管理ツールをサポートしています。
似たようなものに、Dependabotがあります。こちらは2019年、GitHubに買収されたこともあり、現在はGitHub公式機能になっているため、こちらの方が知名度は高いかもしれません。
筆者は当初、このDependabotを使用する予定だったのですが、こちらをGitLabと組み合わせるには設定が何やら面倒そうでした。
Renovateの方はDockerHubの方に公式イメージがあるので、こちらをGitLabのCIツールであるgitlab-ciでビルドし、Renovateのスクリプトを実行するだけで済みます。この手軽さから、今回はGitLab CI × Renovateの構成を選択しています。
環境
手順
を参考にさせていただき、以下の手順で行いました。
- RenovateコンテナからGitLabリポジトリにアクセスできるように、
access token
を発行 - Renovateの設定
- GitLab CIの設定
GitLab側の設定(アクセストークンの発行)
Renovateの設定(Renovate.json)
renovate.jsonに、Renovatebotの設定を書き込みます。
{
"extends": [
"config:base"
],
"timezone": "Asia/Tokyo"
}
基本的に標準の設定をそのまま用いています。
今回は自動マージの設定はしておりませんが、その設定も行うことができます。
他にも、様々なオプションを設定できるので、詳しい情報は以下をご参照ください。
GitLab CIの設定(gitlab-ci.yml, schedular)
gitlab-ci.yml
に、実行するジョブの設定を記述します。
stages:
- check_version
renovate:
stage: check_version
image:
name: renovate/renovate:latest
entrypoint: [""]
script:
- node /usr/src/app/dist/renovate.js --platform gitlab --token {$先ほど作成したアクセストークン} --endpoint https://gitlab.com/api/v4 $CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
only:
variables:
- $renovate
refs:
- master
image:
name: renovate/renovate:latest
の部分で、renovateのDocker imageのlatest
タグを指定しています。
また、
only:
variables:
- $renovate
refs:
- master
only
で、ジョブが作成される条件を制御できます。
variables
・ref
キーワードで、後で設定する$renovate
という変数が有効になっているmaster
ブランチのイベントに対して、ジョブを作成するよう設定しています。
この設定がないと、リポジトリでのあらゆるイベントに対してジョブが作成されてしまいます。
この時点でのディレクトリは以下のようになっています。
$ tree
.
├── gitlab-ci.yml
└── renovate.json
テスト用にgitlab-ciを手動実行してみる
設定が終わったところで、リモート上で動作確認してみます。
リモートへ上げずに、ローカルのDockerコンテナでrenovate
を動作させる方法は以下になります。
docker run --rm renovate/renovate --platform gitlab --token {先ほど作成したtoken} --endpoint https://gitlab.com/api/v4 {リポジトリ名}
テスト用go.modの作成
動作を確認するため、サンプル用のgo mod
を作成します。
$ go mod init
テスト用に、わざとバージョンが低いパッケージを取得します。今回はginを対象にしています。
$ go get github.com/gin-gonic/gin@v1.6.1
最終的なディレクトリ構成は以下になります。
$ tree
.
├── go.mod
├── go.sum
└── renovate.json
ここまででリモートにpushします。
スケジューラの登録
GitLabで[CI/CD]→[Schedules]→[New schedule]と進み、ジョブのスケジューラを登録します。
実行は一週間に1回の頻度を指定しています。また、Variableでrenovate
という変数を有効化します。
この変数は、先ほど設定したgitlab-ci.yml
でジョブの制限条件で使用するものとなります。
スケジュールのテスト実行
GitLabで[CI/CD]→[Schedules]→[▶︎]を押すと、ジョブを手動実行できます。
パッケージのメジャーアップデートがあることを検知しており、masterブランチに対してバージョンアップ用merge requestが作成されていることが確認できます。
マージリクエストの中身をみてみると、go.mod
、go.sum
の依存パッケージが更新されていることがわかります。
おわりに
RenovateをGitLab CIで動かし、メジャーアップデートを検知する仕組みを行いました。人力による外部パッケージのメジャーアップデート追従は厳しいものがあるので、できることなら自動化しておきたいです。
また、業務に導入する際には、そのままだとMerge Requestが放置されたり一部の人に対応が集中したり、などの新たな課題が考えられます。こちらの記事を参考に、マージリクエストをランダムにメンバーにアサインさせるなどの工夫が必要かなと思います。
参考資料