はじめに
こんにちは、NADPの原木と申します。今回はOpenShift上でCI/CDを実現できるOpenShift Pipelinesについて、実際に利用するときにあたって疑問に感じたり、問題を解決するために実施した内容を説明したいと思います。
OpenShift Pipelineとは?
OpenShift Pipelinesは、Tektonをベースとしたビルドパイプラインを作成するためのクラウドネイティブなCI/CDソリューションです。Tekton自体は、元々はKubernetesにサーバーレス環境をもたらすKnativeのビルドツール Knative Build を出自としています。その後、スピンアウトして独立したOSSプロジェクトになりました。
英語ではありますが、OpenShift Pipelinesに関して全体感を掴みつつ、すぐに実践したい場合、下記のRed Hat技術ブログやKatacodaと呼ばれる実践型のe-learningが大いに参考になります。
◇Red Hatの技術ブログ
Guide to OpenShift Pipeliness Part 1 – Introducing OpenShift Pipeliness
※Part 5まであります
◇katacodaの実践
Getting Started with OpenShift Pipelines
(参照元URLは現在利用できなくなっております。)
これらのステップを終えた後、実践的な内容を構築したい場合、大抵はさらに覚えなくてはいけないことが多いでしょう。
例えば、このようなサンプルだと必ずOSSでgit cloneする分にはパスワードは必要ないですが、業務アプリケーションのソースコードは通常プライベートなリポジトリサーバーにあります。そこへのアクセスに必要な認証情報やプロキシ情報は普段、使用することが多いにもかかわらず、大抵のOSSではとても分かりづらい場所に設定に関するドキュメントが転がっていたりします。OpenShift Pipelinesにおいてもそういったギャップは多数ありました。
今回のブログではOpenShift Pipelinesのよくあるサンプルを業務アプリケーション用の開発環境に当てはめようとして躓いたこと、気づいたことを改めて説明したいと思います。
ソースコード
openshift-handson-manifests-for-website
実際に動かしてみて得られた気づき
1. サンプルを参考にすると非常に早く作業が終わる。ただし、作り方と作られた時期に注意

今回のデモ環境ではチュートリアルサイトで説明されていた内容を組み合わせることで上記スライドのパイプラインを比較的短時間で構築することができました。
・https://github.com/IBM/tekton-tutorial/tree/master/tekton – Connect to preview
・speed-up-maven-builds-in-tekton-pipelines/
IBM, Red Hatの公式チュートリアルのリポジトリになります。
最初から詳しく説明されていた内容が、ちょうど弊社でやろうとしていたモダナイゼーションプロジェクトでのCI/CDパイプラインで求めるものと多くの点で似ており、スクラッチでパイプラインを構築するより品質担保の面で参考になりました。
ただし、OpenShift Pipelines(Tekton)自体が進化の早いプロダクトであり、デモ環境構築時はバージョンがv1alpha1からv1beta1への移行期にありました。
参考にしているAPIに関してはdeprecatedなものはなるべく使用せずに、公式ドキュメントやGitHub上のリファレンス情報を参照する必要がありました。
今扱っているAPIのバージョンがリファレンスとあっているかという確認は今後もOpenShift Pipelines(Tekton)全般に言えると思います。
2. シークレットトークンとロール管理

アプリケーションのソースコードはOSSではない場合、通常は限られたユーザーしかアクセスできないように鍵付きで管理していると思います。
また、OpenShift上から色々なリソースにアクセスするためにTekton自体にロールを割り振って適切なアクセス管理をコントロールしたいといった要望も出てくると思います。
それらを一石二鳥で解決する手段として、OpenShift Pipelinesでは ServiceAccountを使用した、きめ細かな制御が可能です。
デモで実際に使用したマニフェストファイルを紐解きながら、どうやってOpenShift Pipelinesからシークレットトークンを読み込むのか説明したいと思います。
---
apiVersion: v1
kind: Secret
metadata:
name: github-sec
namespace: handson-demo
annotations:
tekton.dev/git-0: https://github.com (1)
type: kubernetes.io/basic-auth
stringData:
username: UUU
password: PPP
---
apiVersion: v1
kind: Secret
metadata:
name: cr-sec
namespace: handson-demo
annotations:
tekton.dev/docker-0: quay.io (2)
type: kubernetes.io/basic-auth
stringData:
username: UUU
password: PPP
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
namespace: handson-demo
secrets:
- name: github-sec (3)
- name: cr-sec
上記のリソースファイルをデプロイすることで、ServiceAccount、 Secret リソースを作成できます。
(1) GitHubのプライベートリポジトリサーバーからソースコードをcloneするために、ユーザーのID/パスワードを登録します。GitHubはCI/CD用のサービスアカウントを用意していないため、実ユーザー、もしくはbot専用のアカウントのIDを利用する必要があります。
CRDファイルのアノテーションにドメイン情報か書き込むことで、Tekton内部で処理が分かれます。
設定情報は下記のドキュメントにあります。
(2) QuayコンテナレジストリサーバーのユーザーID/パスワードを登録します。こちらも他のコンテナレジストリサーバーに関する認証などバリエーション情報は上記ドキュメントを参照してください。
(3) ServiceAccountに先ほど登録したSecret情報を紐づけます。
今回は割愛させていただきますが、ロールバインドの設定もこのサービスアカウントに対して行います。
OpenShift Pipelinesが動いているnamespaceと、CI/CD環境で利用するステージング環境、
本番環境は違うnamespaceの場合は多いと思うので、適切な管理が必要でしょう。
✽ PipelineRunへのServiceAccountは2020年5月にdeprecatedになりました。taskServiceAccountNameという、Pipelineより細かい粒度の処置に対して制御が可能な設定値が追加されたためです。詳細は下記をご覧ください。
--- apiVersion: tekton.dev/v1alpha1 kind: PipelineRun metadata: generateName: openshift-handson-apps-build-run- namespace: handson-demo spec: serviceAccountName: build-bot(4) (略)
(4) 作成した ServiceAccountは PipelineRun リソースに埋め込むことで、git clone時に、自動的にシークレットトークンなどを取得するようになります。
3. 開発時のビルドで使用するライブラリはストレージ上に保存する

OpenShift Pipelinesでは、git cloneしたソースコードやmavenや go get コマンドで落としてきたライブラリはPVCでマウントしたストレージ上に保存します。
OpenShift Pipelinesは動作環境がコンテナで構成されており、動かすたびにコンテナは作り直されます。その際にコンテナ上に置いた情報は、全て消されてしまいます。
リリース用の成果物を作成するときなど、消し忘れのtmpファイルなど入れたくない場合は環境はまっさらの方がいいでしょう。しかし、通常の開発時にCI/CDを回したい場合、ビルドするたびにライブラリを取得していてはどうしても遅くなります。キャッシュサーバーを間に挟んでいても、ダウンロードする時間は馬鹿にできません。
そこで、データを次のCI/CDにも使いまわせるようにワークスペースをマウントしたストレージ上に作成します。
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: local-source-pvc (1)
labels:
type: local
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: maven-repo-pvc
labels:
type: local
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
(1) PersistentVolumeClaimとして、local-source とmaven-repo-pvc 、二つのPVCを用意します。OpenShift Pipelines実行時に、これらのPVCに基づき、動的にストレージが割り当てられます。
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
generateName: openshift-handson-apps-build-run-
namespace: handson-demo
spec:
serviceAccountName: build-bot
pipelineRef:
name: openshift-handson-apps-build
params:
- name: git-app-url
value: https://github.com/nelco-abm/openshift-handson-apps-addresscode.git
- name: git-manifests-url
value: https://github.com/nelco-abm/openshift-handson-manifests.git
- name: image-registry
value: quay.io/soharaki/addresscode-app
workspaces: (2)
- name: local-source
persistentVolumeClaim:
claimName: local-source-pvc
- name: maven-settings
persistentVolumeClaim:
claimName: maven-repo-pvc
(2) Tekton側からは、workspaceリソースを介してストレージを認識します。
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: openshift-handson-apps-build
namespace: handson-demo
spec:
# 略
tasks:
# 略
# イメージタグをgitのコミット情報より生成する
- name: make-imagetag
taskRef:
name: get-githash
runAfter: ["fetch-repository"]
workspaces: (3)
- name: source
workspace: local-source
# ビルドする
- name: build
taskRef:
name: maven
runAfter: ["make-imagetag"]
params:
- name: GOALS
value: ["clean", "package"]
workspaces: (3)
- name: source
workspace: local-source
- name: maven-settings
workspace: maven-settings
# 略
(3) Taskに応じて実際にマウントするストレージを組み替えます。上記例では、
・イメージタグをgitのコミット情報生成するタスク ⇒local-source
・ビルドするタスク⇒local-source とmaven-repo-pvc
と用途に応じて使い分けをしています。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: maven
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: build-tool
spec:
description: >-
This Task can be used to run a Maven build.
workspaces:
- name: source
- name: maven-settings
params:
# 略
steps:
# 略
- name: mvn-goals
image: $(params.MAVEN_IMAGE)
workingDir: $(workspaces.source.path) (4)
command: ["/usr/bin/mvn"]
args:
- -s
- $(workspaces.maven-settings.path)/settings.xml
- -Dmaven.repo.local=$(workspaces.maven-settings.path) (4)
- "$(params.GOALS)"
(4) タスクの中では、指定したworkspaceに応じて仮想的にディレクトリが割り振られます。$(workspaces.ワークスペース名.path) という環境変数に応じてパスを取得できるので、処理の要所要所でワークスペースのパス名を指定します。
✽ Tektonのサンプルリソースを調べるとPipelineResourcesを使った実装を見かけることが多いですが、Tektonの現在のバージョンであるv1beta1ではサポートされていません。ご注意ください。
resources.md
4. 必要なツールが入ったコンテナイメージがないなら自分で作ればいい

OpenShift Pipelinesはコンテナで動くことを前の章で説明しましたが、Red Hat社やKubernetes Communityが用意したイメージで、ビルドパイプラインのシステム要件を満たせない場合に、自分でカスタマイズしたコンテナイメージを使うこともできます。
kustomise、kubectl、git等、いろいろなツールがインストールされたコンテナイメージを今回のデモ環境のために準備しました。
FROM alpine:3.12
# Its Based on https://github.com/bskim45/docker-helm-kubectl-jq
# Metadata
LABEL org.label-schema.vcs-ref="" \
org.label-schema.name="helm-kubectl-oc-wrap-curl-git-jq-yq-kustomize" \
org.label-schema.url="https://quay.io/repository/soharaki/helm-kubectl-oc-wrap-curl-git-jq-yq-kustomize" \
org.label-schema.vcs-url="" \
org.label-schema.build-date="2020/08/27"
# Note: Latest version of kubectl may be found at:
# https://github.com/kubernetes/kubernetes/releases
ENV KUBE_LATEST_VERSION="v1.18.7"
# Note: Latest version of helm may be found at:
# https://github.com/kubernetes/helm/releases
ENV HELM_VERSION="v3.3.0"
# Note: Latest version of helm may be found at:
# https://github.com/mikefarah/yq
ENV YQ_VERSION="3.3.2"
# Note: Latest version of helm may be found at:
# https://github.com/mikefarah/yq
ENV KUSTOMIZE_VERSION="3.8.1"
RUN apk add --no-cache ca-certificates bash git openssh curl jq \
&& wget -q https://storage.googleapis.com/kubernetes-release/release/${KUBE_LATEST_VERSION}/bin/linux/amd64/kubectl -O /usr/local/bin/kubectl \
&& chmod +x /usr/local/bin/kubectl \
&& wget -q https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz -O - | tar -xzO linux-amd64/helm > /usr/local/bin/helm \
&& chmod +x /usr/local/bin/helm \
&& wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64 \
&& chmod +x /usr/local/bin/yq \
&& wget -q https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz -O - | tar -xzO kustomize > /usr/local/bin/kustomize \
&& chmod +x /usr/local/bin/kustomize
WORKDIR /workspace/source
CMD bash
このDockerfileをビルドして、quay.io/soharaki/helm-kubectl-oc-wrap-curl-git-jq-yq-kustomize:1.18.7-3.3.0-3.3.2-3.8.1 という名前でコンテナレジストリサーバー上に上げることで、OpenShift Pipelinesでも使用することが可能になります。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: update-manifests-for-gitops
spec:
description: >-
このタスクはGitOpsのために、マニフェストファイルリポジトリのリソースファイルを
指定されたタグ名で更新します。
workspaces:
- name: source
description: Location of gitops source code
params:
# 略
steps:
- name: gitops-step
image: quay.io/soharaki/helm-kubectl-oc-wrap-curl-git-jq-yq-kustomize:1.18.7-3.3.0-3.3.2-3.8.1 ←
workingDir: /workspace/source
command: ["/bin/bash", "-c"]
args:
- |-
set -e
# タグ情報
echo $(inputs.params.IMAGE_URL)
# git cloneでmanifestのソースコードをチェックアウトする
git config --global user.email $(inputs.params.GIT_EMAIL)
git config --global user.name $(inputs.params.GIT_USERNAME)
# ソースコードをcloneする
git clone -b master $(inputs.params.GITOPS_REPO) gitops
# ソースコードをコミットする
cd gitops/services/overlays/production
kustomize edit set image $(inputs.params.IMAGE_URL)
if git status --porcelain | grep services/overlays/production; then
# Changes
echo "any tag changed";
git add -u;
git commit -m "Updating image tag name "$(inputs.params.IMAGE_URL);
git push;
else
# No changes
echo "nothing to commit";
fi
所感
OpenShift Pipelinesを使っていて強く思うのが、Kubernetesとの親和性の高さです。「4. 必要なツールが入ったコンテナイメージがないなら自分で作ればいい」でも説明しましたが、必要なツールがあればコンテナイメージですぐに用意できる環境は魅力的だと感じました。
一方で、本番環境のすぐそばに、開発用のCI/CD環境があることに抵抗を覚える開発者も多いでしょう。デモ環境ではnamespaceを開発用の専用ノードに切り出して実演しましたが、コンセンサスを得るためにクラスタごと開発用として分けた上で、その上にOpenShift Pipelinesを構築することも考慮したほうがいいでしょう。
記事担当者:アプリケーション企画開発部 原木
投稿日:2020/12/18