以前の記事では、CI 部分を担う OpenShift Pipelines について解説しました。続いて、本記事では実際に OpenShift Pipelines の CI 部分 を構築したいと思います。
構築の概要
Red Hat のチュートリアルを参考にして図のような CI フローを OpenShift 上に構築します。チュートリアルではパブリックリポジトリを利用していますが、実際構築する際はプライベートリポジトリであるケースが多いため、プライベートリポジトリで構築してみます。CI フローの流れとしては、まず初めにプライベートな Git リポジトリに変更をプッシュした際に EventListener への Webhook がトリガーされます。EventListener は受け取った情報から指定されたパラメータを Trigger Template にバインディングして PipelineRun を実行させます。PipelineRun では最初にリポジトリからソースコードの取得をします。次にソースコードのimage をビルドし、image registry にプッシュしたらフロー終了です。
事前準備
下記構成のプライベートなアプリケーション用Git リポジトリを用意します。アプリケーションの設定や定義をDockerfileとindex.phpで設定し、Kubernetesのリソースはk8sディレクトリ配下にまとめています。
.
├── Dockerfile
├── index.php
└── k8s
├── deployment.yaml
├── route.yaml
└── service.yaml
Dockerfile
FROM image-registry.openshift-image-registry.svc:5000/openshift/php:latest
ADD ./index.php /var/www/html/
CMD ["php","-S","0.0.0.0:8080","-t","/var/www/html"]
index.php
Hello world!
k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ocp-cicd-appli-ui
name: ocp-cicd-appli-ui
spec:
replicas: 1
selector:
matchLabels:
app: ocp-cicd-appli-ui
template:
metadata:
labels:
app: ocp-cicd-appli-ui
spec:
containers:
- image: image-registry.openshift-image-registry.svc:5000/pipelines-tutorial/ocp-cicd-appli-ui
imagePullPolicy: Always
name: ocp-cicd-appli-ui
ports:
- containerPort: 8080
protocol: TCP
k8s/route.yaml
apiVersion: route.openshift.io/v1
kind: Route
metadata:
labels:
app: ocp-cicd-appli-ui
name: ocp-cicd-appli-ui
spec:
port:
targetPort: 8080-tcp
to:
kind: Service
name: ocp-cicd-appli-ui
weight: 100
k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: ocp-cicd-appli-ui
name: ocp-cicd-appli-ui
spec:
type: NodePort
ports:
- name: 8080-tcp
port: 8080
targetPort: 8080
protocol: TCP
selector:
app: ocp-cicd-appli-ui
前提条件
- OpenShift クラスターが構築済みであること
- oc CLI がインストール済みであること
- tkn CLI がインストール済みであること
- プライベートな Git リポジトリにssh設定がされており、対となる秘密鍵を持っていること
- リポジトリ名に”_”が含まれていないこと(“_”が含まれているとPipelineRunリソースが正常に作成できない点に注意)
OpenShift Pipelines をインストール
- OpenShift OperatorHub で Administrator のパースペクティブにいることを確認します。
- Web コンソールで[Operators] > [OperatorHub]に移動します。
- 検索バーに「OpenShift Pipelines」と入力して、 OpenShift Pipelines をクリックして Install をクリックします。
- デフォルトのまま Install をクリックします。
パイプラインを作成
図の赤枠部分を作成していきます。
サンプルアプリケーションをデプロイ
新規プロジェクトを作成します。
$ oc new-project pipelines-tutorial
Now using project "pipelines-tutorial" on server "URL".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.43 -- /agnhost serve-hostname
ssh接続情報の作成
プライベートな Git リポジトリに接続するためのシークレットを作成します。
$ oc apply -f secret.yaml
secret/ssh-credential created
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: ssh-credential
data:
id_rsa: # cat ~/.ssh/id_rsa | base64 で表示された内容を記入(一行で記述すること)
pipeline サービスアカウントを確認
パイプラインを実行するサービスアカウントが存在しているか確認します。
$ oc get serviceaccount pipeline
NAME SECRETS AGE
pipeline 1 102s
タスクをインストール(実行確認のためのCD部分のタスク)
タスクを作成します。これは実行確認のための CD 部分のタスクとなり、続編のCD部分を実装する際は実行しないでください。
$ oc create -f apply_manifest_task.yaml
task.tekton.dev/apply-manifests created
$ oc create -f update_deployment_task.yaml
task.tekton.dev/update-deployment created
apply_manifest_task.yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: apply-manifests
spec:
workspaces:
- name: source
params:
- name: manifest_dir
description: The directory in source that contains yaml manifests
type: string
default: "k8s"
steps:
- name: apply
image: image-registry.openshift-image-registry.svc:5000/openshift/cli:latest
workingDir: /workspace/source
command: ["/bin/bash", "-c"]
args:
- |-
echo Applying manifests in $(inputs.params.manifest_dir) directory
oc apply -f $(inputs.params.manifest_dir)
echo -----------------------------------
update_deployment_task.yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: update-deployment
spec:
params:
- name: deployment
description: The name of the deployment patch the image
type: string
- name: IMAGE
description: Location of image to be patched with
type: string
steps:
- name: patch
image: image-registry.openshift-image-registry.svc:5000/openshift/cli:latest
command: ["/bin/bash", "-c"]
args:
- |-
oc patch deployment $(inputs.params.deployment) --patch='{"spec":{"template":{"spec":{
"containers":[{
"name": "$(inputs.params.deployment)",
"image":"$(inputs.params.IMAGE)"
}]
}}}}'
patched_at_timestamp=`date +%s`
oc patch deployment $(inputs.params.deployment) --patch='{"spec":{"template":{"metadata":{
"labels":{
"patched_at": '\"$patched_at_timestamp\"'
}
}}}}'
作成したタスクを確認
タスクが作成されていることを確認します。
$ tkn task ls
NAME DESCRIPTION AGE
apply-manifests 6 minutes ago
update-deployment 6 minutes ago
パイプラインを作成
パイプラインを作成します。
$ oc create -f pipeline.yaml
pipeline.tekton.dev/build-and-deploy created
pipeline.yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: build-and-deploy
spec:
workspaces:
- name: shared-workspace
- name: ssh-creds
params:
- name: deployment-name
type: string
description: name of the deployment to be patched
- name: git-url
type: string
description: url of the git repo for the code of deployment
- name: git-revision
type: string
description: revision to be used from repo of the code for deployment
default: main
- name: IMAGE
type: string
description: image to be build from the code
tasks:
- name: fetch-repository
taskRef:
name: git-clone
kind: ClusterTask
workspaces:
- name: output
workspace: shared-workspace
- name: ssh-directory
workspace: ssh-creds
params:
- name: url
value: $(params.git-url)
- name: subdirectory
value: ""
- name: deleteExisting
value: "true"
- name: revision
value: $(params.git-revision)
- name: build-image
taskRef:
name: buildah
kind: ClusterTask
params:
- name: IMAGE
value: $(params.IMAGE)
workspaces:
- name: source
workspace: shared-workspace
runAfter:
- fetch-repository
# 以下CD部分のタスクのため、続編のCD部分を実装する際は記入しないこと
- name: apply-manifests
taskRef:
name: apply-manifests
workspaces:
- name: source
workspace: shared-workspace
runAfter:
- build-image
- name: update-deployment
taskRef:
name: update-deployment
params:
- name: deployment
value: $(params.deployment-name)
- name: IMAGE
value: $(params.IMAGE)
runAfter:
- apply-manifests
作成したパイプラインを確認
パイプラインが作成されていることを確認します。
$ tkn pipeline ls
NAME AGE LAST RUN STARTED DURATION STATUS
build-and-deploy 2 minutes ago --- --- --- ---
パイプラインを手動実行
作成したパイプラインを手動で実行して動作を確認します。
$ tkn pipeline start build-and-deploy \
--prefix-name build-deploy-ui-pipelinerun \
-w name=shared-workspace,volumeClaimTemplateFile=persistent_volume_claim.yaml \
-w name=ssh-creds,secret=ssh-credential \
-p deployment-name=ocp-cicd-appli-ui \
-p git-url=<リポジトリ名:git@xxx:xxx/xxx.gitの形式> \
-p IMAGE=image-registry.openshift-image-registry.svc:5000/pipelines-tutorial/ocp-cicd-appli-ui \
--use-param-defaults
PipelineRun started: build-deploy-ui-pipelinerun-ngnjn
In order to track the PipelineRun progress run:
tkn pipelinerun logs build-deploy-ui-pipelinerun-ngnjn -f -n pipelines-tutorial
persistent_volume_claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: source-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
Pipelinesを確認するとPipelineが実行中になっています。
Pipeline run を確認するとパイプラインの実行ログなどを確認することが出来ます。Succeeded になっていることを確認します。
アプリケーションのルートを取得
デプロイしたアプリケーションのルートを取得して正しくデプロイされていることを確認します。
$ oc get route ocp-cicd-appli-ui --template='http://{{.spec.host}}'
<アプリケーションのURL>
トリガーを作成
図の赤枠部分を作成していきます。
テンプレートの適用
トリガーテンプレートを作成します。
$ oc create -f triggertemplate.yaml
triggertemplate.triggers.tekton.dev/sample-app created
triggertemplate.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: sample-app
spec:
params:
- name: git-repo-url
description: The git repository url
- name: git-revision
description: The git revision
default: main
- name: git-repo-name
description: The name of the deployment to be created / patched
resourcetemplates:
- apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: build-deploy-$(tt.params.git-repo-name)
spec:
taskRunTemplate:
serviceAccountName: pipeline
pipelineRef:
name: build-and-deploy
params:
- name: deployment-name
value: $(tt.params.git-repo-name)
- name: git-url
value: $(tt.params.git-repo-url)
- name: git-revision
value: $(tt.params.git-revision)
- name: IMAGE
value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/$(tt.params.git-repo-name):$(tt.params.git-revision)
# Pipelineで実行結果確認のCD部分を実装する場合はコミットIDを参照しないため下記に置き換える
# value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/$(tt.params.git-repo-name)
workspaces:
- name: shared-workspace
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
- name: ssh-creds
secret:
secretName: ssh-credential
バインディングの適用
トリガーバインディングを作成します。
$ oc create -f triggerbinding.yaml
triggerbinding.triggers.tekton.dev/sample-app created
triggerbinding.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
name: sample-app
spec:
params:
- name: git-repo-url
# privateリポジトリのためssh_urlを参照
value: $(body.repository.ssh_url)
- name: git-repo-name
value: $(body.repository.name)
- name: git-revision
value: $(body.head_commit.id)
トリガーの適用
トリガーを適用します。webhookのsecretも作成するため、後程トークンの値を使います。
$ oc create -f trigger.yaml
trigger.triggers.tekton.dev/sample-trigger created
secret/github-secret created
trigger.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: Trigger
metadata:
# event_listenerで参照するTrigger名
name: sample-trigger
spec:
serviceAccountName: pipeline
interceptors:
- ref:
name: "github"
params:
- name: "secretRef"
value:
secretName: github-secret
secretKey: secretToken
- name: "eventTypes"
value: ["push"]
bindings:
- ref: sample-app
template:
ref: sample-app
---
apiVersion: v1
kind: Secret
metadata:
name: github-secret
type: Opaque
stringData:
# webhookのシークレット
secretToken: "1234567"
EventListenerの作成
EventListenerを作成します。
$ oc create -f event_listener.yaml
eventlistener.triggers.tekton.dev/sample-app created
event_listener.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: sample-app
spec:
serviceAccountName: pipeline
triggers:
# webhookをインターセプトするTrigger名を参照
- triggerRef: sample-trigger
EventListener サービスをルートとして公開
EventListener サービスをルートとして公開します。
$ oc expose svc el-sample-app
route.route.openshift.io/el-sample-app exposed
webhook-url を取得
webhook-url を取得を取得します。取得したURLはGit リポジトリのwebhook設定に使用します。
$ echo "URL: $(oc get route el-sample-app --template='http://{{.spec.host}}')"
URL: <webhook-url>
Webhookを手動設定する
Git リポジトリにWebhookを設定します。
- GitHubのリポジトリを開きます。
- Settings > Hook > Add Webhook をクリックします。
- payload URL に webhook-url を追加 > コンテンツタイプをapplication/jsonに選択 > シークレットを追加 例:1234567 > Add Webhook をクリックして設定完了です。
パイプライン実行テスト
Git リポジトリの index.php に適当な変更を加え、コミットを Git リポジトリにプッシュします。
git add .
git commit -m "hogehoge"
git push
OpenShift WebConsole Developer パースペクティブを見ると、PipelineRun が自動的に作成されます。
Succeeded になっていることを確認します。
続いて、アプリケーションに加えた変更が反映されていることを確認して完了です。
まとめ
本記事では実際に Red Hat のチュートリアルを参考にしてOpenShift Pipelines の CI 部分を構築してみました。実行確認のために CD 部分を実装しましたが、これはマニフェストファイルを適用しただけの push 型のデプロイでした。次回は CD 部分となる OpenShift GitOps を構築して デプロイ先の状態変化を検知してマニフェストファイルの状態を保ち続ける pull 型のデプロイを実装してみます。