【NADP】OpenShift Pipelinesに関する細かい話(デモ解説その3) - Natic | Application Modernization Platform – 日商エレクトロニクス

【NADP】OpenShift Pipelinesに関する細かい話(デモ解説その3)

はじめに

こんにちは、NADPの原木と申します。今回はOpenShift上でCI/CDを実現できるOpenShift Pipelinesについて、実際に利用するときにあたって疑問に感じたり、問題を解決するために実施した内容を説明したいと思います。

先日「近づく”2025年の崖” フレームワークとコンテナ化事例を基に内製化のヒントが得られるウェビナー」で実践したデモに関する技術解説になります。

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の実践
https://www.katacoda.com/openshift/courses/cicd-application-delivery/pipelines

これらのステップを終えた後、実践的な内容を構築したい場合、大抵はさらに覚えなくてはいけないことが多いでしょう。

例えば、このようなサンプルだと必ずOSSでgit cloneする分にはパスワードは必要ないですが、業務アプリケーションのソースコードは通常プライベートなリポジトリサーバーにあります。そこへのアクセスに必要な認証情報やプロキシ情報は普段、使用することが多いにもかかわらず、大抵のOSSではとても分かりづらい場所に設定に関するドキュメントが転がっていたりします。OpenShift Pipelinesにおいてもそういったギャップは多数ありました。

今回のブログではOpenShift Pipelinesのよくあるサンプルを業務アプリケーション用の開発環境に当てはめようとして躓いたこと、気づいたことを改めて説明したいと思います。

ソースコード

https://github.com/nelco-abm/openshift-handson-manifests-for-website

実際に動かしてみて得られた気づき

1. サンプルを参考にすると非常に早く作業が終わる。ただし、作り方と作られた時期に注意

今回のデモ環境ではチュートリアルサイトで説明されていた内容を組み合わせることで上記スライドのパイプラインを比較的短時間で構築することができました。

https://github.com/IBM/tekton-tutorial/tree/master/tekton – Connect to preview

https://github.com/ibm-cloud-architecture/appmod-liberty-tekton/tree/master/tekton/tekton-argo – Connect to preview

https://developers.redhat.com/blog/2020/02/26/speed-up-maven-builds-in-tekton-pipelines/

全てIBM, Red Hatの公式チュートリアルなどのリポジトリです。

最初から詳しく説明されていた内容が、ちょうど弊社でやろうとしていたモダナイゼーションプロジェクトでのCI/CDパイプラインで求めるものと多くの点で似ており、スクラッチでパイプラインを構築するより品質担保にちょうどよかったと思います。

ただし、OpenShift Pipelines(Tekton)自体が進化の早いプロダクトであり、デモ環境構築時はバージョンがv1alpha1からv1beta1への移行期にありました。参考にしているAPIに関してはdeprecatedなものはなるべく使用せずに、公式ドキュメントやGitHub上のリファレンス情報を参照する必要がありました。これは今後も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内部で処理が分かれます。設定情報は下記のドキュメントにあります。

https://github.com/tektoncd/pipeline/blob/master/docs/auth.md

(2) QuayコンテナレジストリサーバーのユーザーID/パスワードを登録します。こちらも他のコンテナレジストリサーバーに関する認証などバリエーション情報は上記ドキュメントを参照してください。

(3) ServiceAccountに先ほど登録したSecret情報を紐づけます。

今回は割愛させていただきますが、ロールバインドの設定もこのサービスアカウントに対して行います。

OpenShift Pipelinesが動いているnamespaceと、CI/CD環境で利用するステージング環境、本番環境は違うnamespaceの場合は多いと思うので、適切な管理が必要でしょう。

✽ PipelineRunへのServiceAccountは2020年5月にdeprecatedになりました。taskServiceAccountNameという、Pipelineより細かい粒度の処置に対して制御が可能な設定値が追加されたためです。詳細は下記をご覧ください。

https://github.com/tektoncd/pipeline/issues/2614 – Connect to preview

---
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