Jenkins XによるPreview環境構築
永井 佑樹
本記事は リクルートライフスタイル Advent Calendar 2019 3日目の記事です。
じゃらんnetを担当している永井です。
最近、案件ごとに独立して動作確認できる環境を作りたくて、Jenkins Xを検証していました。 Jenkins Xはまだ情報が少なく、一筋縄では行かなかったので本記事ではその構築過程をご紹介します。
Jenkins X
Jenkins Xは、Git/Docker/Kubernetesの利用を前提として構築・運用を可能な限り自動化してくれるCI/CDソリューションです。
jx create cluster
と叩けばGKEやEKSなどに標準的なKubernetesクラスタを作成してくれ、
jx install
と叩けば対象のKubernetesクラスタにJenkins XをインストールしてGitHubにwebhookまで作成してくれます。
Webコンソール画面は基本必要なくなり、jx
コマンド経由で各ジョブの状況も確認できます。
Jenkins Xでできることは全てJenkinsと各種プラグインを活用することで実現可能らしいのですが、 JenkinsやKubernetesまわりについて深く知らずとも幾つかのコマンドを実行していくことで適したCI/CD環境を構築できることが魅力です。
私も、普段はFlutterを推進したり、 Spring BootをGAEやCloud Runで動かしたりといった具合で、 素のJenkinsをKubernetesに最適化しろと言われると、正直知識が不足していて全然イメージが湧きません。
しかしJenkins Xであれば、これからご紹介していくように各技術への理解が曖昧でも(幾つかのissuesと向き合いながらではありますが)モダンなCI/CDを構築・運用できそうです。
目的
本記事では、特にJenkins Xのpreview環境に注目していきます。
異なる開発者たちが、複数の機能追加・改修を担当しており、それぞれを独立して動作確認したい、という状況はよくあることだと思います。 これまでは、動作確認したい案件ごとに都度環境構築するなどしていましたが、手間も費用も掛かって非効率です。 Kubernetesを活用すれば、リソースを効率的に使いながら、それぞれの環境を独立して動作させることができます。
Jenkins Xはその構築と運用の手助けをしてくれるということで、今回検証してみることにしました。
構築
構築にあたり、以下を前提に置いています。
- GitHub Enterpriseとの連携(GitHubとGitHub EnterpriseではJenkins Xの設定も一部異なります)
- GitHub Enterpriseとの通信は固定IPでなければならない
Jenkins Xは様々なKubernetes環境に対応していますが、 今回は最も対応が進んでいそうなGKEと、実際構築を予定しているEKSの2つを試しました。
Kubernetesクラスタ作成
GKEの場合
GKEで「GitHub Enterpriseとの通信は固定IPでなければならない」をクリアするためには、VPCとNATゲートウェイを用意した上で、jx create cluster gke
ではなく自前でクラスタを作成する必要があります。
jx create cluster gke
を実行すると、限定公開クラスタ(private cluster)が無効な状態でクラスタが作成されるため、
NATゲートウェイのIPアドレスでGitHub Enterpriseと通信してくれません。
EKSの場合
EKSの場合は、jx create cluster eks
を実行すると、実質eksctl create cluster
が実行され、
public subnets3つとprivate subnets3つ、そしてIAMロールとInternet/NATゲートウェイが作成されます。
GitHub Enterpriseとの通信には、ここで作成されたNATゲートウェイのIPアドレスを使います。
このとき、jx create cluster eks
ではなくeksctl create cluster --managed
を実行すると、最近使えるようになったEKSのManaged Node Groupsを利用できます。
ここで作成されたManaged Node Groupはpublic subnetsに作成されており、その通信はNATゲートウェイを通りません。
今回は、こうして作成されたManaged Node Groupを一度削除して、
改めてprivate subnetsを選択した新しいManaged Node Groupを作成することでNATゲートウェイを通るようにしました。
ここで、Nodes用のロールは自動作成されたIAMロール(eksctl-<cluster-name>-nodegro-NodeInstanceRole-<id>
)を選択します。
jx create cluster eks
を実行する場合は、そのままだとこの後説明する2通りのJenkins Xインストールのうちdeprecatedな方が実行されるので、
ここでは--skip-installation
オプションを付けて実行することをオススメします。
Jenkins Xインストール
Jenkins Xのインストール方法には現在2通り存在します。
コマンド | 説明 |
---|---|
jx install | 従来の方法。コマンドに各オプションを付与したり、標準入力経由で設定値を入力していく。2020/01/02にdeprecatedになる予定。 |
jx boot | Jenkins Xの設定もgitで管理する方法。今後はなるべくこちらを利用することが推奨されている。 |
これを見ると「jx boot
を使おう」となると思うのですが、jx install
だと問題ないけれどjx boot
では躓くissuesも幾つかあるようです。
一方で、jx install
で発見されたissuesは、jx boot
に切り替えることを提案されて終わっていたりもします。
jx boot
を試しながら、問題があればissuesやpull requestsを作成して地道に進んでいくことが建設的なのかもしれませんが、
差し当たりどちらを使っていくか悩ましいところです。
jx install
1
2
3
4
5
6
7
$ jx install --provider={gke|eks} \
--git-provider-url=https://<github enterprise domain> \
--no-default-environments \
--domain=<jenkins x domain> \
--exposecontroller-urltemplate='"{{.Service}}-{{.Namespace}}.{{.Domain}}"' \
--urltemplate='"{{.Service}}-{{.Namespace}}.{{.Domain}}"' \
--verbose
のように実行します。
今回欲しいのはpreview環境のみなので、--no-default-environments
オプションを付与することでデフォルトで作成されるstaging/production環境を作成しないようにします。
--exposecontroller-urltemplate
や--urltemplate
は、SSL証明書を*.<domain>
で作成できるように指定しています(デフォルトは'"{{.Service}}.{{.Namespace}}.{{.Domain}}"'
)。
コマンドを実行すると、以下のような選択を求められます。
1
2
3
? Select Jenkins installation type: [Use arrows to move, space to select, type to filter]
> Serverless Jenkins X Pipelines with Tekton
Static Jenkins Server and Jenkinsfiles
残念ながら、前者はGitHub以外に対応していないようです。 そのため、GitHub EnterpriseやBitBucketを利用している場合は後者を選択しましょう。
しばらくするとjxing-nginx-ingress-controller
というロードバランサーが立ち上がるので、
1
2
3
$ kubectl get services -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jxing-nginx-ingress-controller LoadBalancer XXX.XXX.XXX.XXX xxxxx.ap-northeast-1.elb.amazonaws.com 80:xxxxx/TCP,443:xxxxx/TCP 9m20s
上記EXTERNAL IPを*.<domain>
の向き先として設定する必要があります。
このあとは、コンソールに表示される指示に従っていけば、無事Jenkins adminユーザーのパスワードが表示され、http://jenkins-jx.<domain> でアクセスできるようになります。
HTTPSでアクセスしたい、という場合は工夫が必要です。
基本的には jx update ingress --namespaces=jx --verbose
と実行すれば良いのですが、GKE/AWSともにそのまま放っておくと成功しません。
こちらにあるように、
part0-configmap.yaml
を編集してkubectl apply
する必要があります。
jx boot
jx install
は工夫が必要ながらも何とかJenkins Xをインストールできました。jx boot
はどうでしょうか。
まず、現時点でHelmはv2.15.0未満である必要があります。
その上で、Jenkins Xの設定値を管理するレポジトリをenvironment-<kubernetes-cluster-name>-dev
の名前で用意します。
中身は、 jenkins-x/jenkins-x-boot-config の内容でpushします。
この各yamlファイルをローカルで修正し、jx boot
することでJenkins Xのインストール・更新ができます。
今回はpreview環境のみが必要なので、staging/production環境のための設定は削除します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
--- a/env/jxboot-resources/values.tmpl.yaml
+++ b/env/jxboot-resources/values.tmpl.yaml
@@ -65,17 +65,6 @@ gitops:
dockerRegistryOrg: ""
{{- end }}
-
- staging:
- repo: "{{ .Environments.staging.repository }}"
- owner: "{{ .Environments.staging.owner | default .Requirements.cluster.environmentGitOwner }}"
- server: ""
-
- production:
- repo: "{{ .Environments.production.repository }}"
- owner: "{{ .Environments.production.owner | default .Requirements.cluster.environmentGitOwner }}"
- server: ""
-
storage:
logs:
url: "{{ .Requirements.storage.logs.url }}"
jx-requirements.ymlの各設定値はこちらを参照して設定していきましょう。 GitHub Enterpriseの場合、webhookはlighthouseにする必要があります。
また、secretStorage
は現時点local
でなければならないようです。
GKE/AWSともに、
secretStorage
をvault
にすると失敗してしまいます。
修正が終わったら、environment-<kubernetes-cluster-name>-dev
の直下で jx boot --verbose
を実行します。
1
2
3
4
DEBUG: Applying Helm hook post-upgrade YAML via kubectl in file: /tmp/helm-template-workdir-719161591/jenkins-x/helmHooks/env/charts/jenkins-x-platform/charts/expose/templates/job.yaml
DEBUG: job.batch/expose created
DEBUG: Waiting for helm post-upgrade hook Job expose to complete before removing it
と表示されてからしばらくDEBUGログも出ない状態になりますが、気長に待てば無事インストール完了まで行けるはずです。
プロジェクト追加
新しくJenkins Xにジョブを追加したい場合は、jx create quickstart
やjx create spring
で始めることをオススメします。
既存のプロジェクトをjx import
することも可能ですが、Jenkinsfileの他に、こちらにあるようなファイル群をプロジェクト内に作成し、正しく記述する必要があります。
jx create quickstart
などでプロジェクトを作成すれば、あとはアプリケーションのソースコードを移植してDockerfileを修正することで基本的には動くようになるはずです。
ただし、EKSの場合はまたもう一工夫必要です。
jx create quickstart
などでプロジェクトを作成すると、自動的にmasterブランチのジョブが走り始めます。
すると以下のようなエラーでジョブが失敗します。
1
2
3
[ERROR] Error parsing the serverURL: https://index.docker.io/v1/,
error: docker-credential-ecr-login can only be used with Amazon Elastic Container Registry.
credentials not found in native keychain
このエラーは、こちらにあるような方法でsecretを修正すれば解消します。
jx boot
でJenkins Xをインストールした場合は、environment-<kubernetes-cluster-name>-dev
にもpull requestが作成されているはずです。
このpull requestをマージして、再度jx boot
を実行してから次のステップへ進みましょう。
Preview環境
さて、ここまででmasterブランチのジョブは通るようになり、いよいよpull requestsに対してpreview環境を立ち上げます。
jx create quickstart
などで作成したプロジェクトのJenkinsfileには、既にjx preview
コマンドが記述されているはずです。
この箇所を、以下のように修正しましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -17,6 +17,7 @@ pipeline {
PREVIEW_VERSION = "0.0.0-SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER"
PREVIEW_NAMESPACE = "$APP_NAME-$BRANCH_NAME".toLowerCase()
HELM_RELEASE = "$PREVIEW_NAMESPACE".toLowerCase()
}
steps {
container('nodejs') {
@@ -27,7 +28,9 @@ pipeline {
sh "jx step post build --image $DOCKER_REGISTRY/$ORG/$APP_NAME:$PREVIEW_VERSION"
dir('./charts/preview') {
sh "make preview"
- sh "jx preview --app $APP_NAME --dir ../.."
+ sh "jx preview --app $APP_NAME --dir ../.. --urltemplate='\"{{.Service}}-{{.Namespace}}.{{.Domain}}\"'"
}
}
}
--urltemplate
を追加しているのは、jx install
の時と同じ理由です。
また、preview環境に対してHTTPSで通信できるように、以下を修正します。
1
2
3
4
5
6
7
8
9
10
11
--- a/charts/preview/values.yaml
+++ b/charts/preview/values.yaml
@@ -6,7 +6,7 @@ expose:
config:
exposer: Ingress
http: true
- tlsacme: false
+ tlsacme: true
cleanup:
Args:
こうしてpull requestを作成すると、webhook経由でジョブが走り始めます。
例えば、 jx create quickstart
で node-http
を選択したとします。
Preview用のブランチで、以下のように修正してみます。
1
2
3
4
5
6
7
8
9
10
11
--- a/index.html
+++ b/index.html
@@ -12,7 +12,7 @@
<body>
<div class="cover">
<div class="feature">
- <h1>Hello Node Preview</h1>
+ <h1>Hello Node</h1>
<div class="brand">
Jenkins <strong>X</strong>
</div>
このブランチのpull requestを作成して、remoteにpushしてみます。
すると、 node-xxx
という名前のジョブ実行用podが立ち上がり、
1
2
3
4
5
6
7
8
9
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
exposecontroller-59tm2 0/1 Completed 0 57m
jenkins-845998c594-8zbg5 1/1 Running 0 61m
jenkins-x-chartmuseum-d87cbb789-dzl4h 1/1 Running 0 61m
jenkins-x-controllerrole-8499688fb5-2f84d 1/1 Running 0 61m
jenkins-x-heapster-ff6df6848-mmb95 2/2 Running 0 61m
jenkins-x-nexus-6bc788447f-6xxgn 1/1 Running 0 61m
nodejs-b1rll 2/2 Running 0 2m7s
完了次第、 https://<repo-name>-jx-<org-name>-<rep-name>-pr-<pr-number>.<domain>/
というようなURLが生成され、
pull requestに対してURL付きでコメントがpushされます。
無事preview環境が出来上がりました! 🎉
クローズしたpull requestsに対するpreviewsは、定期的に削除してくれるようです。
1
2
3
4
5
$ kubectl get cronjobs
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
jenkins-x-gcactivities 0/30 */3 * * * False 0 <none> 107m
jenkins-x-gcpods 0/30 */3 * * * False 0 <none> 107m
jenkins-x-gcpreviews 0 */3 * * * False 0 <none> 107m
まとめ
いかがでしたでしょうか。
正直まだまだ躓き所が多い印象ではありますが、調べれば何とか解決していけますし、学習・コミット機会と捉えて楽しむこともできそうです。
これを機に、一緒にissuesと向き合う仲間が増えてくれると嬉しいです。