Renovate Botで依存関係とDockerイメージの更新を自動化:安全なPull Requestワークフロー

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

背景と導入理由

ソフトウェアは静かに劣化していきます。アップストリームの開発者が重大なバグを修正したりセキュリティパッチをリリースしたりするにつれ、package.json、requirements.txt、go.mod に記載されたあらゆるパッケージは次第に遅れをとっていきます。コンテナ層も例外ではありません。node:20-alpine や python:3.11-slim を指定したDockerfileは一見安定しているように見えます。しかし水面下では、最新のベースダイジェストをプルしてリビルドしない限り、OpenSSLやcurlといった下位のOSパッケージに毎月重大なCVE(脆弱性)が蓄積されていきます。

多くの場合、放置がこの劣化を招きます。エンジニアがユーザー向け機能の開発スプリントに追われていると、30ものマイクロサービスにわたる変更履歴(changelog)の確認はスプリントボードからこぼれ落ちてしまいがちです。セキュリティスキャナーが問題を指摘してくれても、スキャンするだけではコードは修正されません。その結果、チームは修正・テストの計画もないまま、優先順位のついていない60件ものJiraチケットやアラートに忙殺されることになります。

Renovate Botは、日常的なアップデートを扱いやすい小規模なPull Request(PR)へ自動変換することで、この行き詰まりを解消します。Dependabotのようなシンプルなツールとは異なり、Renovateは複数エコシステムが混在するモノレポの処理、Helmチャートの依存関係解決、不変なDockerダイジェストの固定に対応しており、スケジュールや自動マージをきめ細かく制御できます。

アップデートを後回しにして誰もが嫌がる四半期ごとのスプリントにまとめるやり方は、ほとんど機能しません。対照的に、小規模で扱いやすい単位のPull Requestに分割すれば、摩擦を大幅に軽減できます。アップストリームのリリースノートがPRの説明文に直接記載され、CIも即座に実行されます。メンテナンス作業は、チーム総出のパニックから日常的なバックグラウンド作業へと変貌します。

インストール手順

Renovateの実行方法には主に2通りあります。マネージドなGitHub Appを利用する方法と、CI/CDパイプライン内のセルフホストランナー上でエフェメラル(使い捨て)タスクとして実行する方法です。

方法1:GitHub App(インフラ構築不要)

標準的なGitHubアカウントであれば、クラウドアプローチの設定は5分もかかりません。

  1. GitHub Marketplaceを開き、公式のRenovateアプリケーションを検索します。
  2. 対象リポジトリを選択し、コードとPull Requestに対する読み取り/書き込み権限を承認します。
  3. Pull Requestタブを確認します。Renovateが初期設定用のrenovate.jsonファイルを含む、Configure RenovateというタイトルのオンボーディングPRを自動的に作成します。

方法2:GitHub Actionsによるセルフホストランナー

強固なファイアウォールの背後でプライベートなArtifactoryレジストリやGitHub Enterpriseを運用している場合は、セルフホストが適しています。repo権限を持つPersonal Access Token(またはスコープを絞ったGitHub Appの秘密鍵)を生成し、RENOVATE_TOKENという名前でリポジトリシークレットに保存します。

次のワークフローファイルを.github/workflows/renovate.ymlとして保存します。

name: Renovate

on:
  schedule:
    # 月曜日から金曜日の 04:00 UTC に実行
    - cron: '0 4 * * 1-5'
  workflow_dispatch:

jobs:
  renovate:
    runs-on: ubuntu-latest
    steps:
      - name: リポジトリをチェックアウト
        uses: actions/checkout@v4

      - name: Renovate Bot を実行
        uses: renovatebot/[email protected]
        with:
          configurationFile: .github/renovate.json5
          token: ${{ secrets.RENOVATE_TOKEN }}

設定

設定ファイルはプロジェクトルート、または.github/ディレクトリ内に配置します。JSON5はインラインコメントや見やすいフォーマットに対応しているため、.github/renovate.json5を使用するのが理想的です。

Dockerサポートを含む基本設定

以下は実績のある実戦向けテンプレートです。各言語のパッケージ管理、コンテナタグの不変ダイジェストへの固定、安全なパッチ更新のグループ化を行い、ボットの大量通知によるスパムを防ぎます。

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended",
    ":dependencyDashboard"
  ],
  "timezone": "Asia/Ho_Chi_Minh",
  "schedule": ["before 6am on monday"],
  "prConcurrentLimit": 5,
  "prHourlyLimit": 2,
  "labels": ["dependencies", "renovate"],
  "packageRules": [
    {
      "description": "PRのノイズを抑えるためnpmパッケージのマイナーおよびパッチ更新をグループ化",
      "matchManagers": ["npm"],
      "matchUpdateTypes": ["minor", "patch"],
      "groupName": "npm minor and patch updates"
    },
    {
      "description": "Dockerイメージタグを不変なsha256ダイジェストに固定",
      "matchManagers": ["dockerfile"],
      "pinDigests": true
    },
    {
      "description": "CI通過後に安定したパッチ更新を自動マージ(0.x系のSemVerリリースは除外)",
      "matchUpdateTypes": ["patch"],
      "matchCurrentVersion": "!/^0/",
      "automerge": true,
      "automergeType": "pr"
    }
  ]
}

matchCurrentVersion: "!/^0/"のルールに注目してください。セマンティックバージョニング(SemVer)では、0.x.yのパッケージはパッチリリースであっても破壊的なAPI変更が含まれることがよくあります。この保護ルールにより、安定版となる1.0.0に到達するまで、不安定なライブラリが自動マージパイプラインに含まれるのを防ぐことができます。

RenovateによるDockerイメージ固定の仕組み

標準的なDockerタグは可変(ミュータブル)なポインタです。アップストリームのメンテナーが明日golang:1.22-alpineを上書きしてしまえば、手元のコードを一切変更していなくても次のビルドが失敗する可能性があります。Renovateは、チームにとって可読性の高いタグ名を維持しながら、暗号学的に正確なSHA256ダイジェストでロックすることでこの問題を解決します。

次のような初期状態のDockerfileを考えてみましょう。

# Renovate 導入前:
FROM golang:1.22-alpine
WORKDIR /app
COPY . .
RUN go build -o server main.go
CMD ["./server"]

Renovateはベースイメージを解析し、次のような更新PRを作成します。

# Renovate の PR 適用後:
FROM golang:1.22-alpine@sha256:43c094ad24b6ac0546c62193baeb3e6e49ce14d3250845d166c77c25f64b0386
WORKDIR /app
COPY . .
RUN go build -o server main.go
CMD ["./server"]

これにより、ビルドは完全に決定論的(再現可能)になります。アップストリームの発行元がカーネルパッチを含むAlpineベースイメージをリビルドしてプッシュするたびに、Renovateはハッシュを更新する専用PRを生成します。Goランタイムのバージョンを見失うことなく、監査可能性を確保できます。

検証とモニタリング

厳格な安全策なしに自動PRを導入すると、ほぼ確実にmainブランチの破損を招きます。クリーンなワークフローを実現するには、可視性と堅牢なテストスイートが不可欠です。

1. Dependency Dashboard(依存関係ダッシュボード)

:dependencyDashboardを追加すると、リポジトリ内に1つのインタラクティブなGitHub Issueが有効化されます。このダッシュボードは包括的なコントロールセンターとして機能します。

  • 次のスケジュール枠で処理待ちとなっている今後の更新一覧
  • ブランチのレート制限やステータスチェックの失敗により保留されているPR
  • クローズされたPRの再オープンや、オンデマンドで即座にチェックを実行できるインタラクティブなMarkdownチェックボックス

テックリードは、クローズされたPRのログを精査することなく、プロジェクト全体の依存関係の乖離(ドリフト)を30秒で把握できます。

2. 厳格なCIゲートの適用

勘や当て推量だけでautomerge: trueを有効にしてはいけません。ユニットテスト、結合テスト、コンテナビルドを実行するGitHubの必須ステータスチェックを設定し、mainブランチを保護してください。

name: CI Pipeline

on:
  pull_request:
    branches: [main]

jobs:
  test-and-build:
    runs-on: ubuntu-latest
    steps:
      - name: コードをチェックアウト
        uses: actions/checkout@v4

      - name: Go のセットアップ
        uses: actions/setup-go@v5
        with:
          go-version: '1.22'

      - name: ユニットテストの実行
        run: go test -v -race -timeout 5m ./...

      - name: Docker ビルドの検証
        run: docker build --no-cache -t test-app ./

3. Docker Hubのレート制限への対策

匿名でのDocker Hubへのリクエストは、IPアドレスあたり6時間につき100回のプルに制限されています。共有のGitHub Actionsランナー上でRenovateが複数のマイクロサービスにわたる多数のイメージをチェックすると、HTTP 429 Too Many Requestsエラーに直面することになります。環境変数やホストルールを介して認証済みクレデンシャルを渡すことで、制限を200回(無料枠)または無制限(有料プラン)に引き上げることができます。

# ランナーに認証情報を渡す
RENOVATE_HOST_RULES='[
  {
    "hostType": "docker",
    "matchHost": "docker.io",
    "username": "prod-ci-bot",
    "password": "dckr_pat_YourPersonalAccessToken123"
  }
]'

スケジュールによるバッチ配信、不変ダイジェストによるロック、そして堅牢なCIチェックを組み合わせることで、手動での依存関係管理に伴う摩擦を解消できます。パッケージのログ調査に追われることなく、セキュリティを保ちながら本来のビジネスロジックの実装に集中できるようになります。

Share: