Kubernetes環境に特化したCI/CDツール「Jenkins X」を試してみる

広く使われている継続的インテグレーション(CI)/継続的デリバリ(CD)ツールの1つに「Jenkins」がある。このJenkinsの開発チームが、Kubernetesに特化したCI/CDツール「Jenkins X」を発表した。今回はこのJenkins Xの特徴やインストール、基本的な使い方を紹介する。

昨今ではソフトウェア開発を迅速に進めるために「継続的インテグレーション(CI)」と呼ばれる手法が広く採用されている。CIはバージョン管理システムなどと組み合わせて使われるのが一般的で、たとえばバージョン管理システムへのコミットをトリガーとして自動的にビルドやテスト、パッケージ作成を実行する仕組みなどを構築できる。また、最近では「継続的デリバリ(CD)」という手法も使われる。CDはCIと似ているが、運用環境へのデプロイまでも自動で行うという仕組みだ。

CIツールとして著名なものの1つに、以前紹介した「Jenkins」がある。Jenkinsは汎用性が高く、ビルドやテストなどの自動化処理を柔軟に定義できるのが特徴だ。また、機能を拡張するプラグインも多数公開されており、さまざまな環境、さまざまなソフトウェア開発で利用できる。一方で、昨今普及が進んでいるKubernetesベースのクラウドインフラストラクチャと組み合わせて利用しようとすると設定が複雑になるほか、クラウドインフラストラクチャ内へのインストールも手間がかかるなど、使いにくい点があることが指摘されていた。

今回紹介する「Jenkins X」は、こうした問題点を解決すべく立ち上がったJenkinsのサブプロジェクトの1つだ(図1)。

図1 Jenkins XのWebサイト
図1 Jenkins XのWebサイト

Jenkins XはKubernetesクラスタ上にデプロイして運用するアプリケーションの開発に特化しており、Jenkins XもKubernetes上で動作するソフトウェアとして提供される。Jenkins XのコンセプトはJenkins Enhancement Proposals(JEP-)400としてまとめられているが、「クラウドネイティブなアプリケーション開発のためのKubernetesネイティブなCI/CDプラットフォーム」と称されている。また、Jenkins XはJenkinsをベースとするものの、現時点ではJenkinsとは全く使用感が異なるCI/CDツールとなっている。

Jenkins Xの特徴

Jenkins Xの特徴を挙げると、以下のようになる。

  • Kubernetesクラスタ上で実行されるアプリケーションの開発に特化
  • Kubernetesクラスタ上でのみ動作する
  • CIだけでなく、Kubernetesクラスタへのデプロイを行うCD機能も備える
  • GitHubなどのGitベースのソフトウェア開発プラットフォームと連携させて使用することが前提
  • デプロイなどの作業を、Gitを使って管理する「GitOps」をサポート
  • GUIは最低限のものしか提供されず、操作はコマンドラインもしくは連携させている開発プラットフォーム経由で行う

Jenkins XがJenkinsともっとも異なる点として、Jenkins XはKubernetesクラスタ上で実行されるアプリケーションの開発に特化しており、Jenkins X自体もKubernetesクラスタ上でしか動作しないことがある。また、Jenkins XはビルドしたアプリケーションのKubernetesクラスタへのデプロイ機能も標準搭載している。これによって、リポジトリへのコミット操作をトリガーとしてビルド、テスト、デプロイまでを一括で実行できる。

Jenkins XはGitHubなどのGitベースのソフトウェア開発プラットフォームと連携させることを前提としている。これはプルリクエストやイシュー(issue)を活用した開発スタイルを前提としているためだ。特にJenkins Xでは「GitOps」と呼ばれる開発・運用スタイルが推奨されている。GitOpsはKubernetesベースのソフトウェア開発プラットフォームを提供するWeaveworksが提唱したソフトウェア開発・運用スタイルで、Gitリポジトリ上でソフトウェアのソースコードや各種リソースだけでなくビルドのために必要な設定やデプロイに必要な設定までも一括管理し、これら設定の変更をトリガーにして自動的にビルドやデプロイを実行するというアイデアを核としている。

人間がコマンドライン、もしくはGUIなどでビルドやテスト、デプロイを実行するという従来型のサービス運用においては、いつ誰がどのような条件でそれらの作業を実行したのか、という記録が残りにくいという問題があった。CIツールでは、あらかじめビルドやテストの手順を設定ファイルに記述しておき、バージョン管理システムへのコミットをトリガーにして自動でビルドやテストを実行させることでこれらの再現性を担保できるようになっているが、GitOpsではそれを運用作業にまで適用するのが特徴だ。Jenkins Xでは、パッケージ管理ツールの「Helm」やKubernetesのAPI経由でクラスタを操作し、設定ファイルに従って自動でデプロイ作業を実行することでこれを実現している。

このように運用においても人間による手作業を完全に排除することで、ソフトウェア実行インフラストラクチャへの変更履歴についても確実に管理できるようになっている。

Jenkins X導入の注意点

Jenkins Xは最新のソフトウェア開発トレンドを取り込んだ意欲的なプロジェクトではあるが、プロジェクトが正式に発表されたのは2018年3月で、開発期間はまだ2年未満とまだ比較的若いプロジェクトである。開発は活発に行われているものの、ドキュメントや運用ノウハウなどに関する情報はまだ十分とは言い難い。さらに、現状ではGoogleが提供するKubernetesクラスタ「Google Kubernetes Engine」(GKE)以外でのKubernetes環境での利用は「未検証」というステータスとなっている。筆者の検証ではGKE以外での動作も確認できているものの、かなりの試行錯誤が必要で、動いているように見えるが何が適切な挙動なのか十分に判別できないこともあった。

さらに、運用にはJenkinsやJenkins Xの知識に加えて、KubernetesやHelmなどの知識も必要となる。そのため、現時点では運用環境での活用はかなりハードルが高いと思われる。現段階でJenkins Xの導入を検討する際には、こういった問題点を十分に考慮する必要があるだろう。

Jenkins Xを活用したCI/CD環境の構築

さて、それでは実際にKubernetesクラスタ上にJenkins Xを導入し、ビルドやデプロイなどを実行させるまでの手順を紹介していこう。

Kubernetesクラスタの必要用件

使用したKubernetesクラスタは以前紹介したkubeadmを使って独自に構築したもので、採用しているKubernetesのバージョンは1.15.5だ。現在のKubernetesの最新版は9月にリリースされたバージョン1.16だが、API関連でいくつかの大きな仕様変更があったためか、Kubernetes 1.16で構築したクラスタ上ではJenkins Xをインストールできなかった。そのため、今回はKubernetes 1.15系のクラスタを使用している。

独自に構築したKubernetes環境へのJenkins Xのインストールについては、公式ドキュメントのInstall on Kubernetesページで言及されているのだが、このページは現在「Deprecated」(廃止予定)というステータスで、ここに記載されている方法は推奨されていないようだ。ただ、このページに記載されている次の要件については大きくは変わっていないと思われる。

  • Kubernetes 1.8以降
  • KubernetesクラスタでのRBAC(Role Based Access Controll)が有効化されている
  • KubernetesクラスタでDefault Storage Classが設定されている
  • マスターノードに加えて、少なくとも4仮想CPUを備えたワーカーノード

kubeadmを使ってクラスタを構築した場合、基本的にRBACが有効となるようインストールされるため、これについては特に設定は不要だ。一方でDefault Storage Classについてはクラスタの実行環境に応じた設定が必要になる(こちらについては後述する)。

また、これ以外にクラスタ内でのコンテナイメージの配信に使用するDocker Registryも必要となる。公式ドキュメントでは自動的にクラスタ内にDocker Registryサーバーが立ち上げられるとされているが、このDocker Registryを使用するための設定が適切に行われないというトラブルに遭遇したため、今回は独自にHTTPSで接続できるDocker Registryサーバーを用意した。Docker Registryサーバーの構築方法については過去の記事(「継続的デリバリ」(CD)を実現できるコンテナクラスタ管理ツール「Spinnaker」)で紹介しているので、こちらを確認してほしい。

なお、独自にDocker Registryサーバーを立ち上げる場合、本来はユーザー名/パスワードなどを使った認証を行うべきだが、本記事執筆時に検証を行った際、Jenkins Xが適切に認証情報をハンドリングできない場合があるという問題が発生したため、今回は止むを得ずDocker Registryサーバー側の設定を変更し(認証設定をコメントアウトし)、認証なしでアクセスできるようにして使用した。この場合、ファイアウォールなどでクラスタを構成するマシンのIPアドレス以外からのアクセスをブロックするといった対応が必要となる。

また、先に述べたとおり、Jenkins XではGitベースのソフトウェア開発プラットフォームとの連携が必須となる。現時点でJenkins Xが対応しているプラットフォームは次の通りだ。

  • GitHub
  • GitHub Enterprise
  • Bitbucket
  • Bitbucket Server
  • Gitlab
  • Gitea

GitHubおよびBitbucketはクラウド型のサービスで、GitHub EnterpriseおよびBitbucket Server、Gitlab、Giteaは利用者が自身の管理するサーバーにインストールして利用するソフトウェアだ。ちなみにGitHub EnterpriseおよびBitbucket Serverは商用ソフトウェア、GitlabとGiteaはオープンソースソフトウェアだ(Gitlabについては商用版やホスティングサービスも提供されている)。ただし、Giteaについては現時点では一部の機能が利用できないという制限があるとされている。デフォルト設定ではGitHubを利用するようになっており、それ以外のプラットフォームでは検証が十分でないようなので、今回はGitHubを連携先プラットフォームとして使用している。

これらプロジェクト管理プラットフォームからは、使用するKubernetesクラスタにアクセスできる(Webフックを送信できる)ようになっている必要がある。一般的には、クラスタのマスターノードにグローバルIPアドレスを割り当てて、インターネット側からアクセスできるようファイアウォール等の設定を行っておけば良い。以下ではこのクラスタにアクセスできるIPアドレスを「マスターノードのIPアドレス」と表現している。

事前準備1:GitHubのアクセストークンの取得

Jenkins Xをインストールする前には、KubernetesクラスタおよびDocker Registryサーバーの用意に加えていくつかの事前準備が必要となる。まず必要となるのが、GitHubのアクセストークンだ。

GitHubのリポジトリに外部アプリケーションからアクセスするには、アクセストークンと呼ばれる文字列が必要となる。これは設定画面(Settings)の「Developer settings」内にあるPersonal access tokensページで作成できる(図2)。

図2 GitHubの「Personal access tokens」ページ
図2 GitHubの「Personal access tokens」ページ

ここで「Generate new token」をクリックすると、トークン管理のためのNote(注釈)と、このトークンを利用するアプリケーションに与える権限(scopes)を指定できる「New personal access token」画面が表示される(図3)。

図3 「New personal access token」ページ
図3 「New personal access token」ページ

Jenkins Xはリポジトリの作成やコミットおよびリリースの作成、プルリクエスト管理など、GitHubのさまざまな機能を利用するが、具体的にどの権限を使用するかの説明はない。そのため、あまり推奨できないが今回は全権限を与えるよう設定した。最後に画面下の「Generate token」をクリックするとアクセストークンが作成されてトークン文字列が表示される。このトークン文字列は作成直後のタイミングでしか表示されず、再表示はできない仕組みのため、必要に応じて適当なテキストファイルなどにコピーしておこう。なお、このトークンを利用することでリポジトリへのすべてのアクセスが可能になるため、管理は厳重に行ってほしい。

事前準備2:gitコマンドの準備

Jenkins Xは後述する「jx」というフロントエンドコマンドを使って各種操作を行うが、このコマンドはいくつかの処理で内部的にgitコマンドを実行する。そのため、別途gitコマンドをインストールしておく必要がある。また、ユーザーのグローバル設定で、gitで使用するユーザー名とメールアドレスを登録しておこう。これはホームディレクトリ内の「.gitconfig」ファイルを編集するか、もしくは次のように「git config」コマンドで行える。

$ git config --global user.name <ユーザー名>
$ git config --global user.email <メールアドレス>

なお、インストールされているgitコマンドのバージョンが古いといくつかの処理が失敗するようだ。UbuntuやDebianの現行バージョンでは比較的新しいバージョンのGitが提供されているため問題になることはないと思われるが、RHEL 7やCentOS 7において標準で提供されているGitはやや古めのため、問題が発生する。これらの環境ではSoftware Collection(SCL)という公式外部リポジトリでより新しいバージョンのものが提供されているので、こちらを利用しよう。たとえばCentOS 7では、次のようにしてバージョン2.18系のパッケージをインストールできる。

# yum install centos-release-scl
# yum install rh-git218

SCLで提供されているパッケージを有効にするには、「scl enable」コマンドを使ってシェルを起動すれば良い。

$ scl enable  rh-git218 bash
$ git --version
git version 2.18.1

事前準備3:jxコマンドのインストール

Jenkins Xでは、「jx」というコマンドでクラスタへのJenkins Xのインストールや各種管理作業を実行するようになっている。このjxコマンドはGitHubのリリースページで公開されている。多い時には1日に数回の頻度で頻繁にリリースされているが、「Latest release」となっているものが最新版なのでそちらをダウンロードしよう。Linux(AMD64)向けは「jx-linux-amd64.tar.gz」だ。そのほかWindowsやmacOS(darwin)、ARM版Linux向けのバイナリも用意されている。

ダウンロードしたtar.gzファイルにはREADMEファイルやchangelogと共に「jx」というバイナリファイルが含まれているので、tarコマンドで展開後にパスの通ったディレクトリにjxコマンドをコピーもしくは移動しておく。

$ tar xzf jx-linux-amd64.tar.gz

事前準備4:/usr/local/binの権限確認

インストール時、jxコマンドは必要に応じて/usr/local/binディレクトリに必要なツールをダウンロードする。そのため、後述する「jx boot」コマンドはこのディレクトリへの書き込み権限を持つユーザーで実行する必要がある。通常/usr/local/binディレクトリへの書き込みにはroot権限が必要なので、「jx boot」コマンドを実行するユーザーが/usr/local/binディレクトリへの書き込みを行えるようパーミッションを変更しておこう。たとえばこのディレクトリの所有グループを「jx boot」コマンドを実行するユーザーの所有グループに変更し、かつグループに対し書き込み権限を与えておけば良い。

# chgrp <グループ名> /usr/local/bin
# chmod 775 /usr/local/bin

インストール作業1:Jenkins Xで使用するネームスペースの用意

続いて、Jenkins Xのクラスタへのインストール手順を説明する。なお、何らかの理由でインストール作業をやり直したい場合、後述する「jx uninstall」コマンドを実行してからこの「インストール作業1」から手順をやり直す必要がある。

Jenkins Xでは、Kubernetes上に独自のネームスペースを用意してそのネームスペース上でJenkins Xのコンポーネントを実行させることを推奨しており、デフォルトでは「jx」というネームスペースが使用される。このネームスペースはインストール時に自動的に作成されるが、次で説明するStorage Classの作成時にもこのネームスペースを使用するため、次のように事前に作成しておく。

$ kubectl create ns jx

インストール作業2:KubernetesのStorage Classの作成

Kubernetesでは、永続的ストレージをPodに動的に割り当てるための「Storage Class」という仕組みが用意されている。詳しくはKubernetesの公式ドキュメントを参照してほしいが、Storage ClassはネットワークストレージをPodの要求に応じて動的に確保して割り当てるための設定を記述したリソースで、ネットワークストレージごとに提供されている「Provisioner」を指定することでさまざまなネットワークストレージに対応できるようになっている。

Kubernetesクラスタを提供するクラウド型サービスでは標準でStorage Classが提供されているものもあるが、kubeadmで構築したクラスタでは自前でStorage Classの設定を行う必要がある。さらに、Kubernetesが標準でサポートしているネットワークストレージはAmazon Web Services(AWS)やMicrosoft Azure、Google Computing Engine(GCE)といった大手クラウドが提供するサービスや、vSphere、OpenStack Cinderといった大規模なネットワークストレージシステムに限られている。そのため、これらが利用できない環境においては別途Provisionerについての準備も必要となる。

こういった独自クラスタでStorage Classを設定するための選択肢はいくつかあるが、その1つに「kubernetes-incubator」というコミュニティが公開している「nfs-client」というNFS向けのProvisionerがある。リポジトリのdeployディレクトリ以下に設定に必要なマニフェストファイルも公開されており、こちらを利用することで比較的容易にStorage Classを準備できる。具体的な手順は次のとおりだ。

まず、この「external-storage」リポジトリをクローンするか、もしくはGitHubのdeployディレクトリ内にある「class.yaml」および「deployment.yaml」、「rbac.yaml」の3つのマニフェストファイルをダウンロードする。

$ wget https://github.com/kubernetes-incubator/external-storage/raw/master/nfs-client/deploy/class.yaml
$ wget https://github.com/kubernetes-incubator/external-storage/raw/master/nfs-client/deploy/deployment.yaml
$ wget https://github.com/kubernetes-incubator/external-storage/raw/master/nfs-client/deploy/rbac.yaml

続いて、rbac.yamlとdeployment.yamlを環境に応じて変更する。まずrbac.yamlだが、「kind: ClusterRoleBinding」および「kind: RoleBinding」以下の「namespace:」部分をJenkins Xで使用するネームスペース(今回は「jx」)に変更する。

  
  
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default  ←この「default」を使用するものに変更する
  
  
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default  ←この「default」を使用するものに変更する
  
  

続いてdeployment.yamlの「containers:」以下の「env:」と「volumes:」以下を次のように変更する。



  containers:
    - name: nfs-client-provisioner
      image: quay.io/external_storage/nfs-client-provisioner:latest
      volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentvolumes
      env:
        - name: PROVISIONER_NAME
          value: fuseim.pri/ifs
        - name: NFS_SERVER
          value: 10.10.10.60  ←使用するNFSサーバーのIPアドレスに変更する
        - name: NFS_PATH
          value: /ifs/kubernetes  ←マウントするディレクトリに変更する
  volumes:
    - name: nfs-client-root
      nfs:
        server: 10.10.10.60  ←使用するNFSサーバーのIPアドレスに変更する
        path: /ifs/kubernetes  ←マウントするディレクトリに変更する

NFSサーバー側では、ここで指定したディレクトリをクラスタ内のノードから書き込み可能でマウントできるよう設定を行っておこう。NFSサーバーの設定は本題から外れるので割愛するが、たとえばRHEL 7/CentOS 7などでは公式ドキュメントで手順が解説されている。

このとき注意したいのがファイル権限の設定だ。Jenkins Xはこれらストレージに対しroot権限でのアクセスを要求するようで、NFSサーバーの/etc/exportsファイルで「no_root_squash」オプションを指定しておかないとPodの起動に失敗する場合がある。たとえば「/var/nfs」ディレクトリを使用する場合、次のようにクラスタ内の各IPアドレスに対して「no_root_squash」オプションが有効になるよう指定しておこう。

/var/nfs <コンテナが使用するIPアドレス範囲>(rw,no_root_squash)

NFSサーバーの設定が完了したら、次のようにマニフェストファイルからStorage ClassおよびRBAC関連の設定、そしてProvisioner本体を作成する。このとき、「-n <ネームスペース名>」オプションでJenkins X用に作成したネームスペースを指定しておく。以下では「jx」ネームスペースを使用しているが、それ以外の場合は適宜適切なものに置き換えてほしい。

$ kubectl -n jx apply -f class.yaml
storageclass.storage.k8s.io/managed-nfs-storage created

$ kubectl -n jx apply -f rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

$ kubectl -n jx apply -f deploy.yaml
serviceaccount/nfs-client-provisioner unchanged
deployment.apps/nfs-client-provisioner created

これで問題がなければ、次のように「nfs-client-provisioner」Podが作成される。

$ kubectl -n jx get po
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-78b7d65564-8kfg6   1/1     Running   0          5s

なお、設定が正しく行えているかどうかは次のようなマニフェスト(GitHubのdeployディレクトリで公開されているものと同一)を使ってPodを作成することで確認できる。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi
---
kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: gcr.io/google_containers/busybox:1.24
    command:
      - "/bin/sh"
    args:
      - "-c"
      - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim

適切に設定が完了していれば、「test-pod」というPodが作成されてステータスが「Completed」となるとともに、NFSサーバーの公開ディレクトリ内に「jx-test-claim-pvc-<ID文字列>」というディレクトリが作成され、そこに「SUCCESS」という名前のファイルが作成されているはずだ。ちなみにこのディレクトリは、Podを削除すると自動的に削除される。

最後に、次のように実行してここで作成したStorage Classをデフォルトで使用するよう設定しておく。

$ kubectl -n jx patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

作成されたStorage Class(sc)をkubectl getコマンドで確認し、次のように「(default)」と表示されていれば設定完了だ。

$ kubectl -n jx get sc
NAME                            PROVISIONER      AGE
managed-nfs-storage (default)   fuseim.pri/ifs   107s

インストール作業3:インストール設定ファイルが含まれたリポジトリのクローン

Jenkins Xでは、インストール時に必要な設定ファイルがhttps://github.com/jenkins-x/jenkins-x-boot-config.gitというリポジトリで公開されている。インストール作業を実行する前にこのリポジトリをクローンしておく。

$ git clone https://github.com/jenkins-x/jenkins-x-boot-config.git
$ cd jenkins-x-boot-config/

インストール作業4:「jx-requirements.yml」ファイルの編集

このリポジトリ内にある「jx-requirements.yml」ファイルがインストール設定を記述するファイルだ。デフォルトでは最低限の設定項目が記述されているが、いくつか環境に応じた変更が必要だ。設定項目の概要は公式ドキュメントのJenkins X Bootページに、設定項目のリファレンスは公式ドキュメントのRequirementsConfig以下にまとめられているが、ここで設定すべき主要な項目は次のとおりだ。

  • 使用するクラスタ環境に関する設定
  • 連携させるプロジェクト管理プラットフォーム
  • gitopsによる管理を行うかどうかの設定
  • クラスタ内で稼働する各サービスの公開設定(ingress設定)

まず使用するクラスタ環境に関する設定だが、これはjx-requirements.ymlファイル内の「cluster:」項目で行う。指定が必要なのは以下の部分だ。

  
  
cluster:
  clusterName: jx  ←クラスタ名。任意に指定可能だがネームスペースと同じものを指定しておくのが無難
  environmentGitOwner: <ユーザー名>  ←Jenkins Xの設定を管理するリポジトリの所有者を指定
  project: test  ←GKEを利用する場合のプロジェクト名を指定。GKE以外のクラスタを使用する場合でも適当な文字列を指定しておかないとエラーとなる場合がある
  provider: kubernetes  ←独自に構築したクラスタを使用する場合は「kubernetes」と指定する
  zone: ""
  environmentGitPublic: true  ←Jenkins Xの設定を管理するリポジトリを公開リポジトリとして作成する場合「true」を指定
  gitPublic: true  ←Jenkins Xが作成するリポジトリを公開リポジトリにする場合「true」を指定
  registry: <Docker Registryサーバーのホスト名>:<ポート番号>  ←使用するDocker Registryサーバーを指定。このサーバーにはHTTPSでアクセスできる必要がある
  namespace: jx  ←使用するKubernetesクラスタのネームスペース
  
  

なお、デフォルトではJenkins XとGitHubを連携させる設定となっており、GitHub以外のプラットフォームを利用する場合は「cluster:」以下に「gitKind:」および「gitName:」、「gitServer:」といった項目を指定する必要がある。また、デフォルトのWebフックハンドラである「prow」はGitHub専用となっているため、あわせて「webhook:」の値を「prow」から「lighthouse」に変更しておく必要もある。詳しくは公式ドキュメントのJenkins X Boot内にまとめられているので、こちらを参照してほしい。ちなみにGiteaを利用する場合の設定についてはこのページ内には記載されていないが、次のように記述すれば良い。

  gitKind: gitea
  gitName: <名前として使用する適当な文字列>
  gitServer: <サーバーのURL>

この場合も「webhook:」は「lighthouse」に設定しておく必要がある。

webhook: lighthouse

「gitops:」部分では、Jenkins X自体の管理を、GitOpsを使って行うかどうかを指定する。GitHubと連携させる場合、「true」を指定しないと適切なインストールが行えない場合があるようだ。

  
  
gitops: true
  
  

「ingress:」部分では、次のように外部からJenkins Xの各サービスにアクセスする際の窓口となる「ingress」の設定を行う。

  
  
ingress:
  domain: "<クラスタのマスターノードのIPアドレス>.nip.io"  ←クラスタに外部からアクセスする際のドメイン名を指定する
  namespaceSubDomain: .jx.  ←クラスタに外部からアクセスする際のサブドメイン名に付与される文字列を指定する
  externalDNS: false
  tls:
    email: ""
    enabled: false
    production: false
  
  

ここで「domain:」に指定している「.nip.io」というのは、IPアドレスを含んだドメイン名をIPアドレスに解決するサービスを提供しているドメインだ。「<IPアドレス>.nip.io」というドメインは、そのIPアドレスに解決される。

クラスタのマスターノードのIPアドレスにドメイン名を割り当てている場合、もちろんそれを指定しても良い。ただしその場合、「<任意の文字列>.<domain:で指定したドメイン>」といったサブドメインがマスターノードのIPアドレスに解決できるよう設定されている必要がある。nip.ioの場合は、「<任意の文字列>.<IPアドレス>.nip.io」というドメインがそのIPアドレスに自動的に解決されるため、特にこれ以外の設定は必要ない。

これ以外の設定項目については、検証時点ではデフォルトのままで問題なかった。ただ、今後アップデートによる仕様変更などが行われる可能性が十分にあるため、念のため公式ドキュメントのJenkins X Bootページには目を通しておくことをおすすめする。

インストール作業5:「jenkins-x.yml」ファイルの編集

独自に構築したKubernetesクラスタにJenkins Xをインストールする場合、記事執筆時点のバージョンでは各種サービスを公開するIPアドレスを自動取得できずインストール処理が途中で停止してしまう。そのため、事前にインストール時に実行するコマンドが記述されている「jenkins-x.yml」ファイルを変更しておく。このファイルは、ProjectConfigというフォーマットになっているが、とりあえず次のように「name: create-install-values」以下の部分を変更すれば良い。

  - name: create-install-values
    command: jx
    args:
    - step
   - create
    - install
    - values
    - -b
    - --external-ip  ←この行を追加
    - <マスターノードのIPアドレス>  ←この行を追加
    dir: /workspace/source/env
  - name: install-external-dns

インストール作業6:「jx boot」コマンドの実行

以上の作業が完了したら、クローンしたリポジトリ内(jx-requirements.ymlファイルなどが含まれているディレクトリ内)で「jx boot」コマンドを実行する。この際にいくつか対話的に入力が求められるので、次の実行例のように適切な値を入力していく。

$ jx boot
Booting Jenkins X
Cloning the Jenkins X versions repo https://github.com/jenkins-x/jenkins-x-versions.git with ref refs/heads/master to /home/hylom/.jx/jenkins-x-versions

  
  

STEP: verify-preinstall command: /bin/sh -c jx step verify preinstall --provider-values-dir="kubeProviders" in dir: /home/hylom/jx/jenkins-x-boot-config

↓GKE環境以外では検証されていないという旨の注意が表示される
jx boot has only been validated on GKE, we'd love feedback and contributions for other Kubernetes providers
? Continue execution anyway? Yes  ←「Y」を入力する

Locking version stream https://github.com/jenkins-x/jenkins-x-versions.git to release v1.0.164. Jenkins X will use this release rather than master to resolve all versions from now on.
↓WebフックをHTTPで受信する設定になっている点についての注意が表示される
WARNING: TLS is not enabled so your webhooks will be called using HTTP. This means your webhook secret will be sent to your cluster in the clear. See https://jenkins-x.io/architecture/tls for more information
? Do you wish to continue? Yes  ←「Y」を入力する

  
  

STEP: create-helm-values command: /bin/sh -c jx step create values --name parameters in dir: /home/hylom/jx/jenkins-x-boot-config/env

defaulting to secret storage scheme local found from requirements file at /home/hylom/jx/jenkins-x-boot-config/jx-requirements.yml
defaulting to secret base path to the cluster name jx found from requirements file at /home/hylom/jx/jenkins-x-boot-config/jx-requirements.yml
generated schema file /home/hylom/jx/jenkins-x-boot-config/env/parameters.schema.json from template /home/hylom/jx/jenkins-x-boot-config/env/parameters.tmpl.schema.json

? Jenkins X Admin Username <ユーザー名>  ←Jenkins Xの各種機能にアクセスする際に使用するユーザー名を入力する
? Jenkins X Admin Password [? for help] ***********  ←パスワードを入力する
? Pipeline bot Git username <ユーザー名> botがGitHubにアクセスする際に使用するユーザー名を入力する
? Pipeline bot Git email address <メールアドレス> ←botがGitHubにアクセスする際に使用するメールアドレスを入力する
? Pipeline bot Git token [? for help] ******  ←準備しておいたGitHubのアクセストークンを入力する
↓Jenkins XへのWebhook送信時に使用するトークンが表示される
Generated token *****************************, to use it press enter.
This is the only time you will be shown it so remember to save it
? HMAC token, used to validate incoming webhooks. Press enter to use the generated token [? for help]   ←表示されたトークンを使用するのでそのままEnterを入力する
↓使用するDocker Registryサーバーを登録する
? Do you want to configure an external Docker Registry? Yes  ←「Y」を入力する
? Docker Registry Url https://<ホスト名>:<ポート番号>/  ←Docker RegistryサーバーのURLを入力する
? Docker Registry username *b<ユーザー名>  ←Docker Registryへのアクセスに使用するユーザー名を入力する。認証不要に設定している場合でも適当なものを入力しておく必要がある
? Docker Registry password [? for help] ***********  ←パスワードを入力する

  
  


STEP: verify-installation command: /bin/sh -c jx step verify install --pod-wait-time 30m in dir: /home/hylom/jx/jenkins-x-boot-config/env

verifying the Jenkins X installation in namespace jx
verifying pods
Checking pod statuses
POD                                          STATUS
crier-75685cd47d-ccdg4                       Pending
deck-67bc895974-ghwsl                        Pending
  
  (Jenkins Xの各コンポーネントが稼働するPodが起動するまで待機する)
  
Verifying the git Secrets
Verifying git Secret jx-pipeline-git-github-github
Verifying username hylom at git server github at https://github.com
Found 1 organisations in git server https://github.com: hylom-test
Validated pipeline user hylom on git server https://github.com
Git tokens seem to be setup correctly
Installation is currently looking: GOOD
Using namespace 'jx' from context named 'kubernetes-admin@kubernetes' on server 'https://<IPアドレス>:6443'.

なお、環境によっては、Jenkins Xを構成するコンポーネント(Pod)がすべて立ち上がるまで時間がかかる場合がある。エラーによって特定のPodが立ち上がらないという場合もあるので、適宜kubectlコマンドでPodの稼働状況を確認すると良いだろう。もし何らかのトラブルでインストール作業が失敗・中断された場合、次のように実行することで途中のステップから再開することができる。

$ jx boot -s <ステップ名>

ここで指定する「ステップ名」は、作業中に「STEP: <ステップ名> command: ...」のように表示されているものだ。

さて、インストール作業が完了すると、jx-requirements.ymlファイルで指定したGitHubのユーザーアカウントに対し、次の3つのリポジトリが自動的に作成される(図4)。

  • environment-jx-dev
  • environment-jx-staging
  • environment-jx-production
図4 GitHub上にリポジトリが作成される
図4 GitHub上にリポジトリが作成される

Jenkins Xでは必要に応じてKubernetesクラスタ上に自動でデプロイを行うようになっており、その際に使用する各種設定とネームスペースの組み合わせを「environment(環境)」と呼ぶ。Jenkins Xのデフォルトでは開発向けの「dev」とプレビュー向けの「staging」、運用向けの「production」という3つの環境が作成され、これらのリポジトリにそれぞれの環境の設定などが記録される。デフォルト設定ではそれぞれの環境はKubernetes上では「jx-dev」および「jx-stagin」、「jx-production」というネームスペースを使用するようになっている。

インストール作業7:ingressへのIPアドレス割り当て

今回検証した環境では、インストールの完了後も「jx boot」コマンドによって作られたロードバランサ(「jxing-nginx-ingress-controller」サービス)に外部IPアドレスが割り当てられず、外部からJenkins Xの各コンポーネントにアクセスできない状況になっている。kubectlコマンドで確認すると、次のようにこのサービスの「EXTERNAL-IP」が「<pending>」になっているはずだ。

$ kubectl -n kube-system get svc
NAME                                  TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
jxing-nginx-ingress-controller        LoadBalancer   10.108.202.90   <pending>     80:32685/TCP,443:30008/TCP   12m
jxing-nginx-ingress-default-backend   ClusterIP      10.109.161.61   <none>        80/TCP                       12m
kube-dns                              ClusterIP      10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP       24h

そのため、次のように「kubectl patch」コマンドを使って手動でIPアドレスを指定する必要がある。

$ kubectl -n kube-system patch svc jxing-nginx-ingress-controller -p '{ "spec": { "externalIPs": [ "<マスターノードのIPアドレス>" ] } }'
service/jxing-nginx-ingress-controller patched

コマンドの実行後、指定したIPアドレスが「EXTERNAL-IP」として正しく設定されているか確認しておこう。

$ kubectl -n kube-system get svc
NAME                                  TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE
jxing-nginx-ingress-controller        LoadBalancer   10.108.202.90   <指定したIPアドレス> 80:32685/TCP,443:30008/TCP   13m
jxing-nginx-ingress-default-backend   ClusterIP      10.109.161.61   <none>           80/TCP                       13m
kube-dns                              ClusterIP      10.96.0.10      <none>           53/UDP,53/TCP,9153/TCP       24h

また、クラスタ外からJenkins Xのコンポーネントにアクセスできることも確認しておこう。たとえばJenkins XのWebフック受付URLは、今回の設定では「http://hook.jx.<マスターノードのIPアドレス>.nip.io/hook」となる。curlコマンドなどでこのURLにアクセスし、ステータスコード200を受信できればOKだ。

$ curl -v http://hook.jx.<マスターノードのIPアドレス>.nip.io/hook
*   Trying <IPアドレス>...
* TCP_NODELAY set
* Connected to hook.jx.<IPアドレス>.nip.io (<IPアドレス>) port 80 (#0)
> GET /hook HTTP/1.1
> Host: hook.jx.<IPアドレス>.nip.io
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: openresty/1.15.8.2
< Date: Mon, 28 Oct 2019 16:58:31 GMT
< Content-Length: 0
< Connection: keep-alive
< 
* Connection #0 to host hook.jx.<IPアドレス>.nip.io left intact

Docker Registryサーバーにアクセスするための認証情報作成

独自に立ち上げたDocker Registryサーバーを使用する場合、一般的にはアクセス時に認証が必要となる。今回は認証不要でアクセスできるDocker Registryサーバーを使用するため設定は不要だが、それ以外の場合は認証情報の登録が必要だ。また、「jx boot」コマンドの実行時にDocker Registryサーバー関連の設定は行われるが、この際に適切な設定が行われない場合もあるようだ。そのため、手動で認証情報を追加する方法を説明しておこう。

認証情報設定については公式ドキュメントのDocker Registryページ内にも記述されているが、まずdockerが利用できる環境で次のように「docker login」コマンドを実行する。

$ docker login <ホスト名>:<ポート番号>
Username: ←ユーザー名を入力
Password: ←パスワードを入力
Login Succeeded

ログインに成功する(「Login Succeeded」と表示される)と、コマンドを実行したユーザーのホームディレクトリ以下に「.docker/config.json」というファイルが作成されているはずだ。このファイルを適当なディレクトリに「config.json」というファイル名でコピーする。

$ cp ~/.docker/config.json config.json

このファイルは次のようになっているはずだ。

$ cat config.json 
{
	"auths": {
		"<ホスト名>:<ポート番号>": {
			"auth": "<トークン文字列>"
		}
	}
}

なお、「"<ホスト名>:<ポート番号>":」以下の部分が複数記述されている場合があるが、その場合はJenkins Xで使用するものだけを残して他は削除しておく。最後に「kubectl create secret」コマンドでこのファイルをsecretリソースに格納する。

$ kubectl -n jx create secret generic jenkins-docker-cfg --from-file=config.json

すでにこのリソースが作成されている場合、一度このリソースを削除して再作成すれば良い。最後に適切にsecretリソースが作成されているかを確認しておこう。

$ kubectl -n jx describe secret jenkins-docker-cfg
Name:         jenkins-docker-cfg
Namespace:    jx
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
config.json:  91 bytes

ちなみに、secretリソースには指定した内容がBASE64でエンコードされて格納されており、その内容は次のようにして確認できる。

$ kubectl -n jx get secret jenkins-docker-cfg -o go-template='{{ index .data "config.json" }}' | base64 -d

インストールしたJenkins X環境をアンインストールする

インストールしたJenkins X環境が不要になった場合、もしくは設定エラーなどでインストールに失敗した場合などには、「jx uninstall」コマンドでインストールしたコンポーネントをアンインストールできる。

$ jx uninstall
? Uninstall JX - this command will remove all JX components and delete all namespaces created by Jenkins X. Do you wish to continue? Yes  ←「Y」と入力

? This action will permanently delete Jenkins X from the Kubernetes context kubernetes-admin@kubernetes. Please type in the name of the context to confirm: ←確認のためコンテキストの入力が求められる。この場合、表示されている「kubernetes-admin@kubernetes」と入力する
Removing installation of Jenkins X in team namespace jx
  :
  :
deleting namespace jx
Jenkins X has been successfully uninstalled from team namespace jx

この処理を実行すると、インストール時に指定したネームスペースが丸ごと削除される。そのため、再度インストールを行う際には「インストール作業1」からやり直す必要がある。

Jenkins XによるCI/CDを試してみる

Jenkins Xではさまざまなプログラミング言語やターゲットに向けたCI/CD設定のテンプレートが用意されており、これを利用することで簡単にCI/CD設定済みのプロジェクトを作成できるようになっている。まずはJenkins XでのCI/CDの流れを掴むため、この機能を使って簡単なプロジェクトを作成し、ビルドやデプロイの流れを確認してみよう。

「quickstart」機能を使ったプロジェクトの作成

Jenkins Xでは、テンプレートから新しいプロジェクトを作成する「jx create quickstart」コマンドが用意されている。適当なディレクトリでこのコマンドを実行し、指示に応じて対話的に設定を行うことで設定済みのリポジトリが作成される。ちなみに、このコマンドで利用できるテンプレートは、Jenkins Xの「Jenkins X Quickstarts」というプロジェクトで公開されている。

今回は「node-http」というテンプレートを選択し、ここから「test-node-http」というリポジトリを作成した。

$ jx create quickstart
? github username: <ユーザー名>  ←GitHubへのアクセスに使用するユーザー名を入力
To be able to create a repository on github we need an API Token
Please click this URL and generate a token 
https://github.com/settings/tokens/new?scopes=repo,read:user,read:org,user:email,write:repo_hook,delete_repo

Then COPY the token and enter it below:

? API Token: ****************************************  ←GitHubのアクセストークンを入力
↓利用できるテンプレートが一覧表示されるので、矢印キーでそこから使用するものを選びEnterを押す
? select the quickstart you wish to create node-http
Using Git provider github at https://github.com
? Do you wish to use hylom as the Git user name? Yes  ←最初に指定したユーザーでリポジトリを作成するので「Y」を入力
? Who should be the owner of the repository? hylom  ←使用するリポジトリのオーナーを指定
? Enter the new repository name:  test-node-http  ←作成するリポジトリ名を入力
Creating repository hylom/test-node-http
Generated quickstart at /home/hylom/jx/test-node-http
### NO charts folder /home/hylom/jx/test-node-http/charts/node-http
Created project at /home/hylom/jx/test-node-http
The directory /home/hylom/jx/test-node-http is not yet using git
? Would you like to initialise git now? Yes  ←「Y」と入力してカレントディレクトリにローカルリポジトリを作成する
? Commit message:  Initial import  ←コミットメッセージを入力

  
  

regenerated Prow configuration

Watch pipeline activity via:    jx get activity -f test-node-http -w
Browse the pipeline log via:    jx get build logs hylom/test-node-http/master
You can list the pipelines via: jx get pipelines
When the pipeline is complete:  jx get applications

For more help on available commands see: https://jenkins-x.io/developing/browsing/

Note that your first pipeline may take a few minutes to start while the necessary images get downloaded!

処理が完了すると、カレントディレクトリ内に新たなディレクトリが作成され、そこに作成されたプロジェクトのソースコードや設定ファイルが格納されるとともに、連携しているGitHubのユーザーアカウントに対しこれらのファイルを格納したリポジトリが自動的に作成される(図5)。

図5 自動的にGitHub上に連携するリポジトリが作成される
図5 自動的にGitHub上に連携するリポジトリが作成される

このリポジトリの作成時には、自動的にWebフックなどのJenkins Xとの連携に必要な設定も行われる。これによって、このリポジトリへのコミットやプッシュ、プルリクエスト、イシューへの投稿などが発生した際に、それに対応してJenkins Xが各種処理を実行できるようになっている。

パイプラインの確認

Jenkins Xでは、ビルドやテストなどの作業を「パイプライン(pipeline)」と呼ぶ。Jenkins Xに登録されているパイプラインは、「jx get pipelines」コマンドで確認できる。たとえば「test-node-http」リポジトリのパイプラインは「<ユーザー名>/test-node-http/master」という名前で登録されていることが分かる。なお、「<ユーザー名>/environment-jx-」で始まるパイプラインは、インストール時に作成されたJenkins X環境に対する処理を実行するパイプラインだ。

$ jx get pipelines
Name                                   URL LAST_BUILD STATUS DURATION
hylom/environment-jx-dev/master        N/A N/A        N/A    N/A
hylom/environment-jx-production/master N/A N/A        N/A    N/A
hylom/environment-jx-staging/master    N/A N/A        N/A    N/A
hylom/test-node-http/master            N/A N/A        N/A    N/A

「jx create quickstart」コマンドでリポジトリを作成すると自動的にパイプラインが実行され、リポジトリ内に格納されているビルド設定ファイルやデプロイ設定ファイルの内容に従って自動的にビルドやコンテナの作成、デプロイが行われる。パイプラインで実行されている処理は「jx get activity」コマンドで確認できる。

$ jx get activity
STEP                                   STARTED AGO DURATION STATUS
hylom/environment-jx-staging/master #1                      
hylom/environment-jx-staging/master #2                      
hylom/environment-jx-staging/PR-1 #1                        
hylom/test-node-http/master #1                              
hylom/test-node-http/master #2                              Succeeded Version: 0.0.2
  Release                                    9m24s     1m0s Succeeded 
  Promote: staging                           8m24s    2m30s Succeeded 
    PullRequest                              8m24s    2m30s Succeeded  PullRequest: https://github.com/hylom/environment-jx-staging/pull/1 Merge SHA: 0e66fb2dda314c74cdace825e44414c2571683fd
    Update                                   5m54s       0s Succeeded 

ここでは、先ほど作成した「test-node-http」リポジトリのパイプラインが実行され成功していることが確認できる。ちなみに、「-f <リポジトリ名>」オプションで指定したリポジトリに関する情報だけを表示することも可能だ。

$ jx get activity -f test-node-http
STEP                           STARTED AGO DURATION STATUS
hylom/test-node-http/master #1                      
hylom/test-node-http/master #2                      Succeeded Version: 0.0.2
  Release                            6m20s     1m0s Succeeded 
  Promote: staging                   5m20s    2m30s Succeeded 
    PullRequest                      5m20s    2m30s Succeeded  PullRequest: https://github.com/hylom/environment-jx-staging/pull/1 Merge SHA: 0e66fb2dda314c74cdace825e44414c2571683fd
    Update                           2m50s       0s Succeeded 

デフォルトのパイプライン設定では、ビルドやコンテナの作成完了後、自動的に「jx-staging」というネームスペース内にコンテナがデプロイされる。デプロイされたコンテナにアクセスするためのURLは、「jx get applications」コマンドで確認できる。

$ jx get applications
APPLICATION    STAGING PODS URL
test-node-http 0.0.2   1/1  http://test-node-http-jx-staging.<IPアドレス>.nip.io

この例の場合、「http://test-node-http-jx-staging.<IPアドレス>.nip.io」というURLでデプロイされたPodにアクセスできる。ちなみに今回使用した「node-http」というテンプレートでは、単にリポジトリ内にある「index.html」ファイルを表示するだけのアプリケーションとなっており、このURLにアクセスすると図6のようなページが表示される。

図6 「node-http」テンプレートでデプロイされるPodにアクセスすると静的なページが表示される
図6 「node-http」テンプレートでデプロイされるPodにアクセスすると静的なページが表示される

さらに、GitHubのリポジトリ上では自動的にバージョン番号付きのリリースが作成され、そこにソースコードを圧縮したアーカイブが登録される(図7)。

図7 リポジトリ上に自動的にリリースが作成される
図7 リポジトリ上に自動的にリリースが作成される

ちなみに、「jx get activity」の出力には「PullRequest: https://github.com/hylom/environment-jx-staging/pull/1」といった表示がされている。自動デプロイによるPod作成は「staging」環境の変更操作に該当するため、ここではJenkins Xが自動的にプルリクエストを作成してそれをマージするという処理がバックグラウンドで実行される(図8)。このように、Jenkins Xでは環境に対する操作についてもリポジトリ上に何らかの形で記録として保存する仕組みになっている。

図8 「environment-jx-staging」リポジトリに自動的にプルリクエストが作成され、それによって操作の記録が残される
図8 「environment-jx-staging」リポジトリに自動的にプルリクエストが作成され、それによって操作の記録が残される

また、ビルドログは「jx get build logs <パイプライン名>」で確認できる。

$ jx get build logs hylom/test-node-http/master
↓表示するログを選択する
? Which build do you want to view the logs of?:  hylom/test-node-http/master #2
Build logs for hylom/test-node-http/master #2
  
  (ログが表示される)
  

パイプラインを手動で起動するには、「jx start pipeline」コマンドを使用する。

$ jx start pipeline <パイプライン名>

なお、パイプラインを実行したPodはしばらくの間はそのまま残されるが、一定時間が経過すると自動的に削除される。

Gitリポジトリ上での操作に応じた処理

Jenkins Xでは、連携させているリポジトリ上での操作に応じてビルドやテスト、各種設定などを実行する。たとえばmasterブランチにコミットを行うと、Jenkins Xは自動的にビルドやコンテナ作成を行ってstaging環境のPodをアップデートするようになっている。

また、昨今ではプロジェクトの各開発者がそれぞれ自身のリポジトリを持ち、それぞれで開発した結果をプルリクエスト経由でマスターリポジトリに反映させる、といった開発スタイルが普及しているが、Jenkins Xではそれを支援する仕組みも導入されている。この機能についても紹介しておこう。

先の「jx create quickstart」コマンドで作成したリポジトリ内には、「OWNERS」という名前のファイルが作成されている。このファイルには、GitHub上でプルリクエストのマージ権限を持つユーザー(approvers)と、レビューを行うユーザーであるレビュワー(reviewers)がYAML形式で列挙されている。デフォルトでは、次のようにどちらもリポジトリ所有者(今回の場合は「hylom」)に設定されているはずだ。

$ cat OWNERS
approvers:
- hylom
reviewers:
- hylom

Jenkins Xではプルリクエストが作成されると、これらのユーザーに対してレビューやマージの許可(approve)を求め、これに応じたユーザーが作業の完了をコメントで投稿することで自動的にマージを実行するようになっている。

たとえば、masterブランチへのプルリクエストが作成されると、Jenkins Xは自動的にそれに対していくつかのコメントやラベルを追加する(図9)。

図9 プルリクエストに対し、Jenkins Xが自動でコメントを投稿してラベルを追加する
図9 プルリクエストに対し、Jenkins Xが自動でコメントを投稿してラベルを追加する

あわせて、OWNERSで指定されたレビュワーに対するレビュー要求や、Jenkins Xが実行するタスクである「tide」が自動で設定される(図10)。この時点ではtideについては待機状態になっている。

図10 レビュー要求とタスクも追加される
図10 レビュー要求とタスクも追加される

レビュワーがこのリポジトリにアクセスすると、画面上部に「Add your review」というボタンが表示されるので、これをクリックしてレビューを行う(図11)。問題がなければ、「Approve」を選択して「Submit review」をクリックする。

図11 レビュワーはプルリクエストのレビューを実行する
図11 レビュワーはプルリクエストのレビューを実行する

続いて、マージやチェック作業を実行する担当者(Assignees)を割り当てる。これは、「/assign @<ユーザー名>」というコメントを投稿する(画面下のテキストエリアに「/assign @<ユーザー名>」と入力して「Comment」ボタンをクリックする)ことで実行される(図12)。

図12 「/assign @<ユーザー名>」というコメントを投稿すると担当者が割り当てられる
図12 「/assign @<ユーザー名>」というコメントを投稿すると担当者が割り当てられる

担当者はプルリクエストをチェックし、問題がなければ「/lgtm」(「looks good to me」、「問題ないように見える」の略)とコメントする。このコメントをトリガーとして、Jenkins XはKubernetesクラスタ内にプレビュー用の環境(ネームスペース)を自動的に作成し、そこでプルリクエストのマージとビルド、デプロイを実行する。この作業が完了すると、プルリクエスト内にプレビュー環境内で起動されたPodにアクセスできるURLが投稿される(図13)。

図13 「/lgtm」というコメントが投稿されると、Jenkins Xはプレビュー用の環境内にプルリクエストをマージしてデプロイを行う。ここで「here」リンクをクリックするとそのPodにアクセスできる
図13 「/lgtm」というコメントが投稿されると、Jenkins Xはプレビュー用の環境内にプルリクエストをマージしてデプロイを行う。ここで「here」リンクをクリックするとそのPodにアクセスできる

続いて、担当者は「/ok-to-test」というコメントを投稿する。本来であれば、これによって自動的にテストが実行され、「needs-ok-to-test」というラベルが削除されるはずなのだが、今回はリポジトリ内にテストに関する設定が用意されていないためか何も実行されない。そのため、今回は手作業で「needs-ok-test」ラベルを削除した(図14)。

図14 「/ok-to-test」とコメントすると本来自動的に「needs-ok-to-test」ラベルが削除されるはずだが、動作しなかったため手作業でラベルを削除する
図14 「/ok-to-test」とコメントすると本来自動的に「needs-ok-to-test」ラベルが削除されるはずだが、動作しなかったため手作業でラベルを削除する

また、プレビュー環境をチェックして問題がなければプルリクエスト「/approve」というコメントを投稿することで「approved」ラベルが付与されてマージ作業が自動で実行されるはずなのだが、こちらも動作しなかった。そのため、同様に手作業で「approved」ラベルを付与する。すると、これに対応して自動的にマージ作業が実行されてプルリクエストが「Merged」というステータスになる(図15)。

図15 同様に手作業で「approved」ラベルを付与すると、Jenkins Xによってマージが実行される
図15 同様に手作業で「approved」ラベルを付与すると、Jenkins Xによってマージが実行される

マージが実行されると、Jenkins Xはビルドやコンテナの作成を実行し、staging環境へのデプロイを実行する。また、同時に新しいバージョン番号を付与してリリースの作成を行う(図16)。

図16 プルリクエストを元にリリースが作成される
図16 プルリクエストを元にリリースが作成される

なお、ここで紹介したようなコメントによる各種処理の実行は「prow」というコンポーネントで実行されている。prowについての詳細はドキュメントのProwページにまとめられている。また、利用できるコマンド一覧はヘルプページで確認できる。猫画像を自動投稿する「/meow」といったコマンドも利用可能だ(図17)。

図17 猫画像を投稿する「/meow」といったコマンドも利用できる
図17 猫画像を投稿する「/meow」といったコマンドも利用できる

ちなみに、prowはGitHubとの連携に特化したコンポーネントで、ほかのプラットフォームでは利用できない。その場合、「lighthouse」というコンポーネントがこのようなWebフックに対する処理を実行するよう設定される。

本番環境へのデプロイ

Jenkins Xでは、「production」という運用向けの環境がデフォルトで作成されている。staging環境にデプロイされているアプリケーションは、次のように「jx promote」コマンドを実行することで、いつでもproduction環境にデプロイできる。

まず、「jx get applications」コマンドを実行してアプリケーションの状況を確認する。

$ jx get applications
APPLICATION    STAGING PODS URL
test-node-http 0.0.3   1/1  http://test-node-http-jx-staging.<IPアドレス>.nip.io

ここでは、「test-node-http」のバージョン0.0.3がstaging環境で稼働している。これを、production環境にもデプロイしてみよう。「jx promote」コマンドでは、「--app」オプションでアプリケーションを、「--version」オプションでバージョンを、「--env」オプションで環境を指定する。

$ jx promote --app test-node-http --version 0.0.3 --env production
WARNING: prow based install so skip waiting for the merge of Pull Requests to go green as currently there is an issue with gettingstatuses from the PR, see https://github.com/jenkins-x/jx/issues/2410
Namespace jx-production created 
Promoting app test-node-http version 0.0.3 to namespace jx-production
pipeline hylom/test-node-http/master
WARNING: No $BUILD_NUMBER environment variable found so cannot record promotion activities into the PipelineActivity resources in kubernetes
Created Pull Request: https://github.com/hylom/environment-jx-production/pull/1
pipeline hylom/test-node-http/master
WARNING: No $BUILD_NUMBER environment variable found so cannot record promotion activities into the PipelineActivity resources in kubernetes
Pull Request https://github.com/hylom/environment-jx-production/pull/1 is merged at sha f32463d9529e35aefd8ed8a9712e826c28e23169
Pull Request merged but we are not waiting for the update pipeline to complete!
? Do you wish to use hylom as the user name to comment on issues Yes  ←「Y」と入力する
WARNING: Could not find the service URL in namespace jx-production for names test-node-http, jx-production-test-node-http, jx-production-test-node-http

コマンドを実行するとデプロイ作業が開始され、しばらく経つとproduction環境(「jx-production」ネームスペース)内でPodが稼働する。アクセスするためのURLは「jx get applications」で確認できる。なお、次の例では環境を指定する「-e」オプションで、production環境内で動いているアプリケーションのみを表示させている。

$ jx get applications -e production
APPLICATION    PRODUCTION PODS URL
test-node-http 0.0.3      1/1  http://test-node-http-jx-production.***.***.**.***.nip.io

また、稼働中のアプリケーションを停止させる(削除する)には「jx delete application」コマンドを使用する。このコマンドをオプションなしで実行すると、まず削除するアプリケーションの選択が求められるので、指示に従って操作を行えば良い。

既存のリポジトリをJenkins Xと連携させる

最後に、既存のリポジトリをJenkins Xと連携させる方法を紹介しておこう。といっても作業は簡単で、まずJenkins Xと連携させているGitHubアカウントでリポジトリを作成してソースコードなどをコミットするか、もしくはGitHubのフォーク機能を使ってリポジトリを作成しておき、それをローカルディレクトリにクローンしてそのディレクトリ内で「jx import」コマンドを実行すれば良い。

Jenkins Xではプログラミング言語ごとに「pack」と呼ばれる基本的なビルド設定テンプレートが提供されており、「jx import」コマンドの実行時に使用するpackを指定する必要がある。提供されているpackは「jx import --list-packs」コマンドで確認できる。

$ jx import --list-packs
Getting latest packs ...
Available draft packs:
C++
D
apps
appserver
charts
csharp
custom-jenkins
cwp
docker
docker-helm
dropwizard
environment
git
go
go-mongodb
gradle
helm
javascript
jenkins
liberty
maven
maven-java11
ml-python-gpu-service
ml-python-gpu-training
ml-python-service
ml-python-training
nop
php
python
ruby
rust
scala
swift
typescript

たとえばNode.jsベースのソフトウェアでは、「--pack javascript」というオプションを指定して「jx import」コマンドを実行すれば良い。すると、Jenkins Xのための各種設定ファイルがリポジトリ内に作成されるとともに、GitHubのリポジトリに対してWebフックの設定などが行われる。

$ jx import --pack javascript
WARNING: No username defined for the current Git server!
? Do you wish to use hylom as the Git user name: Yes  ←使用するユーザー名を確認する
trying to use draft pack: javascript
selected pack: /home/hylom/.jx/draft/packs/github.com/jenkins-x-buildpacks/jenkins-x-kubernetes/packs/javascript
replacing placeholders in directory /home/hylom/jx/my-node-webserver
app name: my-node-webserver, git server: github.com, org: hylom-test, Docker registry org: hylom-test
skipping ignored file "/home/hylom/jx/my-node-webserver/.dockerignore"
skipping directory "/home/hylom/jx/my-node-webserver/.git"
skipping ignored file "/home/hylom/jx/my-node-webserver/.gitignore"
skipping ignored file "/home/hylom/jx/my-node-webserver/.helmignore"
skipping ignored file "/home/hylom/jx/my-node-webserver/charts/my-node-webserver/.helmignore"
↓リポジトリへのコミット作業が発生するので、ユーザー名とパスワードを入力する
Username for 'https://github.com': <ユーザー名>
Password for 'https://hylom@github.com': <パスワード>
Creating GitHub webhook for hylom-test/my-node-webserver for url http://hook.jx.***.***.**.***.nip.io/hook
regenerated Prow configuration

Watch pipeline activity via:    jx get activity -f my-node-webserver -w
Browse the pipeline log via:    jx get build logs hylom-test/my-node-webserver/master
You can list the pipelines via: jx get pipelines
When the pipeline is complete:  jx get applications

For more help on available commands see: https://jenkins-x.io/developing/browsing/

Note that your first pipeline may take a few minutes to start while the necessary images get downloaded!

なお、デフォルト設定でどのようにビルドやテストが行われるかは使用するpackごとに異なるため注意したい。詳しくはドキュメントのBuild Packsページやリポジトリ上のファイルなどを参照してほしいが、たとえば前述の「javascript」packでは「npm test」コマンドでテストを実行し、「npm start」コマンドでアプリケーションを起動するような設定になっている。また、サービスは8080番ポートを使用することが前提となっている。

KubernetesとGitHubの利用者には有用なものの、ドキュメントの不備が課題

このようにJenkins XではGitHubとの連携が特徴的であり、Kubernetes環境向けのアプリケーションを、GitHubを使って開発しているのであれば魅力的だ。ただ、先に述べたとおりドキュメントが十分でない点と、GKE以外の環境での検証不足は大きな課題だ。開発は活発に行われているものの、プロジェクトへの不具合報告をみるとGKE+GitHub以外の環境での不具合については現時点では対応しきれていないような雰囲気も感じられる。

また、GitHub以外のプロジェクト支援プラットフォームとの連携に関しても検証は行ったものの、ドキュメントでの記載が少なく、何が適切な動作なのかが分からず戸惑うこともあった。さらに、インストール時には設定を少し変えただけでもエラーが出るなど、トラブルも少なくない。設定やデプロイなどについては比較的分かりやすいため、今後の改善に期待したいところである。