既存のJenkinsサーバをEKS上に移行する

## はじめに
私が所属するDevOpsチームではEKS上で開発向け[aslead](https://helpdesk.aslead.cloud/wiki/portal)というサービスを展開しています。[aslead](https://helpdesk.aslead.cloud/wiki/portal)ではCI/CDツールとしてGitLab Runnerを採用しているのですが、Jenkinsを利用しているユーザーも多く移行コストがかかるため、EKS上にJenkinsを構築しサポートすることにしました。本記事ではEKS上にJenkinsを構築・移植する観点で手順を説明します。

## 方針
EKS環境にHelmを利用してJenkinsサーバを構築し、既存オンプレ環境のJenkins資産を移行します。
サーバ側の設定や認証など基本機能についてはこちらで作業を実施し、管理対象であるプロジェクトの移行はユーザー側で実施いただくことになりました。

## 構成
以下の移行先の現行構成に、HelmのJenkinsを追加します。
![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697478/5fe2e8ce-c488-37c5-9a4e-5dcf5416d5bb.png)


## master/slave構成の検討
Jenkinsのmaster/slave機能はHelm版でも利用できます。

#### 方式
##### master方式
  - Helm Chartでslave podを無効にした場合、master podですべての処理を行います。

##### master-slave方式
  - master-slave方式ではmaster podで設定を行い、揮発性のslave podでジョブを実行します。ジョブが完了したらslave podは消滅します。
  - Helm Chartで各slave pod毎にイメージを選択したり個別の設定を行うことができます。Jenkinsで管理するソフトウェア毎に異なるビルド・実行環境を用意したい場合、slave podを容易に準備し割り当てることができるため有効です。
  - masterの設定に加えて、以下のslaveの設定を追加すれば利用できます
     - Chart内でagentセクション、kubernetesのプラグインを設定
     - デプロイ後、Jenkins UIのConfigureCloudsのページでslave pod利用の設定

#### 課題
  - master-slave方式の場合、ジョブとpodの対応をパイプラインの形式で記述する必要があり、移植コストがかかる

#### 結論
当初master-slave方式で検討を進めていましたが、上記課題に記載のとおり、既存のJenkinsから移行する際にパイプライン形式にジョブを移植する必要がありました。
そもそもJenkinsを希望するユーザーは移植コストを抑えることが主な目的であること、今回のテナントでは全てのプロジェクトで同一のビルド・実行環境でよいという要件であったため、前者のmaster方式を採択しました。

## 構築の手順
ここから手順になります。

#### 1. S3バケットの作成
Jenkinsのアプリケーションバックアップの手段が用意されているため、設定情報を記述するvalue.yamlで設定行うことでS3にバックアップを取得できます。

value.yamlのパラメータは後ほど記載しますが、先にバックアップの保存先となるS3バケットを作成します。Jenkinsコンテナ内の/home/jenkins配下のファイルがバックアップされます。

#### 2. AWS Backupの設定
EBSバックアップの設定を行います。
アプリケーションバックアップも設定していますが、リストアを考えるとEBSバックアップから行う方が簡単かつ確実なためです。

#### 3. JenkinsのHelm Chartをダウンロード
公式からHelm Chartをダウンロードします。
https://github.com/helm/charts/tree/master/stable/jenkins

今回使用したバージョンは以下です。

|Chartバージョン|アプリバージョン|
|:--|:--|
|2.1.0|2.235.3|

#### 4. Helm Chartのパラメータの設定
value.yamlで以下のパラーメータを設定します。

|名前|デフォルト値|設定値|内容|
|:--|:--|:--|:--|
|initContainerEnv|(空)|(環境変数)|initコンテナでの環境変数の設定|
|containerEnv|(空)|(環境変数)|masterコンテナの環境変数の設定|
|javaOpts|(空)|(環境変数)|java_ops環境変数の設定|
|serviceType|ClusterIP|NodePort|サービスの種類|
|installPlugins|`kubernetes:1.25.7`<br/>    - `workflow-job:2.39`<br/>    - `workflow-aggregator:2.6`<br/>    - `credentials-binding:1.22`<br/>    - `git:4.2.2`<br/>    - `configuration-as-code:1.41`|（インストールするプラグイン）|インストールするプラグインを設定。デプロイ後UIからも追加可能。|
|ingress.enabled|false|true|Ingressの設定。今回は構築済み。|
|ingress.annotations|(空)|(ingressのannotations)|ingressのannotations|
|agent.enabled|true|false|slaveの設定|
|backup.enabled|false|true|アプリケーションバックアップの設定|
|backup.schedule|02***|19***|バックアップ取得のCronJobのスケジュール設定(UTC時間)|
|backup.annotations|(空)|iam.amazonaws.com/role: <CLUSTER>-S3FullAccessRole|backup podのannotations|
|backup.env.name|(空)|AWS_REGION|バックアップ環境変数|
|backup.env.value|(空)|ap-northeast-1|バックアップのリージョン|
|backup.env.destination|s3://jenkins-data/backup|(手順2で作成したS3バケット)|バックアップを保存するオブジェクトストレージのアクセス先|

 デフォルトではbackupジョブ起動時にbackup podがたち完了後も残ります。
 jenkins-backup-cronjob.yamlでpodの世代数を指定するためパラメータを追加します。

|名前|デフォルト値|設定値|内容|
|:--|---|:--|:--|
|successfulJobsHistoryLimit|(空)|1|バックアップジョブ成功時のpodの世代数|
|failedJobsHistoryLimit|(空)|1|バックアップジョブ失敗時のpodの世代数|


#### 5. Jenkinsをデプロイ
以下のコマンドで、パラメータ設定済みのvalue.yamlを使用してJenkinsをデプロイします。

```
$ helm install --name jenkins --namespace jenkins ./jenkins
```

Deployment、service、Podの状態を確認します。（起動までには数分かかります）
起動すれば以下のような結果が返ってきます。initとmasterコンテナが起動した状態です。

```
$ kubectl get pod -n jenkins
NAMESPACE     NAME                                                         READY   STATUS    RESTARTS   AGE
jenkins       jenkins-786dbcf7dc-mjqvb                                    2/2     Running   0          4h19m
```

#### 6. JenkinsのUIへのアクセス
以下のコマンドで、ingressで割り当てられたJenkinsのアドレス、ポートが確認できます。

```
$ kubectl get ing -n jenkins
```

Webブラウザからhttp://上記で確認したアドレス:ポート でアクセスできます。初回は認証はなくトップページが表示されます。