Tekton Pipelines を使用して Hello World アプリケーションを作成し、Kubernetes 上にデプロイする

現在、コンテナー・ベースのソフトウェア開発が盛んに行われるようになっています。簡単に環境を複製できるため、一般に、開発者はアプリケーションを自分のデスクトップ上で作成し、ローカルでデバッグとテストを行ってから、アプリケーションをビルドして Kubernetes クラスターにデプロイします。

このチュートリアルでは、アプリケーションを IBM Cloud 上の Kubernetes クラスターにデプロイするための以下の 2 つの方法を紹介します。

  • DevOps パイプラインを使用せずに、kubectl CLI を使ってデプロイする
  • Tekton Pipelines (Kubernetes スタイルの継続的インテグレーション/継続的デリバリー (CI/CD) パイプライン) を使用してデプロイする

前提条件

このチュートリアルに従うには、あらかじめ以下の作業を行っておく必要があります。

  • IBM Cloud アカウントを作成する。
  • IBM Cloud 上の Kubernetes サービスのインスタンスを作成する。サービス・インスタンスを作成するには約 20 分かかります。
  • kubectl CLI を使用して Kubernetes クラスターにアクセスできるようにする。手順を参照するには、IBM Cloud ダッシュボード > [クラスター名]> 「Access (アクセス)」 の順に選択してください。
  • IBM Cloud コンテナー・レジストリー上に名前空間を作成する。それには、IBM Cloud ダッシュボードで 「Navigation (ナビゲーション)」 > 「Kubernetes」 > 「Registry (レジストリー)」 > 「Namespaces (名前空間)」 の順にクリックします。
  • Git CLI を構成する。以下のコマンドを実行して、リポジトリーをワークステーションに複製します。

    git clone https://github.com/IBM/deploy-app-using-tekton-on-kubernetes.git
    

所要時間

前提条件に対応したならば、約 40 分でこのチュートリアルを完了できます。

kubectl を使用してアプリケーションをビルドし、IBM Cloud Kubernetes Service 上にデプロイする

以下の手順に従って、アプリケーションをビルドして Kubernetes クラスター上にデプロイします。

  1. アプリケーション用の Dockerfile を作成し、その Dockerfile を使用してコンテナー・イメージをビルドします。
  2. ビルドしたコンテナー・イメージを、アクセス可能なコンテナー・レジストリーにアップロードします。
  3. コンテナー・イメージを使用して Kubernetes デプロイメントを作成し、構成 (YAML) ファイルを使用してアプリケーションを IBM Cloud Kubernetes Service クラスターにデプロイします。

このチュートリアルでは以下のようにして、シンプルな Hello World! Node.js アプリケーションを Kubernetes 上にデプロイしています。以下のコードはサンプル・アプリから抜粋したものです。複製したリポジトリーに含まれているコードを使用してください。

  const app = require('express')()

  app.get('/', (req, res) => {
    res.send("Hello from Appsody!");
  });

  var port = 3300;

  var server = app.listen(port, function () {
    console.log("Server listening on " + port);
  })

  module.exports.app = app;

Dockerfile とデプロイメント構成ファイルの deploy.yaml は、前に複製した GitHub リポジトリー内に用意されています。このセクションで説明する手順に従うと、CLI を使ってアプリケーションをクラスターにデプロイできます。

1. デプロイ・ターゲットをセットアップする

最初のステップとして、アクセス可能なコンテナー・レジストリーにアップロードするコンテナー・イメージに対し、正しいデプロイ・ターゲットを設定する必要があります。クラスターを作成したリージョンに応じて、イメージの URL は以下の形式になります。

  <REGION_ABBREVIATION>.icr.io/<YOUR_NAMESPACE>/<YOUR_IMAGE_NAME>:<VERSION>

以下のコマンドで、クラスターのレジストリー API エンドポイントに関する詳細を取得します。このコマンドの出力からリージョンの略語がわかります。

   ibmcloud cr api

名前空間を取得するには、以下のコマンドを使用します。

    ibmcloud cr namespaces

例えば、US-South リージョンのデプロイメント・ターゲットは以下のようになります。

       us.icr.io/test_namespace/sampleapp:1.0

2. アプリケーションをデプロイする

以下のコマンドを実行してアプリケーションを Kubernetes クラスター上にデプロイします。

  cd ~/deploy-app-using-tekton-on-kubernetes/src

  # Build and push it to IBM Cloud Container registry. Following command takes care of build and push to container registry and eliminates the overhead to run docker commands individually.
  ibmcloud cr build -t us.icr.io/test_namespace/sampleapp:1.0 .

  # Verify whether the image is uploaded to the container registry
  ibmcloud cr images

  # Update deploy target in deploy.yaml
  sed -i '' s#IMAGE#us.icr.io/test_namespace/sampleapp:1.0# deploy.yaml

  # Run deploy configuration
  kubectl create -f deploy.yaml

  # Verify output - pod and service should be up and running
  kubectl get pods
  kubectl get service

デプロイが正常に完了した後、デプロイ済みアプリケーションに http://<public-ip-of-kubernetes-cluster>:32426/ でアクセスして、IBM Cloud ダッシュボードから Kubernetes クラスターのパブリック IP を取得できます。ポート 32426 は、deploy.yaml 内で nodePort として定義されています。

上記の手順では、CLI を使用して Kubernetes クラスター上にデプロイする方法を説明しました。デプロイ後にアプリケーションを変更した場合は、この手順を繰り返す必要があります。

これよりも短時間で確実にアプリケーションをビルド、テスト、デプロイするには、このワークフロー全体を自動化します。CI/CD の手法に従えば、開発と手作業によるデプロイ・プロセスのオーバーヘッドを削減できるため、大幅な時間の節約と作業の軽減につながります。

このチュートリアルの次のセクションでは、Tekton Pipelines を使用したビルドとデプロイ手法を説明します。

Tekton Pipelines を使用してアプリケーションをビルドし、IBM Cloud Kubernetes Service 上にデプロイする

Tekton は、CI/CD システムを作成するための強力かつ柔軟な、Kubernetes ネイティブのオープンソース・フレームワークです。Tekton はそのベース部分の実装の詳細を抽象化するため、特定のクラウド・プロバイダーやオンプレミス・システムに依存しないビルド、テスト、デプロイ・プロセスが可能になります。

Tekton Pipelines の使用方法を説明する前に、理解しておく必要のある大まかなコンセプトを紹介します。

Tekton Pipelines プロジェクトは、パイプラインを定義する CRD (Custom Resource Definition: カスタム・リソース定義) を 5 つ追加して Kubernetes API を拡張しています。

  • Task: コードのコンパイル、テストの実行、イメージのビルドとデプロイなどの一連のビルド・ステップを定義する個別のジョブです。
  • TaskRun: 定義された Task を実行するための CRD です。Task の入力と出力をバインドする TaskRun を使用して、単一の Task を実行できます。
  • Pipeline: パイプラインを構成する Task のリストを記述します。
  • PipelineRun: Pipeline の実行を定義します。実行する Pipeline と、入力および出力として使用する 1 つ以上の PipelineResource を参照します。
  • PipelineResource: Pipeline の入力 (Git リポジトリーなど) または出力 (Docker イメージなど) であるオブジェクトを定義します。

Tekton Pipelines を使用してアプリケーションのビルドとデプロイのワークフローを自動化するには、以下の手順に従います。

1. Tekton Pipelines のコンポーネントを Kubernetes クラスターに追加する

最初のステップとして、以下のコマンドを使用して Tekton Pipelines を Kubernetes クラスターに追加します。

  kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

上記のコマンドによって Tekton Pipelines がインストールされると、2 つのポッドが作成されます。作成されたポッドを確認するには、以下のコマンドを使用します。必ず、ポッドが実行状態になるまで待ってください。

  kubectl get pods --namespace tekton-pipelines

詳細については、Tekton のドキュメントを参照してください。以上の手順が完了すると、Kubernetes クラスターは Tekton Pipelines を実行できる状態になります。それではまず、カスタム・リソースの定義を作成するところから始めましょう。

2. PipelineResource リソース定義を作成する

このチュートリアルで例として使用するアプリケーションのソース・コード、Dockerfile、デプロイメント構成は、前に複製した GitHub リポジトリー内に用意されています。

Git リポジトリーにアクセスするための入力 PipelineResource を作成するには、以下の手順に従います。

以下のようにして、git.yaml ファイル内に Git リポジトリーを対象とした PipelineResource を定義します。

  • リソースの type として Git を指定します。
  • url に、Git リポジトリーの URL を指定します。
  • revision に、使用する Git リポジトリーのブランチ名を指定します。

完全な YAML ファイルは ~/tekton-pipeline/resources/git.yaml にあります。以下のコマンドを使用して、このファイルをクラスターに適用します。

  cd ~/tekton-pipeline
  kubectl apply -f resources/git.yaml

3. Task リソース定義を作成する

Task はパイプラインのステップを定義します。Git リポジトリー内のソース・コードを使用してアプリケーションをクラスターにデプロイするために、build-image-from-sourcedeploy-to-cluster という 2 つの Task を定義します。Task リソース定義内では、引数 (args) として使用するパラメーターを $(inputs.params.<var_name>) として指定します。

build-image-from-source を定義する

この Task には以下の 2 つのステップが含まれます。

  1. list-src ステップで、複製されたリポジトリー内のソース・コードをリストアップします。このステップの目的は、ソース・コードが適切に複製されているかどうかを確認することです。
  2. build-and-push ステップで、Dockerfile を使用してコンテナー・イメージをビルドし、ビルドしたイメージをコンテナー・レジストリーにプッシュします。このチュートリアルの例では、イメージをビルドしてプッシュするために Kaniko を使用します。Kaniko の他に、buildah、podman なども使用できます。Kaniko は引数として、Dockerfile の名前と場所、コンテナー・イメージのアップロード先を使用します。

すべての必須パラメーターを渡します。以下のコマンドを使用して、このファイルをクラスターに適用します。

  kubectl apply -f task/build-src-code.yaml

deploy-to-cluster を定義する

次は、ビルドされたコンテナー・イメージを使用してアプリケーションをポッド内にデプロイし、サービスとして公開して、どこからでもアプリケーションにアクセスできるようにします。この Task は、~/src/deploy.yaml にあるデプロイメント構成を使用します。

この Task には以下の 2 つのステップが含まれます。

  1. update-yaml ステップで、deploy.yaml 内の IMAGE をコンテナー・イメージの URL で置き換えます。
  2. deploy-app ステップで、アプリケーションを Kubernetes ポッド内にデプロイし、~/src/deploy.yaml を使用してアプリケーションをサービスとして公開します。このステップでは kubectl を使用して Kubernetes クラスター上にデプロイメント構成を作成します。

すべての必須パラメーターを渡します。

以下のコマンドを使用して、このファイルをクラスターに適用します。

  kubectl apply -f task/deploy-to-cluster.yaml

4. Pipeline リソース定義を作成する

Pipeline では、実行する Task をリストアップし、各 Task に必要な入力リソース、出力リソース、入力パラメーターを指定します。Task 間に依存関係がある場合は、その依存関係にも対処します。

tekton-pipeline/resources/pipeline.yaml の内容は以下のとおりです。

  • Pipeline リソース定義では、上述の 2 つの Task (build-image-from-source および deploy-to-cluster) を使用します。
  • 2 つの Task を順番に実行する必要があるため、runAfter キーを使用しています。
  • PipelineResource (Git リポジトリー) を resources キーで指定します。

すべての必須パラメーターを渡します。Pipeline リソース定義内ではパラメーター値が $(params.imageUrl) として定義されています。これは、Task リソース定義内の args とは異なります。以下のコマンドを使用して、このファイルをクラスターに適用します。

  kubectl apply -f pipeline/pipeline.yaml

5. PipelineRun リソース定義を作成する

パイプラインを実行するには、PipelineRun リソース定義を使用して、すべての必須パラメーターを渡す必要があります。PipelineRun がパイプラインをトリガーし、トリガーされたパイプラインが TaskRun を作成するといった流れです。同じようにして、すべてのパラメーターが置換されて Task に渡されます。

PipelineRun 内でパラメーターが定義されていない場合、リソース定義自体に含まれる spec で定義されている params からデフォルト値が選出されます。例えば、Task build-image-from-source 内で pathToDockerfile パラメーターが使用されているものの、その値が pipeline-run.yaml 内で指定されていないとします。その場合、Task の実行時には ~/tekton-pipeline/build-src-code.yaml 内で定義されているデフォルト値が使用されます。

PipelineRun リソース定義に含まれる tekton-pipeline/pipeline/pipeline-run.yaml の内容は以下のとおりです。

  • pipeline.yaml を使用して作成されたパイプライン application-pipeline を参照します。
  • 入力として使用する PipelineResource git を参照します。
  • Pipeline と Task の実行時に必要なパラメーターの値を params に指定します。
  • サービス・アカウントを指定します。

パイプラインを介してイメージをレジストリーにプッシュし、クラスターにデプロイするには、パイプラインにコンテナー・レジストリーとクラスターにアクセスするのに十分な権限が付与されていなければなりません。レジストリーに対する資格情報はサービス・アカウントによって提供されます。したがって、PipelineRun を実行する前にサービス・アカウントを定義する必要があります。

注: まだ PipelineRun ファイルを適用しないでください。適用する前に、このファイルに使用するサービス・アカウントを定義する必要があります。

6. サービス・アカウントを作成する

保護されたリソースにアクセスするには、Kubernetes リソースを作成または変更するためのシークレットを使用するサービス・アカウントをセットアップする必要があります。IBM Cloud Kubernetes Service は、IBM Cloud Identity and Access Management (IAM) のロールを使用するように構成されています。IAM のロールによって、ユーザーが IBM Cloud Kubernetes に対して実行できるアクションが決まります。

API キーを生成する

IBM Cloud ダッシュボードを使用して API キーを生成するには、IBM Cloud のドキュメントで説明している手順に従ってください。あるいは、以下の CLI コマンドを使用して API キーを生成することもできます。

  ibmcloud iam api-key-create MyKey -d "this is my API key" --file key_file.json
  cat key_file.json | grep apikey

apikey をコピーします。次のステップで、このキーを使用します。

シークレットを作成する

シークレットを作成するには、以下のコードを使用します。APIKEY は前の手順で生成した API キー、REGISTRY はクラスターのレジストリー API エンドポイントです。この例でのエンドポイントは、us.icr.io となります。

  kubectl create secret generic ibm-cr-secret --type="kubernetes.io/basic-auth" --from-literal=username=iamapikey --from-literal=password=<APIKEY>

  kubectl annotate secret ibm-cr-secret tekton.dev/docker-0=<REGISTRY>

このコードによって、ibm-cr-secret という名前のシークレットが作成されます。サービス・アカウントの構成ファイル内で、このシークレットを使用します。

構成ファイル tekton-pipeline/pipeline/service-account.yaml の内容は以下のとおりです。

  • ServiceAccount リソースはシークレット ibm-cr-secret を使用します。
  • シークレット・リソースの定義に従い、新しく作成されたシークレットがサービス・アカウントの API トークンに取り込まれます。

次のステップは、ロールを定義することです。1 つの名前空間内に限って、ロールを使用してリソースに対するアクセス権限を付与できます。ルール内に適切なリソースと apiGroup を含めておかないと アクセスで問題が発生して失敗します。ロール・バインディングにより、ロール内に定義された権限がユーザーまたはユーザーのグループに付与されます。ロール・バインディングには、対象 (ユーザー、グループ、またはサービス・アカウント) のリストと付与するロールへの参照が保持されます。

以下のコマンドを使用して、このファイルをクラスターに適用します。

  kubectl apply -f pipeline/service-account.yaml

7. パイプラインを実行する

PipelineRun を実行する前に、tekton-pipeline/pipeline/pipelinerun.yaml 内の imageUrlimageTag を更新する必要があります。上記のデプロイ・ターゲットをセットアップするセクションを参照して、イメージの URL とタグを確認してください。イメージの URL が us.icr.io/test_namespace/sampleapp で、イメージのタグが 1.0 の場合、構成ファイルを以下のように更新します。

  sed -i '' s#IMAGE_URL#us.icr.io/test_namespace/sampleapp# pipeline/pipelinerun.yaml
  sed -i '' s#IMAGE_TAG#1.0# pipeline/pipelinerun.yaml

次は、以下のコマンドを使用して PipelineRun 構成を作成します。

  kubectl create -f pipeline/pipeline-run.yaml

これにより、パイプラインが作成されて、ターミナル上に以下のメッセージが表示されます。

  pipelinerun.tekton.dev/application-pipeline-run created

新しいパイプラインのステータスを確認します。

  kubectl describe pipelinerun application-pipeline-run

ステータスによっては、上記のコマンドを再実行する必要があります。出力には暫定的ステータスが以下のように示されます。

Status:
  Conditions:
    Last Transition Time:  2020-07-09T08:43:53Z
    Message:               Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 2, Skipped: 0
    Reason:                Running
    Status:                Unknown
    Type:                  Succeeded

   ...
   ...
Events:
   Type     Reason     Age     From     Message
   ----     ------     ---     ----     -------
   Normal Started 33s PipelineRun
   Normal Running 33s PipelineRun Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 2, Skipped: 0

「Tasks Completed: 0」と示しているメッセージに注目してください。

パイプラインの実行が完了すると、describe コマンドの出力として以下の結果が表示されます。

Events:
   Type     Reason     Age     From     Message
   ----     ------     ---     ----     -------
   Normal Started 2m33s PipelineRun
   Normal Running 2m33s PipelineRun Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 2, Skipped: 0
   Normal Running 57s   PipelineRun Tasks Completed: 1 (Failed: 0, Cancelled 0), Incomplete: 1, Skipped: 0
   Normal Succeeded 43s PipelineRun Tasks Completed: 2 (Failed: 0, Cancelled 0), Skipped: 0

失敗した場合は、どの Task が失敗したのかが示されます。また、ログを確認するための追加情報も示されます。リソースの詳細 (パイプラインなど) を確認するには、kubectl describe コマンドを使用して追加情報を取得します。

  kubectl describe <resource> <resource-name>

8. 結果を確認する

ポッドとサービスが正常に実行されているかどうかを確認するには、以下のコマンドを実行して、その出力を調べます。

  kubectl get pods
  # Output should be something like this
    NAME                                                                READY   STATUS      RESTARTS   AGE
    app-59dff7b655-7ggbt                                                1/1     Running     0          81s
    application-pipeline-run-build-image-from-source-2m62g-pod-f4eb96   0/3     Completed   0          119s
    application-pipeline-run-deploy-application-kg2jm-pod-89f884        0/3     Completed   0          89s

  kubectl get service
  # Output
    NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
    app          NodePort    xxx.xx.xx.xxx   <none>        3300:32426/TCP   4m51s

PipelineRun の実行が正常に完了した後、アプリケーションに http://<public-ip-of-kubernetes-cluster>:32426/ でアクセスして、IBM Cloud ダッシュボードから Kubernetes クラスターのパブリック IP を取得できます。ポート 32426 は、deploy.yaml 内で nodePort として定義されています。

お疲れさまでした!Tekton Pipelines を使用してアプリケーションを正常にデプロイできました。この手順を通して、Tekton Pipelines の基礎と独自のパイプラインの構築を開始する方法を理解できたはずです。Webhook や Web ベースのダッシュボードなど、利用できる機能は他にもさまざまにあるので、ぜひ、IBM Cloud Kubernetes Service を試して確認してください。

次のステップ

このチュートリアルでは、アプリケーションを Kubernetes にデプロイする手段として Tekton Pipelines を使用する方法とその理由を説明しました。 Tekton は IBM Cloud Pak for Applications に組み込まれています。このオファリングは、コンテナー対応の環境内にビジネス・アプリケーションを迅速かつセキュアに移行する手段となります。Cloud Pak for Applications は Red Hat OpenShift をベースに構築され、Red Hat OpenShift でサポートされています。この開発者向けガイドを参考に、Cloud Pak for Applications の詳細を探って試してみてください。