こんにちは。平田です。
OpenShiftのパイプラインビルドを使うとOpenShift上にJenkinsマスタがプロビジョニングされ、Jenkinsのジョブ実行時にエージェント(いわゆるスレーブ。「スレーブ(奴隷)」という言い方はなくなりつつある)Podが起動ます。
ですが、Jenkinsマスタは既存のものを使いたいケースもあると思います。そこで、こちらの記事を参考にOpenShiftの外部にあるJenkinsマスタからエージェントPodを起動してみたいと思います。
OpenShift側の設定
エージェントPodを起動するプロジェクトを作り、Jenkinsマスタが使用するサービスアカウントを作成します。
$ oc new-project jenkins-node
$ oc create serviceaccount jenkins
参考にした記事では権限付与しています。JenkinsジョブからプロジェクトをまたいだOpenShiftの操作を行う場合、適切な権限が必要となります。今回はPodの起動確認だけなので端折ります。
Jenkinsマスタ側の設定
記事のRequirementsに書かれていますが、OpenShift(のPod)からJenkinsのWebサーバポートとJNLPポートにアクセスできる必要があります。単に java -jar jenkins.war
と起動するとループバックアドレスにバインドされて外部からアクセスできなくなるため、 バインドするアドレスを指定します。
java -jar jenkins.war --httpListenAddress=0.0.0.0
起動したらエージェント用のポートを開放します。Jenkinsの管理 > グローバルセキュリティの設定 画面の「Agents」を固定、またはランダムにします。記事では50000にしろ、とありますが手元の環境ではランダムでも動きました。
次にKubernetes Pluginをインストールします。記事ではOpenShift系のプラグインを入れていますが、Podを起動するだけならKubernetes PluginのみでOKです。
インストールすると Jenkinsの管理 > システムの設定 画面の下部にある「クラウド」というセクションからKubernetesの設定を追加できるようになります。ここに、OpenShiftクラスタの情報を入力します。
- Name: 適当な名前をつける。
- Kubernetes URL: OpenShiftマスタのエンドポイント
- Kubernetes server certificate key:
oc serviceaccounts get-token jenkins
の値を入れる。 - Disable https certificate check: 自己証明書の場合、チェックする。
- Kubernetes Namespace: 作成したOpenShiftプロジェクト名
- Jenkins URL: OpenShiftからアクセス可能なJenkinsエンドポイント
更に「Add Pod Template」で起動するPodのスペック(使用するコンテナイメージなど)を定義します。どんなコンテナでも良いというわけではなく、起動したときにJNLPでマスタに接続するよう構成されている必要があります。Jenkinsが公式にベースイメージを公開している他、OpenShiftコミュニティでもMavenとNode.jsのイメージを公開しています(製品版はRed Hatコンテナレジストリにあります)。
- Name: 適当な名前をつける。
- Namespace: 作成したOpenShiftプロジェクト名
- Labels: maven(あとでJenkinsfileから指定する)
- Usage: 「このマシーンを特定ジョブ専用にする」を選ぶ。これを選ばないと、任意のジョブの実行にPodが使用される(Podで実行するつもりでないジョブが実行されてしまう)。
- Time in minutes to retain agent when idle: Podを破棄するまでの時間(分)を指定する。ジョブ終了後もしばらく生かしておくと、トラブルシューティングができて便利。
- Container Template
- Name: jnlp
- Docker Image: 前述の通り、マスタと通信する構成のイメージのみ指定可。ここでは
openshift/jenkins-agent-maven-35-centos7
を指定する。 - Always pull image: チェックする。
- Working directory:
/tmp
- Command to run: 空欄とする。
- Arguments to pass to the command:
${computer.jnlpmac} ${computer.name}
Kubernetes Pluginの設定画面の上の方(Credentialsの下)にある「Test Connection」を実行し、「Connection test successful」と出ることを確認します。うまくいかない場合、Kubernetes URLとcertificate keyが合っているか確認しましょう。
ジョブを起動する
JenkinsにてPipelineジョブを作成して実行してみます。Pod Templateで指定したラベルをagentに指定します。
pipeline {
agent { node { label 'maven'} }
stages {
stage('maven availability') {
steps {
sh "which mvn"
sh "mvn --version"
sh """
mvn dependency:get -B \
-DgroupId=javax -DartifactId=javaee-api -Dversion=7.0 \
-Dtransitive=false
"""
}
}
stage('oc availability') {
steps {
sh "which oc"
sh "oc whoami"
}
}
}
}
OpenShiftのPodを一覧を見ると、ジョブ実行時にPodが起動するのを確認できます。
OpenShiftコミュニティのMavenビルド用イメージでは、mvnコマンドに加えてocコマンドを利用できます。また、 oc whoami
で確認したところ system:serviceaccount:jenkins-node:jenkins
(最初に作成したサービスアカウント)としてログイン済みの状態となっていました。
PersistentVolumeClaimでMavenビルド高速化
エージェントPodが起動するようになったのは良いですが、毎回クリーンな環境が起動するためMavenのローカルリポジトリが空っぽの状態でビルドが始まります。Mavenに限らず依存ライブラリをダウンロードするビルドシステム、プログラミング言語では、Jenkinsジョブが著しく遅くなります。
これについて以下のような対応が考えられます。
- エージェントPod用のDockerfileにダウンロード処理を入れてコンテナイメージに含める。
- 依存ライブラリごとGitリポジトリに入れる。
- Nexus Repository Managerなどを立ててキャッシュする。
- Pod破棄までの時間をながーく設定し、事実上破棄させない。
- PersistentVolumeClaim (PVC) を割り付けて永続化する。
ここではこの記事を参考にPVCを付けてみます。まずPVCを作ります。以下のマニフェストファイルを作ります。
apiVersion: "v1"
kind: "PersistentVolumeClaim"
metadata:
name: "maven-slave-pvc"
spec:
accessModes:
- "ReadWriteMany"
resources:
requests:
storage: "2Gi"
PVCを作ります。
$ oc create -f maven-slave-pvc.yml
次に、Jenkins側に設定した Kubernetes Pod Template の「Volumes」項目にPVCを追加します。
- Claim Name: maven-slave-pvc
- Read Only: チェックしない
- Mount Path:
/home/jenkins/.m2
保存し、ジョブを2回実行します。1回目で依存ライブラリをダウンロードし、2回目以降キャッシュが効いてジョブ実行時間が短縮されます。
まとめ
OpenShift外部のJenkinsマスタから、OpenShift上にエージェントPodを起動し、ジョブを実行することができました。
OpenShiftコミュニティによるMavenエージェントイメージでは、mvnコマンドに加えてocコマンドも利用できます。Jenkinsジョブの実行に必要なツールを追加したい場合、既存のエージェントイメージを元にDockerfileを書くと良いでしょう。