Kubernetes Engine での Jenkins

このトピックでは、Google Kubernetes Engine で Jenkins を使用するためのおすすめの方法について説明します。このソリューションを実装するには、Kubernetes Engine での Jenkins の設定をご覧ください。

Jenkins は、ビルド、テスト、デプロイ パイプラインを柔軟にオーケストレートできるオープンソースのオートメーション サーバーです。Kubernetes Engine は、強力なクラスタ マネージャでコンテナのオーケストレーション システムである Kubernetes のホストされたバージョンです。

継続的デリバリー(CD)パイプラインを設定する必要がある場合、Kubernetes Engine での Jenkins のデプロイは、標準の VM ベースのデプロイと比べて次のような重要なメリットがあります。

  • ビルドプロセスでコンテナを使用すると、1 つの仮想ホストで異なるオペレーティング システムに対してジョブを実行できます。

  • Kubernetes Engine は、各ビルドが以前のビルドと同じクリーンな環境で実行できるように、エフェメラル ビルド エグゼキュータを提供します。

    • ビルド エグゼキュータがエフェメラルである一因は、ビルドが活発に実行されているときには Kubernetes Engine クラスタのみが使用され、バッチ処理ジョブなどの他のクラスタタスクのために利用可能なリソースを残すためです。

    • ビルド エグゼキュータは数秒で起動します。

  • Kubernetes Engine は Google のグローバル ロードバランサを利用して、ウェブ トラフィックをインスタンスにルーティングします。ロードバランサは、SSL ターミネーションを処理し、Google のバックボーン ネットワークを介して、ユーザーに最も近い接続拠点(point of presence)からの最速パスのいずれかにあるウェブ フロントエンドにユーザーをルーティングするグローバル IP アドレスを提供します。

Kubernetes Engine での Jenkins の詳細については、YouTube で Next 2018 の講演をご覧ください。

State of DevOps で、ソフトウェア デリバリーのパフォーマンスを向上させると認められた機能が報告されています。このトピックでは、次の機能について説明します。

Helm を使用した Jenkins コントローラのデプロイ

Helm を使用してチャート リポジトリから Jenkins をデプロイします。Helm は、Kubernetes アプリを構成してデプロイできるパッケージ マネージャーです。

以下の図は、マルチノードの Kubernetes クラスタで Jenkins をデプロイするためのアーキテクチャを示しています。

Jenkins と Kubernetes アーキテクチャ

Jenkins コントローラを Kubernetes クラスタ内の別の名前空間にデプロイします。名前空間を使用することで、Jenkins のデプロイ用に割り当てを作成できます。また、Jenkins をクラスタ内で他のデプロイから論理的に分離できます。

Jenkins サービスの作成

Jenkins は、クラスタがアクセスする必要がある 2 つのサービスを提供します。これらのサービスを別々にデプロイすることで、これらを個別に管理して名前を付けることができます。

  • ポート 8080 上で外部に公開されている NodePort サービスは、Pod と外部ユーザーが Jenkins のユーザー インターフェースにアクセスすることを許可します。このタイプのサービスは、HTTP ロードバランサによって負荷分散できます。

  • ポート 50000 上の内部の非公開 ClusterIP サービスは、Jenkins エグゼキュータがクラスタ内から Jenkins コントローラと通信するために使用します。

以降のセクションでは、サービス定義のサンプルを示します(この定義で、コントローラは master と呼ばれます)。

---
  kind: Service
  apiVersion: v1
  metadata:
    name: jenkins-ui
    namespace: jenkins
  spec:
    type: NodePort
    selector:
      app: master
    ports:
      - protocol: TCP
        port: 8080
        targetPort: 8080
        name: ui
---
  kind: Service
  apiVersion: v1
  metadata:
    name: jenkins-discovery
    namespace: jenkins
  spec:
    selector:
      app: master
    ports:
      - protocol: TCP
        port: 50000
        targetPort: 50000
        name: slaves

Jenkins のデプロイの作成

Jenkins コントローラを、レプリカ数 1 の Deployment としてデプロイします。これにより、クラスタ内で常に 1 つの Jenkins コントローラが実行されます。Jenkins コントローラ Pod が停止するか、Pod が実行されているノードがシャットダウンすると、Kubernetes はクラスタ内の他の場所で Pod を再起動します。

Helm デプロイの一部としてリクエストと上限を設定することが重要です。これによりコンテナでは、スケジューリング前にクラスタ内の一定量の CPU リソースとメモリリソースが確保されます。そうしないと、CPU またはメモリの不足によりコントローラがダウンする場合があります。

Jenkins ホーム ボリュームには、XML 構成ファイルと Jenkins 環境を構成するプラグイン JAR ファイルが格納されています。このデータは、GKE クラスタで管理される永続ディスクに保存され、Jenkins の再起動後もデータが維持されます。永続ディスクのサイズを変更するには、Helm で Jenkins をインストールするときに Persistence.Size の値を編集します。

Jenkins への接続

Jenkins ポッドが作成されたら、ロードバランサのエンドポイントを作成して、Cloud Platform の外側から接続できます。次のおすすめの設定や方法を考慮してください。

  • SSL ターミネーションを使って、構成しやすい L7 ロードバランサに Kubernetes の上りリソースを使用します。

  • Kubernetes Secret を使用して、ロードバランサに SSL 証明書を提供します。tls.certtls.key の値を使用し、上り(内向き)リソース構成で値を参照します。

Jenkins の構成

Jenkins のセキュリティ保護

初めて Jenkins に接続したら、すぐに Jenkins をセキュリティ保護することが重要です。内部ユーザー データベースを利用する、Jenkins の標準的なセキュリティの設定チュートリアルの簡単な手順に沿って操作できます。この設定を行うことで、追加のインフラストラクチャを用意しなくても、匿名ユーザーをロックアウトする機能を利用できるようになります。

プラグインのインストール

次のプラグインをインストールして、Jenkins と Kubernetes Engine との相互作用を高めることができます。

  • Kubernetes プラグインでは、認証に Kubernetes Service アカウントを使用すること、および異なるベースイメージを使用してラベル付きのエグゼキュータの構成を作成することが可能です。このプラグインは、エグゼキュータが必要な場合に Pod を作成して、ジョブが終了したらその Pod を破棄します。

  • Google Authenticated Source プラグインは、Cloud Source Repositories などの Cloud Platform サービスにアクセスする際に、自分のサービス アカウントの認証情報を使用できるようにします。

Helm チャートを使用してプラグインを追加するには、Helm のインストールまたはアップグレード コマンドに渡す値ファイルでプラグインのリストを編集します。

Jenkins エージェントの Docker イメージのカスタマイズ

ポッド テンプレートを作成する際に、既存の Docker イメージを提供するか、ビルド時の依存関係のほとんどがインストールされたカスタム イメージを作成できます。カスタム イメージを使用すると、全体のビルド時間を短縮し、より一貫性のあるビルド環境を作成できます。

カスタムの Docker イメージでは、Jenkins JNLP インバウンド エージェントをインストールして構成する必要があります。JNLP エージェントは、Jenkins ジョブの実行とジョブ ステータスのレポートを調整するため、Jenkins コントローラと通信するソフトウェアです。

オプションとして、FROM jenkins/inbound-agent をイメージ構成に追加できます。たとえば、アプリケーションのビルドプロセスが Go のランタイムに依存している場合、次の Dockerfile を作成して、既存のイメージを独自の依存関係とビルド アーティファクトを使用して拡張できます。

FROM jenkins/inbound-agent
RUN apt-get update && apt-get install -y golang

次に、以下のコマンドを実行して、イメージをビルドしてプロジェクトの Container Registry リポジトリにアップロードします。

docker build -t gcr.io/[PROJECT]/my-jenkins-image .
gcloud auth configure-docker
docker push gcr.io/[PROJECT]/my-jenkins-image

これで、Pod テンプレートを作成するとき、Docker イメージ フィールドに次の文字列を設定できます。[PROJECT] は実際のプロジェクト名に、[IMAGE_NAME] はイメージ名に置き換えます。

gcr.io/[PROJECT]/[IMAGE_NAME]

上記の例は、Jenkins ジョブの開始時に、Go 言語のランタイムが事前にインストールされていることを保証します。

Jenkins での Docker イメージのビルド

独自の Docker デーモンをホストせずに、Jenkins ジョブから Cloud Build を使用して Docker イメージをビルドできます。Jenkins ジョブには、cloudbuild.builds.editor ロールが付与されたサービス アカウント認証情報が必要です。

Jenkins パイプライン ファイルの例については、この GitHub リポジトリをご覧ください。

Kaniko を使用して、クラスタ内にコンテナを作成することもできます。Kaniko の場合、イメージをビルドし、リモートのレジストリに push するために Docker デーモンを必要としません。

Jenkins で Kaniko を使用する例については、GitHub リポジトリをご覧ください。

次のステップ