Appearance
CI/CD Adapterを作成し、アプリケーションのヘルスチェックをする
本チュートリアルでは、Qmonus Value Streamを使って、CI/CD Adapterを作成してCI/CDパイプラインを追加する手順を解説します。 実施する前に、Infrastructure Adapterをカスタマイズし、機能を追加するのチュートリアルが完了していることをご確認ください。
以下のステップを通して、CI/CD Adapterを作成し、パイプラインが実行できることを確認していきます。
- TektonのTask 定義と Pipeline 定義を記述したCI/CD Adapterを作成します。
- QVS Configに作成した CI/CD Adapterを組み込みます。
- AssemblyLineにパイプラインを追加し、実行して動作を確認します。
1. CI/CD Adapterの作成(CLI)
本チュートリアルでは、デプロイ後のアプリケーションに対してヘルスチェックを実施するCI/CD Adapterを作成します。 このCI/CD Adapterは、flask-demoアプリケーションをデプロイするAssemblyLineにてdeployのフェーズ後に実行されます。
作成するCI/CD Adapterは、以下の2つのTekton Pipelineと、それらを構成するTask定義から成り立ちます。
resolveIPAddressPipeline: デプロイしたアプリケーションのIngressに割り当てられたグローバルIPアドレスを取得するパイプラインcurlHealthCheckPipeline: 取得したIPアドレスに対してcurlコマンドを使ってヘルスチェックを実施するパイプライン
以下のような手順にて、各Task定義とPipeline定義を順番に作成していきます。 CI/CD AdapterにおけるTekton PipelineとTaskの定義について詳しくは、CI/CD Adapter Specificationを参照してください。
Task定義の作成
まずは、kubectlコマンドを使ってIngressに割り当てられているグローバルIPアドレスを取得するTask定義を作成します。
Task定義用のフォルダを作成後に、package名をresolveIPAddressTaskとしたTask定義を用意して、パイプライン内でIngressのIPアドレスを取得するコマンドを以下のような内容で作成します。
bash
# ローカルリポジトリへ移動
cd <repository name>
# 本チュートリアル用のブランチをmainブランチから作成
git switch -c create-cicd-adapter main
# .valuestreamディレクトリに移動
cd .valuestream
# CI/CD Adapter Task定義用ディレクトリを作成する
mkdir -p pipeline/tasks
# IngressのIPアドレス取得のTask定義を作成する
vim pipeline/tasks/resolveIPAddressTask.cuego
package resolveIPAddressTask
import (
"qmonus.net/adapter/official/pipeline/schema"
)
#Builder: schema.#TaskBuilder
#Builder: {
name: "resolve-ip-address"
params: { // Qmonus Value StreamのDeployment・Deployment Configからパラメータを受け取るためのParam名
appName: desc: "Application Name of QmonusVS"
k8sNamespace: desc: "Namespace of a deploy resource"
kubeconfigSecretName: desc: "The secret name of Kubeconfig"
}
results: {
ipAddress: { // Tekton内の処理結果を外部に返すためのResult名
description: "External IP Address"
}
}
steps: [{
name: "resolve-external-ip-address" // Tekton TaskのStep名
image: "gcr.io/cloud-builders/kubectl" // kubectlコマンドが実行できるコンテナイメージ
script: """
#!/usr/bin/env sh
# Ingressリソースから割り当てられたIPアドレスを取得し、Resultsに保存
kubectl -n $(params.k8sNamespace) --kubeconfig $KUBECONFIG get ingress $(params.appName) -o=jsonpath='{.status.loadBalancer.ingress[0].ip}' | tee tekton/results/ipAddress
"""
env: [
{
name: "KUBECONFIG"
value: "/secret/kubeconfig"
}]
volumeMounts: [
{
mountPath: "/secret"
name: "user-kubeconfig"
readOnly: true
},
]
}]
volumes: [
{
name: "user-kubeconfig"
secret: {
items: [{
key: "kubeconfig"
path: "kubeconfig"
}]
secretName: "$(params.kubeconfigSecretName)"
}
},
]
}kubeconfig について
上記の Task 定義では、Kubernetes クラスタへのアクセスに必要な kubeconfig を Secret としてマウントしています。 この Secret は、Qmonus Value Stream が Deployment の設定から自動的に作成・管理するため、ユーザが手動で作成する必要はありません。
この kubeconfig をマウントすることで、Task 内で kubectl コマンドを使用して Kubernetes クラスタにアクセスできるようになります。
続いて、package名をcurlHealthCheckTaskとしたTask定義を用意して、パイプライン内でヘルスチェックのコマンドを以下のような内容で作成します。
bash
# ヘルスチェックのTask定義を作成する
vim pipeline/tasks/curlHealthCheckTask.cuego
package curlHealthCheckTask
import (
"qmonus.net/adapter/official/pipeline/schema"
)
#Builder: schema.#TaskBuilder
#Builder: {
name: "curlHealthCheckTask" // Pipeline定義で指定するBuilderスキーマ名
params: { // 外部からパラメータを受け取るためのParam名
ipAddress: desc: "Global IP address of a deploy resource"
}
steps: [{
name: "curl-health-check" // Tekton TaskのStep名
image: "curlimages/curl" // curlコマンドが実行できるコンテナイメージ
script: """
#!/usr/bin/env sh
# /healthエンドポイントにHTTPリクエストを送信してアプリケーションの正常性を確認
curl --fail http://$(params.ipAddress)/health
"""
}]
}Pipeline定義の作成
次に、Pipeline定義用のフォルダを作成し、上記のTaskを含むPipeline定義を作成します。 まずは、package名をresolveIPAddressPipelineとしたPipeline定義を用意し、先ほど作成したresolveIPAddressTaskパッケージを指定する内容で作成します。 また、resultsで、Taskの実行結果であるIPアドレスを外部に返すように設定します。
bash
# CI/CD Adapter Pipeline定義用ディレクトリを作成する
mkdir pipeline/sample
# Pipeline定義を作成する
vim pipeline/sample/resolveIPAddressPipeline.cuego
package resolveIPAddressPipeline
import (
"github.com/qmonus/sample/pipeline/tasks:resolveIPAddressTask"
)
DesignPattern: {
name: "sample:resolveIPAddressPipeline" // sampleフォルダ配下のパッケージ名を記載する
pipelines: {
"resolve-ip-address-after-deploy": {
tasks: {
"resolve-ip-address": resolveIPAddressTask.#Builder
}
results: {
"ipAddress": tasks["resolve-ip-address"].results.ipAddress
}
}
}
}続いて、package名をcurlHealthCheckPipelineとしたPipeline定義を用意し、先ほど作成したcurlHealthCheckTaskパッケージを指定する内容で作成します。
bash
# Pipeline定義を作成する
vim pipeline/sample/curlHealthCheckPipeline.cuego
package curlHealthCheckPipeline
import (
"github.com/qmonus/sample/pipeline/tasks:curlHealthCheckTask"
)
DesignPattern: {
name: "sample:curlHealthCheckPipeline" // sampleフォルダ配下のパッケージ名を記載する
pipelines: {
"curl-health-check-after-resolve-ip-address": {
tasks: {
// 先に作ったcurlHealthCheckTaskパッケージの#Builderスキーマを指定する
"curl-health-check": curlHealthCheckTask.#Builder
}
}
}
}この時点でのフォルダ構成は以下のようになります。
<repository name>/
├── .valuestream/
│ ├── cue.mod/
│ │ └── module.cue
│ ├── local/
│ │ ├── flask-app.cue
│ │ └── hpa.cue
│ ├── output/
│ │ ├── manifest.yaml
│ │ └── pipeline.yaml
│ ├── pipeline/
│ │ ├── sample/
│ │ │ ├── curlHealthCheckPipeline.cue
│ │ │ └── resolveIPAddressPipeline.cue
│ │ └── tasks/
│ │ ├── curlHealthCheckTask.cue
│ │ └── resolveIPAddressTask.cue
│ ├── assemblyline-dev.yaml
│ ├── params.json
│ ├── qvs.yaml
│ └── sample-manifests.yaml
├── app.py
├── Dockerfile
└── requirements.txt2. QVS Configの編集(CLI)
作成したCI/CD Adapterを、QVS Config(qvs.yaml)に組み込みます。
bash
# qvs.yamlを編集する
vim qvs.yaml # 以下のdiffのように変更するyaml
params:
- name: k8sNamespace
type: string
- name: imageName
type: string
- name: hpaStatus
type: string
modules:
- name: github.com/qmonus/sample
local:
path: .
- name: qmonus.net/adapter/official
designPatterns:
# Infrastructure Adapter
- pattern: github.com/qmonus/sample/local:flaskapp
params:
k8sNamespace: $(params.k8sNamespace)
imageName: $(params.imageName)
hpaStatus: $(params.hpaStatus)
# CI/CD Adapter
- pattern: qmonus.net/adapter/official/pipeline/build:buildkitGcp
- pattern: qmonus.net/adapter/official/pipeline/deploy:simple
- pattern: github.com/qmonus/sample/pipeline/sample:resolveIPAddressPipeline
- pattern: github.com/qmonus/sample/pipeline/sample:curlHealthCheckPipelineyaml
params:
- name: k8sNamespace
type: string
- name: imageName
type: string
- name: hpaStatus
type: string
modules:
- name: github.com/qmonus/sample
local:
path: .
- name: qmonus.net/adapter/official
designPatterns:
# Infrastructure Adapter
- pattern: github.com/qmonus/sample/local:flaskapp
params:
k8sNamespace: $(params.k8sNamespace)
imageName: $(params.imageName)
hpaStatus: $(params.hpaStatus)
# CI/CD Adapter
- pattern: qmonus.net/adapter/official/pipeline/build:buildkitGcp
- pattern: qmonus.net/adapter/official/pipeline/deploy:simple
- pattern: github.com/qmonus/sample/pipeline/sample:resolveIPAddressPipeline
- pattern: github.com/qmonus/sample/pipeline/sample:curlHealthCheckPipeline3. Pipeline Manifestの生成および登録 (CLI)
作成したCI/CD Adapterを指定したQVS Configから Pipeline Manifestを生成し、Qmonus Value Streamへ登録します。
bash
# CI/CD Adapterをコンパイルする
qvsctl pipeline compile -m . -c qvs.yaml --prefix flask-demo -o output/pipeline.yaml
# qvsctl auth コマンド使用して認証する(出力されたurlへアクセスしてください)
qvsctl auth
# Project Nameを取得する
qvsctl project list
# 取得したProject Nameを環境変数に設定する
export projectName=<PROJECT NAME>
# Tekton Pipeline/Task ManifestをApplyする
qvsctl pipeline apply -p ${projectName} -f output/pipeline.yaml新たに2つのpipelineflask-demo-resolve-ip-address-after-deploy、flask-demo-curl-health-check-after-resolve-ip-addressと2つのtaskflask-demo-resolve-ip-address、flask-demo-curlhealthchecktaskが生成されることを確認してください。
4. AssemblyLineの修正(CLI)
AssemblyLineに、resolve-ip-address、curl-health-checkのStageを定義し、作成したPipelineおよびDeploymentを指定します。 resolve-ip-addressで取得したipAddressは、$(stages.resolve-ip-address.results.ipAddress)としてcurl-health-checkのStageで利用します。 また、resultsにipAddressを追加して、Pipelineの実行結果として確認できるようにします。
bash
# assemblyline-dev.yamlを編集する
vim assemblyline-dev.yamlyaml
apiVersion: vs.axis-dev.io/v1
kind: AssemblyLine
metadata:
name: flask-demo-dev
spec:
params:
- name: gitRevision
type: string
stages:
- name: build
spec:
pipeline: flask-demo-build
deployment:
app: flask-demo
name: flask-demo-dev
params:
- name: gitRevision
value: $(inputs.gitRevision)
- name: deploy
spec:
pipeline: flask-demo-deploy
deployment:
app: flask-demo
name: flask-demo-dev
params:
- name: gitRevision
value: $(inputs.gitRevision)
- name: imageName
value: $(stages.build.results.imageFullNameTag)
runAfter:
- build
- name: resolve-ip-address
spec:
pipeline: flask-demo-resolve-ip-address-after-deploy
deployment:
app: flask-demo
name: flask-demo-dev
runAfter:
- deploy
- name: curl-health-check
spec:
pipeline: flask-demo-curl-health-check-after-resolve-ip-address
deployment:
app: flask-demo
name: flask-demo-dev
params:
- name: ipAddress
value: $(stages.resolve-ip-address.results.ipAddress)
runAfter:
- resolve-ip-address
results:
- name: gitRevision
value: $(inputs.gitRevision)
- name: imageName
value: $(stages.build.results.imageFullNameTag)
- name: ipAddress
value: $(stages.resolve-ip-address.results.ipAddress)
artifacts:
- path: manifestsyaml
apiVersion: vs.axis-dev.io/v1
kind: AssemblyLine
metadata:
name: flask-demo-dev
spec:
params:
- name: gitRevision
type: string
stages:
- name: build
spec:
pipeline: flask-demo-build
deployment:
app: flask-demo
name: flask-demo-dev
params:
- name: gitRevision
value: $(inputs.gitRevision)
- name: deploy
spec:
pipeline: flask-demo-deploy
deployment:
app: flask-demo
name: flask-demo-dev
params:
- name: gitRevision
value: $(inputs.gitRevision)
- name: imageName
value: $(stages.build.results.imageFullNameTag)
runAfter:
- build
- name: resolve-ip-address
spec:
pipeline: flask-demo-resolve-ip-address-after-deploy
deployment:
app: flask-demo
name: flask-demo-dev
runAfter:
- deploy
- name: curl-health-check
spec:
pipeline: flask-demo-curl-health-check-after-resolve-ip-address
deployment:
app: flask-demo
name: flask-demo-dev
params:
- name: ipAddress
value: $(stages.resolve-ip-address.results.ipAddress)
runAfter:
- resolve-ip-address
results:
- name: gitRevision
value: $(inputs.gitRevision)
- name: imageName
value: $(stages.build.results.imageFullNameTag)
- name: ipAddress
value: $(stages.resolve-ip-address.results.ipAddress)
artifacts:
- path: manifests5. AssemblyLineの登録 (CLI)
修正したAssemblyLineをQmonus Value StreamのProjectへ登録します。
bash
# AssemblyLineをApplyして更新する
qvsctl pipeline apply -p ${projectName} -f assemblyline-dev.yamlgit add、 git commit、 git pushを行い、リモートリポジトリに変更を反映します。 またコミットIDをAssemblyLineを実行するときに指定するため控えておきます。
bash
# リモートリポジトリにpushする
git add --all
git commit -m "Add CI/CD Adapter for health check"
git push origin create-cicd-adapter
# コミットIDを控える
git log -16. AssemblyLineの実行(GUI)
編集したAssemblyLineを実行し、CI/CD Adapterによるヘルスチェックが正常に動作することを確認します。
- 左メニューより、AssemblyLineを選択します。
- 画面中央に表示される
flask-demo-devを選択します。 - 以下のInput Parameterを入力し、
RUNボタンを押下してAssemblyLineを実行します。- gitRevision: 手順5でのgit commit時のコミットID
7. ヘルスチェックの結果確認(GUI)
AssemblyLine の実行後、ヘルスチェックが正常に完了したことを確認します。
- 実行したAssemblyLineの詳細画面から、
curl-health-checkステージを選択します。 - Taskの実行ログを確認します。
- 以下のようなログが出力されていれば、ヘルスチェックは成功です。
"status": "healthy"
8. ブランチをマージする
動作確認が完了したら、作業ブランチをmainブランチにマージします。 GitHub の対象リポジトリからマージを実施してください。
- GitHubの対象リポジトリにアクセスします。
- 画面上部の
Pull requestsタブをクリックします。 - create-cicd-adapterブランチのPull Request画面を開きます。
- Pull Request画面で変更内容を確認し、問題がなければ
Merge pull requestボタンをクリックします。 Confirm mergeボタンをクリックしてマージを完了します。- マージ完了後、
Delete branchボタンをクリックして作業ブランチを削除します(任意)。
リソースの削除
チュートリアルで作成したリソースは、QVS Config(qvs.yaml)のInfrastructure Adapterの定義をコメントアウトし、リモートリポジトリに変更を反映したCommit IDでAssemblyLineを実行することで削除できます。(※リソースは削除されますが、curlHealthCheckPipelineのヘルスチェック機能により、Healthcheckのステージは失敗します。)
詳しくは、デプロイしたリソースの削除を参照してください。
解説
本チュートリアルでは、CI/CD Adapterを新たに作成し、Qmonus Value Streamで実行できることを確認しました。 今回作成した CI/CD Adapterでは、curlコマンドを使用してアプリケーションの /health エンドポイントにHTTPリクエストを送信し、ヘルスチェックを実施しました。このように、CI/CD Adapterを使うことで、デプロイ後の動作確認やテストなど、様々なCI/CD処理を自動化できます。
CI/CD Adapterの詳しい仕様については、CI/CD Adapter Specificationを参照してください。
まとめ
本チュートリアルでは、CI/CD Adapterの作成方法を学びました。 これまでのチュートリアルを通じて、以下のことができるようになりました。
- アプリケーションをビルドする
- Infrastructure Adapterを作成し、アプリケーションをデプロイする
- Infrastructure Adapterをカスタマイズし、機能を追加する
- CI/CD Adapterを作成し、アプリケーションのヘルスチェックをする(本チュートリアル)
これらの知識を活用して、独自のアプリケーションを Qmonus Value Streamでデプロイしてみましょう。
また、Qmonus Value Streamでは伴走支援を実施しています。伴走支援をご希望の方はこちらからご連絡ください。