Tekton、カタログをうまく活用してパイプラインを作る(イメージビルド)

20 Mar 2021, 00:36 By mosuke5

Tekton学習シリーズ

こんにちは、もーすけです。
本日もTekton学習フェーズやっていきます。第7回では、カタログの活用とTektonを使っていく上で必ず通るであろうイメージビルドについてあわせてやっていきたいと思います。 本日のゴールは、Tektonが公開しているカタログ(公開Task)を用いて、任意のGitレポジトリにあるDockerfileをビルドしてレジストリにPushするまです。ではよろしくおねがいします。

カタログを活用する

カタログについて紹介します。今までの学習ではTaskは全部自分で作成してきました。 一方で、パイプライン内で実行したいTaskは共通化されてきます。たとえば、GitHubからソースコードをダウンロードしたい、コンテナイメージをビルドしたい、ビルドしたイメージをレジストリにプッシュしたい、などなど数え切れないほどありますよね。 そこで、Tektonではカタログという形で、Taskを公開してくれています。これを使わない手はありません。

例として、本日使うTaskのひとつであるgit-cloneを見てみましょう。 catalogをまずはダウンロードしてきて中身を確認します。0.1, 0.2, 0.3とバージョニングされているのは、Task自体のバージョンです。利用しているTektonのバージョンに合わせて利用するものを決定しましょう。本環境では、まだ0.15.2を使っているので0.2が該当します。

$ git clone https://github.com/tektoncd/catalog
$ cd catalog/task/git-clone
$ tree
.
├── 0.1
│   ├── README.md
│   ├── git-clone.yaml
│   ├── samples
│   │   ├── git-clone-checking-out-a-branch.yaml
│   │   ├── git-clone-checking-out-a-commit.yaml
│   │   └── using-git-clone-result.yaml
│   └── tests
│       └── run.yaml
├── 0.2
│   ├── README.md
│   ├── git-clone.yaml
│   ├── samples
│   │   ├── git-clone-checking-out-a-branch.yaml
│   │   ├── git-clone-checking-out-a-commit.yaml
│   │   └── using-git-clone-result.yaml
│   └── tests
│       └── run.yaml
└── 0.3
    ├── README.md
    ├── git-clone.yaml
    ├── samples
    │   ├── git-clone-checking-out-a-branch.yaml
    │   ├── git-clone-checking-out-a-commit.yaml
    │   ├── git-clone-sparse-checkout.yaml
    │   └── using-git-clone-result.yaml
    └── tests
        └── run.yaml

// 対象のバージョンはREADME.mdを読めばわかる
$ cat 0.2/README.md
# `git-clone`

**Please Note: this Task is only compatible with Tekton Pipelines versions 0.14.0 and greater!**
...

長いのでブログには記載しませんが、catalog/task/git-clone/0.2/git-clone.yaml を確認してみてください。 Taskが記載されていており、すぐ利用できるようになっています。かなり汎用的に利用できるようパラメータ化も進んでいます。 利用するときには、Taskの中身を確認し必要なパラメータを確認しTaskRunやPipelineRunから指定して利用します。 実践はこのあと見ていきましょう。

ビルドパイプラインを構成する

全体構成

では、作成するパイプラインの形を決めていきましょう。
あるレポジトリからソースコードをダウンロードしてきて、その中にあるDockerfileをビルドして、DockerHubにPushするまでを実現することとします。次のようなイメージでしょうか?

(Pipeline start) - (git-clone) - (builah[build & push])
                         \     /
                          \   /
                   (Persistent Volume [for workspace])

今回はイメージのビルドとレジストリへのPushに buildah というTaskを使います。 buildahは、OCIに準拠したデーモンレスのコンテナビルドツールのひとつです。TektonのTask自身がKubernetes上のコンテナとして動作することもあり、Dockerのようなデーモンプロセスを利用するより、デーモンレスのBuildahやkanikoといったツールを用いたほうが容易に実装できます。

下準備(レジストリ認証)

カタログにある buildah は、イメージのビルドとレジストリへのプッシュをあわせて行います。レジストリへのプッシュには当然レジストリへの認証が必要になります。 コンテナレジストリへの認証を簡単に実現する仕組みもTektonでは用意されています。 Taskを実行するPodの利用するServiceAccountを指定できるのですが、そのServiceAccountにレジストリの認証情報をリンクさせておけばできます。
詳しくは、公式ドキュメントの Authentication を参照しましょう。

今回は、レジストリにDockerHubを利用するので次のような設定ファイルを用意しておきます。 Dockerなどで利用する認証用のconfig.jsonです。xxxxxには、認証に必要なトークンをいれてください。簡単に取得する方法としては、レジストリのIDとパスワードをコロンでつなげてbase64でエンコードすることですかね。echo -n "id:password" | base64 このような感じです。

// config.json
{
	"auths": {
		"https://index.docker.io/v1/": {
			"auth": "xxxxx"
		}
	}
}
$ kubectl create secret generic dockerhub-cred \
    --from-file=.dockerconfigjson=/path/to/config.json \
    --type=kubernetes.io/dockerconfigjson
secret/dockerhub-cred created

次にServiceAccountです。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-tekton-pipeline
secrets:
  - name: dockerhub-cred
$ kubectl apply -f my-tekton-pipeline-sa.yaml
serviceaccount/my-tekton-pipeline created

SecretとSecretを紐付けたServiceAccountの作成ができたら下準備は終了です。

パイプライン

いよいよパイプラインの作成です。
以下のようなパイプラインを作成しました。Taskを独自に作る必要がなかったので、指定するパラメータさえ把握できていればシンプルに書くことができました。Task内に定義されているパラメータをすべてパイプラインで定義する必要はありません。多くのパラメータはデフォルト値が設定されているので、変更したい部分だけパラメータ設定してください。 前回の第6回でやりましたが、Task間はデータを引き継ぎできません。Workspaceが必要になります。

# build-image-pipeline.yaml
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: build-image-pipeline
spec:
  workspaces: 
    - name: shared-workspace
  params:
    - name: git-url
      type: string
    - name: git-revision
      type: string
      default: "master"
    - name: image
      type: string
  tasks:
    - name: fetch-repository
      taskRef:
        name: git-clone
      workspaces:
        - name: output
          workspace: shared-workspace
      params:
        - name: url
          value: $(params.git-url)
        - name: deleteExisting
          value: "true"
        - name: revision
          value: $(params.git-revision)
    - name: build-push-image
      taskRef:
        name: buildah
      params:
        - name: IMAGE
          value: $(params.image)
        - name: DOCKERFILE
          value: "Dockerfile"
        - name: CONTEXT
          value: "$(workspaces.source.path)"
      workspaces:
        - name: source
          workspace: shared-workspace
      runAfter:
        - fetch-repository

では、実行してみましょう。 次のようにPipelineRunを準備しました。

# build-image-pipeline-run.yaml
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: build-image-pipeline-run
spec:
  pipelineRef:
    name: build-image-pipeline
  params: 
    - name: git-url
      value: https://github.com/ncskier/myapp
    - name: image
      value: mosuke5/tekton-practice:from-pipeline
  serviceAccountName: my-tekton-pipeline
  workspaces: 
    - name: shared-workspace
      volumeClaimTemplate:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi

PipelineResourceはどこにいった?

第4回 Tekton、TaskでPipelineResouceを利用したときの挙動を確認する では、Gitレポジトリ上にあるソースコードをPipelineResourceという機能を利用してTaskと連携しました。今回はPipelineResourceを使わずにカタログの git-clone task を利用したわけですが、どちらを利用したほうがいいのでしょうか?と疑問がわくと思います。 今回やってみてわかったのですが、PipelineResourceは忘れていただいて、Taskで操作したほうが使い勝手がいいと考えました。理由として、buildah task もworkspaceでソースコードが引き渡されることが前提となっておりPipelineResourceを使う場合、Task自身を修正しなければなりませんでした。 また、余計なKubernetesリソースを作成することなくPipeline内で完結できるので、PipelineResourceは不要かな。。?と現時点では思っています。

パイプラインの実行

パイプラインを実行して、実行結果を見てみます。
確認ポイントとしては、各Taskの実行結果や最終的なアウトプットとしてのコンテナレジストリです。

$ kubectl apply -f build-image-pipeline.yaml
pipeline.tekton.dev/build-image-pipeline created

$ kubectl apply -f build-image-pipeline-run.yaml
pipelinerun.tekton.dev/build-image-pipeline-run created

// build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9 が完了後に
// build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7 が実行
$ kubectl get pod -w
affinity-assistant-38b60e39a8-0                             0/1     Pending     0          5s
affinity-assistant-38b60e39a8-0                             0/1     ContainerCreating   0          5s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   0/1     Pending             0          5s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   0/1     Init:0/2            0          5s
affinity-assistant-38b60e39a8-0                             1/1     Running             0          7s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   0/1     Init:1/2            0          15s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   0/1     PodInitializing     0          16s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   1/1     Running             0          17s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   1/1     Running             0          17s
build-image-pipeline-run-fetch-repository-s588m-pod-dc5h9   0/1     Completed           0          19s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     Pending             0          1s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     Pending             0          1s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     Init:0/3            0          1s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     Init:1/3            0          18s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     Init:2/3            0          19s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     PodInitializing     0          21s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   3/3     Running             0          22s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   3/3     Running             0          22s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   2/3     Running             0          47s
build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7   0/3     Completed           0          62s
affinity-assistant-38b60e39a8-0                             1/1     Terminating         0          83s
affinity-assistant-38b60e39a8-0                             0/1     Terminating         0          83s
affinity-assistant-38b60e39a8-0                             0/1     Terminating         0          84s
affinity-assistant-38b60e39a8-0                             0/1     Terminating         0          84s

buildah taskは3 Stepになっているのでそれぞれのログ結果を確認します。

$ kubectl logs build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7 -c step-build
+ buildah --storage-driver=overlay bud --format=oci --tls-verify=true --no-cache -f Dockerfile -t mosuke5/tekton-practice:from-pipeline /workspace/source
STEP 1: FROM node:10-alpine
Getting image source signatures
Copying blob sha256:d9692e56401d84fa6b0165d088b435621acc6be27d969b047d62413658094b78
Copying blob sha256:299bbe2100ab5b3ff39aeba08c0335acd76659a5cefd364d351a0b93695bfd77
Copying blob sha256:e95f33c60a645d6d31f52fdc334aecec0d79a1b410789eae37fbf69efcd587ab
Copying blob sha256:bc3b38a692a9ec24681521bbae19ba05bd8d8cf3c24120351c1aed643142ea6c
Copying config sha256:8dd791b3335fdda7c9214afcb2942ade98881493a3d9a2172c2a6f3001ef0268
Writing manifest to image destination
Storing signatures
STEP 2: WORKDIR /myapp
STEP 3: COPY package*.json ./
STEP 4: RUN npm install

> [email protected] preinstall /myapp/node_modules/node
> node installArchSpecificPackage

+ [email protected]
added 1 package in 3.109s
found 0 vulnerabilities

added 52 packages from 38 contributors and audited 52 packages in 5.773s
found 0 vulnerabilities

STEP 5: COPY . .
STEP 6: EXPOSE 3000
STEP 7: CMD ["node", "app.js"]
STEP 8: COMMIT mosuke5/tekton-practice:from-pipeline
--> d849f62cbdd
d849f62cbdde81bc3732c8c77ac8f757a9b129a7b8d20d2966c03dcbb3e40943

$ kubectl logs build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7 -c step-push
+ buildah --storage-driver=overlay push --tls-verify=true --digestfile /workspace/source/image-digest mosuke5/tekton-practice:from-pipeline docker://mosuke5/tekton-practice:from-pipeline
Getting image source signatures
Copying blob sha256:1200582c7aaeec2befa0416b9425b2dd7cf904750c6e2b37ae6b95c18b0e91cc
Copying blob sha256:9120c3c4dc211acf21a892c913e3410cc5c217504941307a821e9259bc662132
Copying blob sha256:796f68ff5eda2be2c081ac8276373cf0d61b7aedebc846909069cffeb85f3d9d
Copying blob sha256:af4e4e5799facf73eff4d722502aedc093c2bdfaf1eefce793347ab6e611387d
Copying blob sha256:6169bf830ae69f192382cfe9a6fe96e7f28a21c0c5e5045b85871b510de58435
Copying config sha256:d849f62cbdde81bc3732c8c77ac8f757a9b129a7b8d20d2966c03dcbb3e40943
Writing manifest to image destination
Storing signatures

$ kubectl logs build-image-pipeline-run-build-push-image-srdsz-pod-wj4l7 -c step-digest-to-results
+ tee /tekton/results/IMAGE_DIGEST
+ cat /workspace/source/image-digest
sha256:b25636094be442def8fb922a6b8a0893eba3ddc258f8042a76008af4ad3a92cc

DockerHubにも無事にイメージがプッシュされているのを確認しました。

tekton-dockerhub

まとめ

本日は、カタログを使用した、イメージのビルド方法について学びました。
だいぶ実践的なパイプラインになってきましたね。これからはKubernetesクラスタにアプリケーションをデプロイするなど、より実践的な内容へと発展していきます。 内容が難しかったよという人は、ぜひ前の学習シリーズの復習などしてみてください。


Tekton学習シリーズ

記事の内容に関連した相談、仕事依頼したい New

記事の内容やクラウドネイティブ技術に関する相談、仕事依頼を開始しました。
仕事依頼、相談をしてみる

記事へのフィードバック

本記事に対して、フィードバックあればこちらのフォームからご記入ください。
記事の内容にフィードバックしてみる

このエントリーをはてなブックマークに追加