こんにちは、Red Hatでソリューションアーキテクトをしている石川です。
前回の記事ではクラウドネイティブなCI/CDを実現するOpenShift Pipelinesの機能のうち、パイプライン構築のためのコンポーネントであるTekton Pipelinesに焦点を挙げ、その概要をご紹介させて頂きました。 今回の記事では、Tekton Triggersという仕組みを使い、構築したパイプラインを開発の一連の流れの中で自動的に実行する方法をご紹介したいと思います。 Tekton TriggersはTekton Pipelinesと同様に、OpenShift Pipelines Operatorをインストールすることですぐに使い始めることが出来ます。
ユースケース
Tekton Triggersについての説明に入る前にユースケースについておさらいしたいと思います。 前回の記事では、開発者が自身の作業用ブランチからメインブランチに対しプルリクエストを行い、それが承認されたタイミング(merge commitが作成されたタイミング)で、アプリケーションの静的診断、コンテナイメージの作成、レジストリへのプッシュなどを自動的に実施するというパイプラインを考えました。
Tekton Pipelinesでは実行する個々のアクションをTask、それらの実行順を定義するものとしてPipelineというカスタムリソースを作成しました。 これに対しTekton Triggersは開発者のGitへのアクションを契機に、定義されたPipelineを、文字通りトリガーし実行する役割を担っています。
上の図を違う角度から見てみましょう。 GitHubやGitlabなど、一般的なGitリポジトリでは開発者のアクションに応じてWebhookを設定することが出来ます。このWebhookを受け取り、定義されたPipelineを実行するためのPipelineRunリソースを作成するのがTekton Triggersとなります。
Tekton Triggersで登場する概念
Tekton Triggersでは以下の3つカスタムリソースを使用することで上記の動きを実現しています。
TriggerTemplate: Webhookを受け取った際に作成するリソース(PipelineRun、TaskRun、等)の定義
TriggerBinding: 受け取ったWebhookのヘッダーやボディ部からPipelineRunに渡すパラメータの定義
EventListner: Webhookの受け口(Service+Pod)の作成と、使用するTriggerTemplate/TriggerBindingの指定
それぞれの関係性を表すと以下のような図になります。
GitリポジトリからのWebhookはEventListnerが作成したServiceを経由して、同じく作成されたPodが受け取ります。このPodはTriggerBindingの中で定義された通りに受信したWebhookのJSONを加工し必要なパラメータを抜き出すと共に、TriggerTemplateで指定されたリソース(PipelineRun)を作成します。
カスタムリソースの作成
ここからは実際に使用されるカスタムリソースを作成していきたいと思います。 まず初めにTriggerBindingでWebhookから受け取る情報を定義します。
TriggerBinding
apiVersion: triggers.tekton.dev/v1alpha1 kind: TriggerBinding metadata: name: test-trigger-binding spec: params: - name: gitrevision value: $(body.head_commit.id) - name: gitrepositoryurl value: $(body.repository.url)
TriggerBindingでは上記のように、spec.params
以下でWebhookから受け取った情報のうち、何をこの後のステップで利用していくかを定義します。
Webhookからどのような形でデータが受け渡されるかについては、使用するGitリポジトリによって異なりますが、例えばGitHubの場合こちらのページからイベント種類ごとの内容を確認することが出来るので参考にしてみて下さい。
TriggerTemplate
apiVersion: triggers.tekton.dev/v1alpha1 kind: TriggerTemplate metadata: name: test-pipeline-template spec: params: - name: gitrevision description: The git revision default: master - name: gitrepositoryurl description: The git repository url resourcetemplates: - apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: generateName: test-run- spec: pipelineRef: name: test-pipeline params: - name: url value: $(tt.params.gitrepositoryurl) - name: SONAR_HOST_URL value: 'http://sonarqube:9000' - name: SONAR_PROJECT_KEY value: 'test-project' - name: IMAGE value: 'jpishikawa/mkdocs-test' workspaces: - name: shared-workspace volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi - name: sonar-settings emptyDir: {}
続いてTriggerTemplateです。
spec.params
にはTriggerBindingで定義したパラメータの情報を記載し、spec.resourcetemplates
以下でWebhookを受けた際に作成するリソースの情報を記載します。上記の例ではkind: PipelineRun
のリソースを作成するようにしていますが、単一のTaskだけを動かしたい場合などはTaskRunを設定することも可能となります。
EventListner
apiVersion: triggers.tekton.dev/v1alpha1 kind: EventListener metadata: name: test-event-listener spec: serviceAccountName: sample-sa triggers: - bindings: - ref: test-trigger-binding template: ref: test-pipeline-template interceptors: - github: secretRef: secretName: github-webhook secretKey: webhook-secret eventTypes: - push - cel: filter: "body.ref == \"refs/heads/master\""
最後にEventListnerです。
これまで作成したTriggerBinding、TriggerTemplateを参照するよう、spec.triggers
以下に記述します。
spec.triggers[].interceptors
という項目では、Webhookに設定された値を検証し、条件を満たさない場合PipelineRunを作成しないというフィルタリングの設定を行っています。上記の例ではWebhookのシークレットを使った送信元リポジトリの認証を行い、トリガー実行をmasterブランチへのpushイベントに対してのみ制限しています。
EventListnerではServiceAccountの設定が必須となっています。前述の通り、EventListnerはTriggerTemplateで指定したリソースを作成することになるため、以下のように必要な権限を持ったService Accountを作成します。
apiVersion: v1 kind: ServiceAccount metadata: name: sample-sa secrets: - name: github-webhook --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: sample-role rules: - apiGroups: - triggers.tekton.dev resources: - eventlisteners - triggers - triggerbindings - triggertemplates verbs: - get - list - watch # PipelineRunを作成可能な権限を付与 - apiGroups: - tekton.dev resources: - pipelineruns verbs: - create - apiGroups: - "" resources: - configmaps verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: sample-role-binding subjects: - kind: ServiceAccount name: sample-sa roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: sample-role
ここまででTrigerBinding、TriggerTemplate、EventListnerのマニフェストを作成出来ました。
実際にこれらを実行してみると、Webhookを受けるためのEventListnerのService、Podの作成を確認することが出来ます。
❯ oc get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE el-test-event-listener ClusterIP 172.30.244.201 <none> 8080/TCP 4m48s ❯ oc get pod NAME READY STATUS RESTARTS AGE el-test-event-listener-58dd7f786c-ql5dz 1/1 Running 0 4m33s
一点注意するポイントとして、Serviceはtype: ClusterIP
として作成されるため、デフォルトではクラスター外部からの通信を受け付けることが出来ません。GitHubなど外部からのWebhookを受け付ける場合にはoc expose
などのコマンドを実行しエンドポイントを作成してあげましょう。
❯ oc get route NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD el-test-event-listener el-test-event-listener-cicd.apps.mycluster.193b.sandbox80.opentlc.com el-test-event-listener http-listener None
これでEventListnerがGitリポジトリのWebhookを受け付ける準備が完了しました。
Webhookの設定
次にGitリポジトリ側でWebhookの設定をしましょう。 今回はGitHubで設定を行いたいと思います。 Webhookを設定したいGitHubのリポジトリにアクセスし、"Settings"→"Webhooks"から新規のWebhookを設定します。
Payload URLには先ほど作成したWebhookのエンドポイントのURLを設定、Content typeをapplication/json
、Secretには認証に使用するシークレットキーを入力します。
今回はpushイベントを対象としWebhookを作成しますが、より詳細な設定を行うことも可能です。
Pipelineの実行
ここまででGitのpushイベントに応じてPipelineを実行する準備が整いました。 最後に実際に新規のcommitを作成し、正しくPipelineが動くか確認してみましょう。
リポジトリ上で新規ファイルを作成するなどの操作を行い新規のcommitを作成すると、それに応じて先ほど設定したWebhookが作成されます。 作成されたWebhookの履歴は設定画面から確認出来ます。
これまでの設定が正しく行われていればTekton Triggersにより新たなPipelineRunが作成されます。 OpenShiftのコンソールを見ると新たなPipelineRunが作成され、Pipelineが実行されていることを確認することが出来ます。
これでGitのアクションからPipeline実行までの一連の動きについて確認することが出来ました。
まとめ
前回から2回に分けてOpenShift Pipelinesについての内容をご紹介しました。
昨今では開発を高速に、かつセキュアにしていくためにはCI/CDによる自動化の仕組みが不可欠となっています。Tektonには複数のカスタムリソースが存在するため、初めは取っ付きづらさを感じるかもしれませんが、一つ一つの役割を理解すると、シンプルで拡張性を持ったパイプラインを構築することが出来るということが理解出来たのではないでしょうか。 皆さんも是非OpenShift Pipelinesを使ったCI/CDパイプラインの構築にチャレンジしてみて下さい。