こんにちは。Xイノベーション本部クラウドイノベーションセンターの柴田です。
本記事では Renovate を使ったKubernetesエコシステムの自動バージョンアップを紹介します。
なお本記事の内容は Kubernetes Meetup Tokyo #48 で紹介された 個人運用k8sクラスタの構成要素の技術選定 - でこてっくろぐ ねお にインスパイアされています。
背景
Kubernetesでは、Kubernetesと連携して動作する様々なOSSやサービスを活用することで、アプリケーションの開発・運用に関する生産性向上や効率化を図ることができます。 本記事ではそれらをKubernetesエコシステムと呼びます。 多くのKubernetesエコシステムは開発元が提供しているコンテナイメージやマニフェストファイルを自分たちのKubernetesクラスタへデプロイして利用します。 開発が盛んなKubernetesエコシステムでは、頻繁に新機能やセキュリティ改善が実装され、新しいバージョンとしてリリースされます。 Kubernetesエコシステムの恩恵を最大限に享受するにはなるべく新しいバージョンを使用することが望ましいです。
またKubernetesでは、マニフェストファイルを GitOps と呼ばれる手法で管理・デプロイすることが多いです。 GitOpsはWeaveworks社が提唱した継続的デプロイの方法であり、以下の特徴があります。
- システム全体が宣言的に記述されていること。
- マニフェストがgitで管理され、それが信頼できる唯一の情報源(Single Source of Truth)であること。
- 承認されたマニフェストの変更が自動的にデプロイされること。またその際Kubernetesクラスタへの認証情報を外部(例えばCIサーバなど)に持たせる必要がないこと。
- マニフェストとKubernetesクラスタの間に差分がある場合、それを検知したり、自動的に修正したりできること。
GitOpsを実現するツールには例えば Argo CD、Flux、PipeCD があります。
以上から、Kubernetesエコシステムの新しいバージョンがリリースされる度に、gitリポジトリで管理されたそれらのマニフェストを最新の内容に更新できることが望ましいです。 また、運用負荷がかからないよう、マニフェストの更新はなるべく自動的に行えることが望ましいです。
Renovateとは
Renovate はプロジェクトの依存関係の更新を自動化するツールです。 似たようなツールに Dependabot などがあります。 Renovateはアプリケーションのライブラリの自動バージョンアップに使われることが多いですが、アプリケーション開発以外の用途でも利用できます。
ここからはRenovateで何ができるかを簡単に説明します。 なお本記事では Renovate v32.97.0 を前提とします。
Platform
Renovateは以下に格納された依存関係ファイルを更新できます。
- Azure DevOps
- Azure DevOps Server
- Bitbucket Cloud
- Bitbucket Server
- Gitea
- GitHub
- GitHub Enterprise Server
- GitLab
Manager
Renovateは以下の依存関係を更新できます。
- docker : ansible, docker-compose, dockerfile, droneci, gitlabci, kubernetes
- dotnet : cake, nuget
- elixir : mix
- golang : gomod
- java : gradle, maven
- js : meteor, npm
- node : nodenv, nvm, travis
- php : composer
- python : pip-compile, pip_requirements, pip_setup, pipenv, poetry, pyenv, setup-cfg
- ruby : bundler, ruby-version
- rust : cargo
- other : ansible-galaxy, argocd, azure-pipelines, batect, batect-wrapper, bazel, bitbucket-pipelines, buildkite, cdnurl, circleci, cloudbuild, cocoapods, conan, deps-edn, flux, fvm, git-submodules, github-actions, gitlabci-include, gradle-wrapper, helm-requirements, helm-values, helmfile, helmsman, helmv3, homebrew, html, jenkins, jsonnet-bundler, kustomize, leiningen, pre-commit, pub, regex, sbt, swift, terraform, terraform-version, terragrunt, terragrunt-version, velaci
Datasource
Renovateは以下の依存先の更新を検知できます。
adoptium-java, artifactory, aws-machine-image, bitbucket-tags, cdnjs, clojure, conan, conda, crate, dart, docker, flutter-version, galaxy, galaxy-collection, git-refs, git-tags, github-releases, github-tags, gitlab-packages, gitlab-releases, gitlab-tags, go, golang-version, gradle-version, helm, hex, jenkins-plugins, maven, node, npm, nuget, orb, packagist, pod, pypi, repology, ruby-version, rubygems, sbt-package, sbt-plugin, terraform-module, terraform-provider
Versioning
依存関係を更新するためにはバージョン表記を比較できる必要があります。 Renovateでは以下のフォーマットのバージョン表記を扱えます。
aws-machine-image, cargo, composer, conan, debian, docker, git, gradle, hashicorp, helm, hex, ivy, loose, maven, node, npm, nuget, pep440, poetry, regex, rez, ruby, semver, semver-coerced, swift, ubuntu
RenovateでKubernetesエコシステムを自動更新する
では実際にRenovateを使ってKubernetesエコシステムの更新作業を自動化したいと思います。
更新対象のKubernetesクラスタ
今回は私が検証用途で使用しているKubernetesクラスタを対象にします。 このKubernetesクラスタには以下の特徴があります。
- すべてのマニフェストはGitHubリポジトリで管理しています。
- マニフェストをKubernetesクラスタへデプロイするために Argo CD と Flux を使用しています。
- 通常は片方だけで十分ですが、検証用途の環境のため両方とも動かしています。
- Kubernetesエコシステムのマニフェストは、以下のいずれかの方法で管理しています。
- Helm:
公式や3rd partyが提供するHelm Chartを利用します。
具体的にはArgo CDの
Application
リソースやFluxのHelmRelease
リソースとしてKubernetesクラスタへデプロイします。 またローカル環境でマニフェストを生成できるよう helmfile も使用しています。 - Kustomize:
kustomize を使って公式が提供するマニフェストをhttps経由で参照します。
イメージタグを書き換えることもあります。
以下は amazon-vpc-cni-k8s のマニフェストを生成する
kustomization.yaml
の例です。
- Helm:
公式や3rd partyが提供するHelm Chartを利用します。
具体的にはArgo CDの
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.10.3/config/master/aws-k8s-cni.yaml images: - name: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni newName: 602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni newTag: v1.10.3 - name: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni-init newName: 602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni-init newTag: v1.10.3
Renovateを実行する
Renovateには大まかに2種類の実行方法があります。
- GitHub App を使用する
- 自分たちでRenovateを実行する(Self-Hosting)
今回はGitHub Actions renovatebot/github-action
を使用して自分たちでRenovateを実行します。
その他のSelf-Hostingの実行方法は Self-Hosting Renovate を参照してください。
以下はGitHub Actionsのワークフローです。
# .github/workflows/renovate.yaml name: Renovate on: schedule: - cron: '0 0 * * *' # Run workflow at 09:00 AM JST every day jobs: renovate: name: Renovate runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run renovate uses: renovatebot/github-action@v32.97.0 with: token: ${{ secrets.GH_TOKEN }} configurationFile: renovate.json
GH_TOKEN
は https://github.com/renovatebot/github-action#token に従って作成したGitHubのPersonal Access Tokenです。
GitHub Actionsでは GITHUB_TOKEN
が利用できますが、 https://github.com/renovatebot/github-action#token に
Note that the
GITHUB_TOKEN
secret can't be used for authenticating Renovate.
とあるためこのようにしています。
Renovateの設定
次にRenovateの設定ファイル renovate.json
を作成します。
今回使用した設定は以下のとおりです。
{ "repositories": [ "ISID/renovate-sample" ], "extends": [ "config:base", ":prHourlyLimitNone", ":prConcurrentLimitNone" ], "enabledManagers": [ "argocd", "flux", "helmfile", "kustomize", "regex" ], "labels": [ "renovate" ], "assignees": [ "@ShibataTakao" ], "argocd": { "fileMatch": [ "^manifests/argo-cd-apps/.*\\.ya?ml$" ] }, "flux": { "fileMatch": [ "^manifests/flux/.*\\.ya?ml$", "^manifests/flux-ks/.*\\.ya?ml$" ] }, "regexManagers": [ { "fileMatch": [ "(^|/)kustomization\\.ya?ml$" ], "matchStrings": [ "https://raw\\.githubusercontent\\.com/(?<depName>[^/]+/[^/]+)/(?<currentValue>[^/]+)/.*", "https://github\\.com/(?<depName>[^/]+/[^/]+)/releases/download/(?<currentValue>[^/]+)/.*" ], "datasourceTemplate": "github-releases", "versioningTemplate": "semver" } ], "packageRules": [ { "matchPackageNames": [ "kubernetes/autoscaler" ], "matchDatasources": [ "github-tags", "github-releases" ], "versioning": "regex:^cluster-autoscaler-(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)?$", "allowedVersions": "< 1.23.0" }, { "matchPackageNames": [ "k8s.gcr.io/autoscaling/cluster-autoscaler" ], "matchDatasources": [ "docker" ], "allowedVersions": "< 1.23.0" } ] }
各設定を順に見ていきましょう。
"repositories": [ "ISID/renovate-sample" ]
repositories
にはRenovateの対象とするリポジトリを指定します。
リポジトリ名を直接指定するかわりに autodiscover
と autodiscoverFilter
を設定してRenovateの対象とするリポジトリを自動的に検出することもできます。
"extends": [ "config:base", ":prHourlyLimitNone", ":prConcurrentLimitNone" ]
extends
には Preset を指定します。
Presetは定義済みの設定の集合です。
デフォルトで定義されたPresetを使うだけでなく、独自のPresetを定義することもできます。
今回は以下のPresetを使用します。
"enabledManagers": [ "argocd", "flux", "helmfile", "kustomize", "regex" ]
enabledManagers
を設定して明示的に指定したManagerのみを有効化します。
多くのManagerはデフォルトで有効になっています。
各Managerの有効/無効は <manager>.enabled
の値を true
または false
に設定することで変更できます。
または enabledManagers
に有効にするManagerを明示的に指定することで、指定したManagerのみを有効にできます。
詳細は Enabling and disabling managers を参照してください。
今回は以下のManagerのみを有効化します。
今回の更新対象のうち
- Helm: 公式や3rd partyが提供するHelm Chartを利用します。 具体的にはArgo CDの
Application
リソースやFluxのHelmRelease
リソースとしてKubernetesクラスタへデプロイします。 またローカル環境でマニフェストを生成できるよう helmfile も使用しています。
は argocd
と flux
と helmfile
を使ってHelm ChartをバージョンアップするためのPRを自動成します。
また
は kustomize
と regex
を使って参照先のマニフェストのURLやイメージタグをバージョンアップするためのPRを自動作成します。
regex
については後ほどもう少し詳しく説明します。
"labels": [ "renovate" ], "assignees": [ "@ShibataTakao" ]
labels
と assignees
にはRenovateが依存関係を更新するために作成するPRのLabelsとAssigneesを設定します。
"argocd": { "fileMatch": [ "^manifests/argo-cd-apps/.*\\.ya?ml$" ] }, "flux": { "fileMatch": [ "^manifests/flux/.*\\.ya?ml$", "^manifests/flux-ks/.*\\.ya?ml$" ] }
fileMatch
には各Managerの依存関係ファイルの追加パスを正規表現で記述します。
多くのManagerにはデフォルトの fileMatch
が設定されていますが、デフォルトの fileMatch
が設定されていない場合や独自のファイルパスを追加で設定したい場合には、 fileMatch
にそれらを追加設定できます。
"regexManagers": [ { "fileMatch": [ "(^|/)kustomization\\.ya?ml$" ], "matchStrings": [ "https://raw\\.githubusercontent\\.com/(?<depName>[^/]+/[^/]+)/(?<currentValue>[^/]+)/.*", "https://github\\.com/(?<depName>[^/]+/[^/]+)/releases/download/(?<currentValue>[^/]+)/.*" ], "datasourceTemplate": "github-releases", "versioningTemplate": "semver" } ]
regexManagers
には regex
Managerの設定を記述します。
regex
を用いることで正規表現を使用して依存関係を検出・自動更新するユーザー独自の仕組みを構築できます。
今回は
- Kustomize: kustomize を使って公式が提供するマニフェストをhttps経由で参照します。 イメージタグを書き換えることもあります。 以下は amazon-vpc-cni-k8s のマニフェストを生成する
kustomization.yaml
の例です。
yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.10.3/config/master/aws-k8s-cni.yaml images: - name: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni newName: 602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni newTag: v1.10.3 - name: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni-init newName: 602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni-init newTag: v1.10.3
で述べた参照先のマニフェストのURLを自動更新するためにこの仕組みを利用します。
fileMatch
には更新対象のファイル kustomization.yaml
のファイルパスを正規表現で設定します。
matchStrings
には kustomization.yaml
内の更新対象の文字列を設定します。
今回は
https://raw.githubusercontent.com/<user>/<repo>/<tag>/<filepath>
(GitHubリポジトリのコンテンツ)https://github.com/<user>/<repo>/releases/download/<release>/<filepath>
(GitHubリポジトリのリリースのアセット)
が更新対象です。
regex
では更新対象の依存関係に関する以下の設定をする必要があります。
これらは、該当する設定項目に値を設定するか、 matchStrings
の正規表現に名前付きキャプチャグループを用いることで設定できます。
Capture Group | Config Field | 必須 | 説明 |
---|---|---|---|
currentValue |
なし | 必須 | 現在のバージョン。Renovateによって更新される。 |
depName |
depNameTemplate |
必須 | 依存関係の名前。 |
packageName |
packageNameTemplate |
オプション | パッケージ名。省略した場合 depName と同じになる。 |
datasource |
datasourceTemplate |
必須 | 依存関係の参照先( Datasource )。 |
depType |
depTypeTemplate |
オプション | 依存関係の種類。 |
versioning |
versioningTemplate |
オプション | 依存関係のバージョン表記( Versioning )。デフォルトは semver 。 |
extractVersion |
extractVersionTemplate |
オプション | キャプチャしたバージョンと Datasource のバージョンの表記が異なる場合に使用する。詳細は extractVersion を参照。 |
currentDigest |
なし | オプション | 現在のDigest。Renovateによって更新される。 |
registryUrl |
registryUrlTemplate |
オプション | 依存関係の参照先のURL。詳細は registryUrls を参照。 |
"packageRules": [ { "matchPackageNames": [ "kubernetes/autoscaler" ], "matchDatasources": [ "github-tags", "github-releases" ], "versioning": "regex:^cluster-autoscaler-(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)?$", "allowedVersions": "< 1.23.0" }, { "matchPackageNames": [ "k8s.gcr.io/autoscaling/cluster-autoscaler" ], "matchDatasources": [ "docker" ], "allowedVersions": "< 1.23.0" } ]
packageRules
には特定の依存関係の更新における追加ルールを設定します。
今回は Cluster Autoscaler に関する以下の追加ルールを設定します。
- Cluster AutoscalerのGiHubリポジトリにおけるタグやリリースの命名規則は
cluster-autoscaler-<major>.<minor>.<patch>
です(例: cluster-autoscaler-1.22.3)。それを解釈できるようversioning
にregex
の正規表現を指定します。 - Cluster Autoscalerは対象のKubernetesクラスタに対応したバージョンを動かす必要があります。
今回の対象であるKubernetesクラスタは現時点でv1.22です。
よってCluster Autoscalerのバージョンもv1.22.Xである必要があります。
RenovateがCluster Autoscalerをv1.23.X以降に更新しないよう
allowedVersions
を指定します。
実行結果
設定に従いGitHub Actionsが毎朝9時にRenovateを実行します。
Helm Chartに更新がある場合は以下のようなPRが自動的に作成されます。
Kustomizeが参照するマニフェストのURLやイメージタグに更新がある場合は以下のようなPRが自動的に作成されます。
PRの説明文には公式GitHubリポジトリのReleaseからRelease Notesが転記されており、具体的な変更内容を知ることができます。
また Dependency Dashboard を有効にしておくと、Renovateが作成したPRを一覧して管理できるIssueが作成されます。
Dependency Dashboardを有効化する設定はPreset config:base
に含まれています。
あとはこれらのPRをマージし、Argo CDやFluxを使ってKubernetesクラスタへデプロイするだけで、Kubernetesエコシステムの更新は完了です。
なお今回は全てのPRの承認・マージを手動で行う形にしましたが、特定の更新のみ承認・マージを必要にしてそれ以外はPRを自動的にマージするよう設定することも可能です。 特定の更新として、例えば特定のパッケージやメジャーバージョンの更新などが設定できます。
おわりに
本記事ではRenovateを使ったKubernetesエコシステムの自動バージョンアップを紹介しました。
開発が盛んなKubernetesエコシステムでは、頻繁に新機能やセキュリティ改善が実装され、新しいバージョンとしてリリースされます。 Renovateを活用し、Kubernetesエコシステムを頻繁かつ自動的にバージョンアップすることで、それらの恩恵を最大限に享受できます。
本記事が少しでもKubernetesクラスタを運用している方のお役に立てば幸いです。
私たちは同じチームで働いてくれる仲間を探しています。クラウドアーキテクトの業務に興味がある方のご応募をお待ちしています。
執筆:@shibata.takao、レビュー:@yamashita.tsuyoshi (Shodoで執筆されました)