[DevOpsプラットフォームの取り組み #2] Qmonus Value Streamを使ってみた(後編) - CI/CDパイプラインの構築

はじめに

DevOpsプラットフォームの取り組みを紹介する2回目の記事の後半です。

Qmonus(クモナス) Value Streamの開発チームの奥井( @HirokiOkui )です。

連載第2回では、Qmonus Value Streamを使ってアプリケーションを実際にビルド・デプロイする事例を2つ、前編・後編に分けて紹介します。 前編では、Cloud Native Adapterを用いてパブリッククラウドとKubernetesの両方をまとめてInfrastructure as Code(以下、IaC)として表現し、クラウド基盤を構築する事例を紹介しました。 後編では、Cloud Native Adapterを用いたContinuous Integration/Continuous Delivery(以下、CI/CD)パイプラインの構築を中心に説明します。

1回目、2回目前編の記事をまだご覧になってない方は、ぜひそちらもご覧ください。

1回目 Qmonus Value Streamの紹介

2回目 Qmonus Value Streamを使ってみた(前編) - クラウド基盤の構築

ユースケース2: Istio BookInfo

アプリケーションのデリバリを実践する事例として、第2回前編では「KubernetesとGCPによるパブリックAPI公開」を紹介しました。後編では2つ目の事例として、Istioプロジェクトのサンプルアプリケーションである BookInfo を扱います。 BookInfoは、書籍のカタログを表示するシンプルなWebアプリケーションですが、言語の異なる4つのマイクロサービスから構成されており、実践的なアプリケーションに近い複雑さとデリバリの難しさを備えています。このため、IaCやCI/CDのツールを評価するのに適しています。

Istioのドキュメントより)

リリースエンジニアリングの難しさ

Kubernetesに対してコンテナをデリバリするためには、 Tekton CI によるビルド、 KustomizeHelm によるマニフェスト生成、 Argo CD によるデプロイを用いてCI/CDパイプラインを構成することが一般的です。 これらを用いてBookInfoをデリバリする方法が、インプレス社の Kubernetes CI/CDパイプラインの実装 に詳しく記されています。

こちら で公開されているBookInfoのデリバリに必要なマニフェストを見ると、デリバリ対象のKustomizeマニフェスト、CI/CDのためのTektonとArgo CDのマニフェストと、多くのマニフェストとパラメータが含まれています。 CI/CDパイプラインを構築するためには、それぞれを正しく結合して使いこなす必要があります。

このように、アプリケーションをリリースするためのCI/CDパイプラインを信頼性高く構築し保守する技術領域のことを、リリースエンジニアリングと言います。 BookInfoのように、マイクロサービスアーキテクチャを採用したアプリケーションのリリースには、高度なリリースエンジニアリングのスキルが要求されます。 これを少人数の開発チームで実践するのは至難の業です。

Qmonus Value Streamを用いたCI/CDパイプラインの構成

Qmonus Value Stream(以下、QVS)では、前編で紹介したとおり、独自のIaC実装であるCloud Native Adapter(以下、Adapter)を用いて上述の問題を解決します。

以降の節で、BookInfoをデリバリするCI/CDパイプラインをAdapterを用いて構成する実例について、順を追って説明します。 ここでは、BookInfoを構成する4つのマイクロサービスのそれぞれをイメージビルドし、生成されたイメージを用いたKubernetes Deploymentと内部通信用のServiceをマイクロサービスごとにデプロイするCI/CDパイプラインを構成します。

Cloud Native Adapterの選択

まず、QVSの設定ファイルであるQVS Configを作成し、その中で使用するAdapterを選択します。 BookInfoの reviews アプリケーションでは、以下のQVS Configを使用します。

params:
  - name: namespace
    type: string
  - name: imageName
    type: string

designPatterns:
  - pattern: qmonus.net/adapter/official/kubernetes/deployment/simple
    params:
      appName: reviews
      namespace: $(params.namespace)
      imageName: $(params.imageName)
      port: "9080"
      env:
        - name: LOG_DIR
          value: "/tmp/logs"
      useDefaultService: true
  - pattern: qmonus.net/adapter/official/pipeline/build:buildkit
  - pattern: qmonus.net/adapter/official/pipeline/deploy:simpleDeploy

ここでは、QVSで用意している3つのAdapterを使用します。 1つ目は、Applicationマニフェストを扱う Adapterであり、Kubernetes DeploymentリソースとServiceリソースを提供します。 2つ目と3つ目は Pipelineマニフェストを扱う Adapterであり、それぞれ Buildkit を用いたBuild Taskと、IaCツールである Pulumi を用いたDeploy Taskを提供します。 BookInfoの残り3つのサービスのQVS Configも、reviewsと同様に、上記で紹介した3つのAdapterを使用します。

Tekton Pipelineの生成

次に、上述したBookInfoの4つのマイクロサービスに対する各QVS Configを指定してコンパイルします。 すると、各マイクロサービスごとのビルド用とデプロイ用のTekton Pipelineが自動生成されます。

$ kubectl get pipeline -o custom-columns=NAME:.metadata.name
NAME
details-build
details-deploy
productpage-build
productpage-deploy
rating-build
rating-deploy
reviews-build
reviews-deploy

Tekton Pipelineから使用されるTekton Taskも自動生成されます。 今回の場合、1つのマイクロサービスにつき5個、計20個のTekton Taskが生成されます。

$ kubectl get task -o custom-columns=NAME:.metadata.name | grep reviews
reviews-app-compile-design-pattern
reviews-app-deployment-worker
reviews-auth-google-registry
reviews-buildkit
reviews-git-checkout
# productpage, details, rating についても同様

生成されたTekton PipelineおよびTaskを以下の図に示します。 Build PipelineはソースコードからBuildkitを用いてdocker imageをビルドし、Google Artifact Registryにプッシュします。 Deploy Pipelineは、QVS Configで指定されているAdapterをコンパイルしてInfrastructureマニフェストを生成し、Pulumiを用いてKubernetesクラスターに対してデプロイします。

Adapterをコンパイルして生成されるTekton Pipelineは、CI/CDパイプライン全体を担うのではなく、上記例のようにBuild、Deploy、Test、Release…といったまとまったプロセス単位ごとに分割されます。 Tekton Pipelineを再利用可能で可搬性がある単位に分割することで、Tekton Pipelineをビルディングブロックのように扱い、柔軟にCI/CDパイプラインを組み立てることができます。

AssemblyLineの作成

最後に、AssemblyLineというQVS独自のリソースを用いてCI/CDパイプラインを構成します。 AssemblyLineに実行対象のTekton Pipelineと実行順序を定義することで、その順序に従いTekton Pipelineが実行されます。

今回は、BookInfoの4つのマイクロサービスをそれぞれビルドし、ステージング環境にデリバリするAssemblyLineを作成します。 作成したAssemblyLineを以下に記します。簡単のため、reviewsのビルドとデプロイに限定し、他の3つは省略しています。

apiVersion: vs.axis-dev.io/v1
kind: AssemblyLine
metadata:
  name: bookinfo-build-and-deploy
spec:
  params:
  - name: gitRevision
  - name: imageTag

  stages:
  - name: reviews-build-staging
    spec:
      deployment:
        app: reviews
        name: staging
      pipeline: reviews-build
      params:
      - name: gitRevision
        value: $(inputs.gitRevision)
      - name: imageTag
        value: $(inputs.imageTag)

  - name: reviews-deploy-staging
    runAfter:
    - reviews-build-staging
    spec:
      deployment:
        app: reviews
        name: staging
      pipeline: reviews-deploy
      params:
      - name: gitRevision
        value: $(inputs.gitRevision)
      - name: imageName
        value: $(stages.reviews-build-staging.results.imageFullNameTag)

  # 以下は省略
  - name: rating-build-stating...
  - name: rating-deploy-stating...
  - name: productpage-build-stating...
  - name: productpage-deploy-stating...
  - name: details-build-stating...
  - name: details-deploy-stating....

AssemblyLineには複数のStageが設定可能であり、1つのStageは1つのTekton Pipelineで構成されます。 Stageごとに、Tekton Pipelineで記述された処理をどのマイクロサービスのどの環境向けに作用させるのか、を選択します。 各Stageの runAfter に依存するStageを指定することで、DAG(有向非巡回グラフ)が形成され、依存関係を持つ複数のStageを順番に実行できます。

また、各Stageの params を記述することで、Tekton Pipeline実行時のパラメータをどこから取得するかを定義します。 ここでは、Build Pipelineの引数である gitRevisionimageTag の値をAssemblyLine実行時のパラメータから取得しており、Deploy Pipelineの imageName の値をBuild Pipelineの実行結果から取得しています。

CI/CDパイプラインの構築が簡単に

以上、Adapterを用いてCI/CDパイプラインを構成する手順を紹介しました。

前述したように、Tekton、Kustomize、ArgoCDなどを用いてCI/CDパイプラインを構築するためには、各ツールに対するスキルに加えてツールごとに異なる様式で多くのマニフェストを記述し結合する必要があり、高い専門性が要求されます。 BookInfoの例では20〜30ほどのマニフェストが必要になり、アプリケーションの構成がより複雑化するにつれて大きく増大します。

QVSでは、ベストプラクティスとして提供されているAdapterを選択するだけで必要なTekton Pipelineが生成されるので、マニフェストを記述する必要がありません。 BookInfoのようなマイクロサービスアプリケーションの例であっても、生成されたTekton Pipelineの実行順序をAssemblyLineに記述するだけで、CI/CDパイプラインを構築できます。 リリースエンジニアリングの専門家でなくても、信頼性の高いCI/CDパイプラインを構成できるようになります。

CI/CDパイプラインの実行

前述した構成の元、 CI/CDパイプラインがどのように実行されるか説明します。

BookInfoのAssemblyLineマニフェストをQVSに登録すると、QVSのWebUI上で以下のようにAssemblyLineが表示されます。 今回は、各マイクロサービスごとにBuild PipelineのあとにDeploy Pipelineを実行するだけのシンプルなAssemblyLineなので2層だけですが、実際のAssemblyLineはCI/CDの様々なタスクや承認行為を含み、より複雑なパイプラインを構成することになります。

AssemblyLineを実行するためには、BookInfoを構成するマイクロサービスやデプロイ先の環境情報などをQVSに事前に入力する必要があります。 ここでも、マニフェストの記述量やパラメータ数を減らすための様々な工夫が導入されていますが、こちらについては別の記事で改めて紹介します。

AssemblyLineは、WebUI上から実行するか、gitのプッシュイベントをトリガとして実行されます。 実行されると、AssemblyLineの実行順序定義に従い先頭から順番にTekton PipelineRunおよびTaskRunが実行され、Kubernetes SchedulerによってPodがスケジューリングされて、各CI/CDタスクが実行されていきます。

WebUIでは、リアルタイムな進捗表示に加えて、Taskを実行しているPodのLogやEventなどの情報を確認できます。 Taskが正常に動作していない場合には、Tektonが動作しているKubernetesクラスターにアクセスすることなく、WebUI上から問題の切り分けを行うことが可能です。

以下のように全てのStageに正常終了のマークがつけば、AssemblyLineの処理は完了です。

デプロイ先のKubernetesクラスターにアクセスして、BookInfoアプリケーションが正常動作していることを確認します。以下の通り、4つのマイクロサービスのDeploymentとServiceが生成され、全てのPodが上がっていることが確認できます。

$ kubectl get all -n sample-bookinfo
NAME                               READY   STATUS    RESTARTS   AGE
pod/details-78457fc5c9-7szn5       1/1     Running   0          12h
pod/productpage-7fccdbdb9c-8cqw8   1/1     Running   0          12h
pod/rating-6c8db77566-gfkxj        1/1     Running   0          12h
pod/reviews-855b779f4d-xqs7t       1/1     Running   0          12h

NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/details       ClusterIP   10.44.12.16    <none>        9080/TCP   12h
service/productpage   ClusterIP   10.44.10.189   <none>        9080/TCP   12h
service/rating        ClusterIP   10.44.0.210    <none>        9080/TCP   12h
service/reviews       ClusterIP   10.44.0.249    <none>        9080/TCP   12h

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/details       1/1     1            1           12h
deployment.apps/productpage   1/1     1            1           12h
deployment.apps/rating        1/1     1            1           12h
deployment.apps/reviews       1/1     1            1           12h

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/details-78457fc5c9       1         1         1       12h
replicaset.apps/productpage-7fccdbdb9c   1         1         1       12h
replicaset.apps/rating-6c8db77566        1         1         1       12h
replicaset.apps/reviews-855b779f4d       1         1         1       12h

productpageのPodにport-forwardしてUIを表示してみると、画面が表示され、正常にデプロイできていることが確認できます。

おわりに

DevOpsプラットフォームの取り組み連載の2回目の記事として、Cloud Native Adapterを使用することでクラウド基盤とCI/CDパイプラインが簡単に構築できることを、2つの事例を用いて紹介しました。 NTTコミュニケーションズでは多くのプロジェクトで内製開発をしており、開発チームがプロダクト開発の最も重要な部分に注力できるように、Qmonus Value Streamの開発とCloud Native Adapterの拡充を進めています。

Qmonus Value Streamチームは、メンバ一人一人が、利用者であるアプリケーション開発者のために信念を持って活動を続けています。 プラットフォームを内製開発するポジション、プラットフォームを使ってNTTグループのクラウド基盤やCI/CDを構築支援するポジションそれぞれで 、一緒に働く仲間を募集していますので、興味を持たれた方は応募いただけると嬉しいです。

次回は、Cloud Native Adapterについてさらに踏み込んで紹介します。お楽しみに!

© NTT Communications Corporation 2014