こんにちは、テクマトリックスの酒井です。
2023 年 9 月に、 Jenkins をベースとした CI/CD 製品である CloudBees CI に新しい高可用性構成/水平スケーリング機能が搭載されました。今回はローカルの Kubernetes クラスターに CloudBees CI をインストールして高可用性構成/水平スケーリング機能を試し、 Jenkins コントローラーの高可用性を確認してみます。
目次
なぜ Jenkins コントローラーに高可用性が必要なのか
Jenkins のコントローラーは 1 つでたくさんのジョブを管理できますが、あまりにも多いと効率的に処理できなくなることがあります。そのようなコントローラーは過負荷のためにパフォーマンスが落ち、パイプラインの実行が長くなり、 UI の反応が遅くなり、クラッシュしてしまうこともあります。さらに、コントローラーで障害が発生したり再起動したりしてダウンタイムが発生すると、コントローラーで実行されているすべてのビルドと、コントローラーを利用しているすべてのチームが悪影響を受けてしまいます。
このような場合、 CloudBees CI の高可用性モードが提供する高可用性と水平スケーリングが課題の解決策となります。
CloudBees CI とは
CloudBees CI は、企業向けに設計された継続的インテグレーション(CI)のプラットフォームで、以下を提供します。
- 大規模な DevOps
- レジリエンスと高可用性
- 簡単な管理
- エンタープライズグレードのセキュリティ
このうち高可用性について、 2023 年 9 月に新しい高可用性構成/水平スケーリング機能がリリースされました。これによって次のような機能が提供されます。
- コントローラーのフェイルオーバー:コントローラーが異常終了しても、パイプラインのビルドは別のレプリカで継続されます。
- ローリング再起動:あるレプリカが再起動する間、他のレプリカは実行し続け、ユーザーはダウンタイムを経験しません。
- 負荷分散:一つの論理的なコントローラーは複数のレプリカに負荷を分散し、レプリカを同期します。
- 自動スケーリング:コントローラーの負荷に応じて自動的にレプリカ数を増減します。
このような機能により、 CI/CD のダウンタイムを削減または排除することや、高負荷なコントローラーを信頼でき安定したコントローラーに変換することができます。なおローリング再起動および自動スケーリングは、 CloudBees CI を Kubernetes にインストールする場合のみ利用可能です。
この記事では、 Kubernetes に CloudBees CI をインストールして、コントローラーのフェイルオーバーと自動スケーリングを試してみます。
構成
Windows 10 のローカル PC 上に Kubernetes クラスターを構築し、このクラスターに CloudBees CI をインストールします。本記事の内容をすべて試すためには、 Kubernetes クラスターは最低 5 以上の vCPU と 12GB 以上のメモリをポッドに提供できる必要があります。
CloudBees CI の高可用性構成を実行するためには複数のポッドから読み書き可能なファイルシステムが必要です。そのため Kubernetes クラスターに NFS サーバーのプロビジョナーをインストールします。
CloudBees CI には主要なコンポーネントが 3 種類あります。 1 つめはコントローラーと呼ばれ、 Jenkins のコントローラーと同等です。 2 つめはエージェントで、これも Jenkins のエージェントと同等です。 3 つめはオペレーションセンターと呼ばれ、ここで複数のコントローラーを一元管理します。事前の設定なしで CloudBees CI を Kubernetes にインストールするとオペレーションセンターのみが起動するため、続いてオペレーションセンターを操作して高可用性構成のコントローラーを作成する手順が必要です。コントローラーが作成できたら、このコントローラー上でジョブの作成や実行ができます。ジョブの実行に必要なエージェントについては、今回は Kubernetes のポッドとしてビルド実行の都度生成されるようにパイプラインで設定します。
準備
それでは構築していきます。最初に、ローカル PC で Hyper-V を有効化することと、環境構築に利用する Minikube, Kubernetes CLI, Helm などのツールをインストールします。この手順については以前の記事を参照してください。
Kubernetes クラスターの作成、および CloudBees CI のインストール
次に Minikube を利用して、 VM および Kubernetes クラスターを作成します。そして Helm チャートから CloudBees CI をインストールして、オペレーションセンターと高可用性構成のコントローラーを実行します。設定ファイルとスクリプトを利用して、 VM の作成から CloudBees CI のコントローラーの作成までをいっぺんに行います。
CloudBees CI の Helm チャートの設定
CloudBees CI の Helm チャートを利用して CloudBees CI をインストールするのですが、それに先立ってインストールのパラメーターを指定する values.yaml
ファイルを作成します。ファイルの内容を以下に記します。
Persistence:
StorageClass: nfs
OperationsCenter:
# License:
# Evaluation:
# # 評価ライセンスを取得します。この機能を使用すると、使用許諾契約に同意したことになります。
# # https://www.cloudbees.com/r/subscription
# Enabled: true
# FirstName: "YOUR_FIRST_NAME"
# LastName: "YOUR_LAST_NAME"
# Email: "YOUR_EMAIL"
# Company: "YOUR_COMPANY_NAME"
CasC:
Enabled: true
ExtraConfigMaps:
- name: oc-casc-bundle
data:
bundle.yaml: |
id: "bundle-1"
version: "1"
apiVersion: "1"
description: "My CloudBees Configuration as Code (CasC) bundle"
jcasc:
- "jenkins.yaml"
jcascMergeStrategy: "errorOnConflict"
plugins:
- "plugins.yaml"
rbac:
- "rbac.yaml"
items:
- "items.yaml"
jenkins.yaml: |
jenkins:
securityRealm:
# ユーザー情報にJenkinsのユーザーデータベースを使用します。
# 通常はLDAPなど外部のサービスを使用することを推奨します。
local:
users:
- id: "butler"
password: "026d7c798b09524a2d2fb8b45634877c"
name: "Butler Admin"
properties:
- mailer:
emailAddress: "butler@ci.cluster.local"
authorizationStrategy: "cloudBeesRoleBasedAccessControl"
unclassified:
cascAutoControllerProvisioning:
provisionControllerOnCreation: true
fireAndForget: true
initialDelay: 15
timeout: 600
duration: 60
plugins.yaml: |
plugins:
- id: "cloudbees-casc-client"
- id: "cloudbees-casc-items-api"
- id: "cloudbees-casc-items-commons"
- id: "cloudbees-casc-items-server"
- id: "configuration-as-code"
- id: "operations-center-rbac"
rbac.yaml: |
removeStrategy:
rbac: "SYNC"
roles:
- name: administer
permissions:
- hudson.model.Hudson.Administer
- name: developer
permissions:
- hudson.model.Hudson.Read
- hudson.model.Item.Read
- hudson.model.Item.Create
- hudson.model.Item.Configure
filterable: "true"
- name: browser
permissions:
- hudson.model.Hudson.Read
- hudson.model.Item.Read
filterable: "true"
- name: authenticated
filterable: "true"
permissions:
- hudson.model.Hudson.Read
groups:
- name: Administrators
roles:
- name: administer
grantedAt: current
members:
users:
- butler
- name: Developers
roles:
- name: developer
- name: Browsers
roles:
- name: browser
items.yaml: |
removeStrategy:
rbac: SYNC
items: NONE
items:
- # 高可用性構成のコントローラー
kind: managedController
name: managed-controller-alpha
displayName: managed-controller-alpha
configuration:
kubernetes:
domain: managed-controller-alpha
disk: 5
replication:
config:
# コントローラーのレプリカの数。
replicas: 2
# 自動スケーリングによるレプリカの最大数。 0 にすると自動スケーリングしません。
maxReplicas: 0
# コントローラーポッドの平均 CPU 使用率が設定値を超えるとスケールアップが開始されます。
targetCPUUtilizationPercentage: 80
values.yaml
の 74行目以降はオペレーションセンターのコードによる設定です。 112-119 行目にコントローラーの高可用性構成の設定があります。コントローラーごとに、レプリカ数、自動スケーリングによるレプリカの最大数、自動スケーリングを開始するしきい値を設定できます。
また values.yaml
の 5-13 行目は評価ライセンスの自動取得の設定です。 5-13 行目のコメントを外し、姓・名・メールアドレス・会社名を(英語で)入力すると、インストールと同時に自動的に評価ライセンスが取得・設定され、すぐに CloudBees CI の利用を開始できます。ただし、評価ライセンスを取得すると CloudBees の使用許諾契約に同意したことになりますのでご注意ください。 values.yaml
の 5-13 行目をコメントのまま進めることも可能ですが、オペレーションセンターへのアクセス後に評価ライセンスの取得フォームに氏名などを入力する必要があります。この記事ではコメントを外した場合の手順のみを記載します。
Kubernetes クラスターの作成と CloudBees CI のインストール
続いて、Kubernetes クラスターを作成して、 CloudBees CI のオペレーションセンターと高可用性構成のコントローラーを起動します。以下の Powershell スクリプトを実行します。
# VM と Kubernetes クラスターを作成
minikube start --driver=hyperv --cpus=6 --memory=12g --disk-size=40gb `
--addons ingress `
--addons metrics-server `
--docker-opt=bip=172.80.0.1/16 `
--docker-opt=default-address-pool=base=172.90.0.0/16,size=24 `
--docker-opt=dns="DNSサーバーのIPアドレス"
# アクセスモードが `ReadWriteMany` のボリュームをサポートするプロビジョナーをインストール
helm install --wait `
--namespace nfs `
--create-namespace `
--set persistence.enabled=true `
--set persistence.size=200Gi `
--repo https://kubernetes-sigs.github.io/nfs-ganesha-server-and-external-provisioner/ `
--version 1.8.0 `
nfs nfs-server-provisioner
# CloudBees CI on modern cloud platforms をインストール
helm repo add cloudbees https://public-charts.artifacts.cloudbees.com/repository/public/
helm repo update cloudbees
kubectl create namespace cloudbees-core
kubectl config set-context $(kubectl config current-context) --namespace=cloudbees-core
helm upgrade --install cloudbees-core `
cloudbees/cloudbees-core `
--version 3.14783.0 `
--namespace cloudbees-core `
--values values.yaml `
--set OperationsCenter.HostName="$(minikube ip).nip.io"
# オペレーションセンターの起動を待つ
Start-Sleep 5
kubectl rollout status sts cjoc --namespace cloudbees-core
# オペレーションセンターの URL を表示するため、 Helm リリースのステータスを表示
helm status cloudbees-core
スクリプトの実行が正常に終了すると、コンソール出力の最後の方に「2. Visit http://...
」と出力されます。この URL をブラウザで開くと、 CloudBees CI のオペレーションセンターのログインページが表示されます。ユーザー名に butler
、パスワードに 026d7c798b09524a2d2fb8b45634877c
と入力してログインすると、オペレーションセンターのダッシュボードが表示されます。
ダッシュボードには managed-controller-alpha
というコントローラーが表示されています。このコントローラーの行の Pod status 列から、レプリカが 2 個中 1 個実行されていることが確認できます。レプリカが 1 個しか実行されていないのはコントローラーの初期設定が完了していないためで、初期設定が完了すると別のレプリカも起動します。
managed-controller-alpha
をクリックしてコントローラーに移動すると、コントローラーの初期設定ページが表示されます。 Install suggested plugins を選択してプラグインをインストールし、続くページで Start using CloudBees CI Managed Controller ボタンをクリックすると、「 Jenkinsへようこそ!」と書かれたコントローラーのダッシュボードが表示されます。 CloudBees CI のコントローラーではありますが、 Jenkins のコントローラーと同じ使い方ができます。
この時点でポッドを確認すると、 cjoc-0
というオペレーションセンターのポッドが 1 個と、 managed-controller-alpha-
で始まるコントローラーのポッドが 2 個確認できます。
> kubectl get po
NAME READY STATUS RESTARTS AGE
cjoc-0 1/1 Running 0 27m
managed-controller-alpha-d6fbbc885-gzs9b 1/1 Running 0 24m
managed-controller-alpha-d6fbbc885-jqxtn 0/1 Running 4 (22s ago) 24m
フェイルオーバーさせてみる
ジョブの実行中にコントローラー(のレプリカ)が停止した際、実行中のジョブがどのようになるかを見ていきます。
まずはジョブを作成します。コントローラーのページの左側メニューの 新規ジョブ作成 から test-pipeline
という名前のパイプラインジョブを作成します。続く設定ページで、パイプラインスクリプトに以下を入力して保存します。
pipeline {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: gcc
image: gcc:13.2.0
command:
- cat
tty: true
'''
defaultContainer 'gcc'
}
}
stages {
stage('first') {
steps {
sh '''
make --version
sleep 30
gcc --version
'''
}
}
}
}
続いて左側メニューの ビルド実行 をクリックしてビルドを開始し、そのビルドのコンソール出力に移動します。コンソール出力の 2 行目から、このビルドは managed-controller-alpha-d6fbbc885-gzs9b
ポッドによって管理されていることが分かります。
それでは、このジョブの実行中にレプリカのポッドを削除してみます。コンソール出力に + sleep 30
まで出力されている時点、つまりスクリプトの実行中に、次のコマンドを実行してポッドを削除します。
> kubectl delete pod managed-controller-alpha-d6fbbc885-gzs9b
pod "managed-controller-alpha-d6fbbc885-gzs9b" deleted
ポッドの削除後も引き続きコンソール出力を見ていると、ビルドの管理がもう一つのポッド managed-controller-alpha-d6fbbc885-jqxtn
に引き継がれる様子を確認できます。
ビルドを管理するレプリカが削除されてもビルドは継続され、無事完了しました!
自動スケーリングさせてみる
次にコントローラーの自動スケーリングを試してみます。自動スケーリングは、コントローラーの負荷が高くなると自動的にレプリカが増えて負荷を分散し、負荷が低くなるとレプリカが減る仕組みです。
まずは自動スケーリングを有効にします。パンくずリストの Jenkins > managed-controller-alpha
の右の歯車アイコン > Configure の順に移動して managed-controller-alpha
の設定ページを開きます( Jenkinsの管理 ページではありません)。そして High Availability までページを下にスクロールすると、高可用性構成の設定が見えます。
今回は自動スケーリングがわざと働くよう、 Maximum number of replicas に 4
を、 CPU threshold in percent に 20
を入力し、 Save ボタンをクリックします。そしてこの設定を反映するために、ページ左側の Stop 、 Start を順にクリックしてコントローラーを再起動します。コントローラーが起動する一方で Kubernetes クラスターでは HolizontalPodAutoscaler リソースが作成されます。
> kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
managed-controller-alpha Deployment/managed-controller-alpha <unknown>/20% 2 4 2 49s
Status に Connected と表示されたら、自動スケーリングを試してみましょう。 managed-controller-alpha
コントローラーの test-pipeline
ジョブに移動して、ページ左側の ビルド実行 を 10 ~ 15 回くらいクリックします。たくさんのビルドが開始されます。
HolizontalPodAutoscaler リソースをウォッチしていると、ターゲットが 20% を超えるとレプリカが増え、20% を下回ってしばらくするとレプリカが減る様子が確認できました。
> kubectl get hpa --watch
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
managed-controller-alpha Deployment/managed-controller-alpha 6%/20% 2 4 2 13m
managed-controller-alpha Deployment/managed-controller-alpha 53%/20% 2 4 2 14m
managed-controller-alpha Deployment/managed-controller-alpha 53%/20% 2 4 4 15m
managed-controller-alpha Deployment/managed-controller-alpha 37%/20% 2 4 4 15m
managed-controller-alpha Deployment/managed-controller-alpha 8%/20% 2 4 4 16m
managed-controller-alpha Deployment/managed-controller-alpha 30%/20% 2 4 4 17m
managed-controller-alpha Deployment/managed-controller-alpha 26%/20% 2 4 4 18m
managed-controller-alpha Deployment/managed-controller-alpha 17%/20% 2 4 4 19m
managed-controller-alpha Deployment/managed-controller-alpha 17%/20% 2 4 4 20m
managed-controller-alpha Deployment/managed-controller-alpha 10%/20% 2 4 4 20m
managed-controller-alpha Deployment/managed-controller-alpha 15%/20% 2 4 4 21m
managed-controller-alpha Deployment/managed-controller-alpha 3%/20% 2 4 4 22m
managed-controller-alpha Deployment/managed-controller-alpha 2%/20% 2 4 4 23m
managed-controller-alpha Deployment/managed-controller-alpha 2%/20% 2 4 4 24m
managed-controller-alpha Deployment/managed-controller-alpha 2%/20% 2 4 3 24m
managed-controller-alpha Deployment/managed-controller-alpha 2%/20% 2 4 3 26m
managed-controller-alpha Deployment/managed-controller-alpha 2%/20% 2 4 3 27m
managed-controller-alpha Deployment/managed-controller-alpha 4%/20% 2 4 2 27m
managed-controller-alpha Deployment/managed-controller-alpha 1%/20% 2 4 2 28m
途中で別のターミナルからポッドを確認すると、 managed-controller-alpha-
で始まるポッドが増えていました。
> kubectl get po
NAME READY STATUS RESTARTS AGE
cjoc-0 1/1 Running 0 55m
managed-controller-alpha-544b58fc68-b5ldh 1/1 Running 0 15m
managed-controller-alpha-544b58fc68-kdxlc 1/1 Running 0 15m
managed-controller-alpha-544b58fc68-lg9kc 0/1 Pending 0 50s
managed-controller-alpha-544b58fc68-pkqmk 0/1 Pending 0 50s
test-pipeline-11-24k8h-rzvf9-9jb5x 2/2 Running 0 79s
test-pipeline-12-48h8f-crb7v-mp0sh 2/2 Running 0 79s
test-pipeline-2-pgq3z-hlzwh-0wrlm 2/2 Terminating 0 78s
test-pipeline-8-dzt22-mxbz5-9ct1c 2/2 Running 0 79s
以上で、コントローラーの負荷に応じて自動的にスケールアップ・スケールダウンすることが確認できました!
まとめ
CloudBees CI を利用して Jenkins コントローラーのフェイルオーバーと自動スケーリングを体験しました。この記事の執筆時点では OSS の Jenkins にフェイルオーバーや自動スケーリングのような機能は搭載されておらず、結果として Jenkins が CI/CD における単一障害点となってしまいがちです。今回試した高可用性構成によって、この単一障害点が解消され、 CI/CD のダウンタイムがなくなると思いました。加えて、ダウンタイムがあることによる開発者の不満や、 CI/CD 環境をメンテナンスする労力も減らすことができるのではと感じました。