Edited at

KnativeなCI/CDツールのTektonを使って、GKE上でイメージのビルド、GKEへのデプロイを行う

元記事はこちら



こちらの記事は5月時点での検証記事です。5月以降もTektonの開発が進んでいるため、現状の環境で動作する保証はありません。参考程度にしてください


What is Tekton?

Tektonはk8sネイティブなCI/CDを構築するためのプロジェクトです。

CDF (Continuous Delivery Foundation)のメンバーでもあります。

image.png

目指すゴールとしてはクラウドプラットフォームやオンプレ環境などに依存しないCI/CD環境を構築することのようです。

READMEを参考にするとTektonは、

1. Cloud Native

・Kunernetes上で実行可能

・コンテナを実行ブロックの単位として扱える

2. Decoupled

・一つのパイプラインで複数のクラスタにデプロイできる

・パイプラインを構築するTaskは単独で実行可能

・複数のgitリポジトリを簡単に扱える

3. Typed

・リソースは入力によって変更可能

(例:例えばImageのビルドを簡単にkanikoにしたりbuildkitにしたりできる)

Tektonに関してもっとよく知りたい方にはCloud Next '19の以下のセッションが参考になると思います。メインで開発をされている二人が発表されています。

https://www.youtube.com/watch?time_continue=1&v=TQJ_pdTxZr0


Tektonに登場する概念

Tektonに登場する概念ついて説明します。


Step

もっとも基本的な単位、kubernetesのPodと同じように定義できる


Task

複数のStepによって構成される。Stepごとに動作させるコンテナやリソースは指定できる。


Pipline

Taskを組み合わせたもの、実行する順番などを指定することもできる。また、複数あるTaskは同じノードで実行される訳ではない。

image.png


PiplineResources

Taskで利用されるインプットやアウトプットを指定するためのリソースとしてPiplineResourcesがあります。

例えば、

・TaskにインプットとしてGitHubのソースコードを利用

・TaskのアウトプットとしてDockerイメージを作り出す。また、作ったイメージはGCRやDockerHubなどのイメージレジストリーにPushされる

といった場合にPiplineResourcesを利用します。


TaskRun && PipelineRun

TaskやPipelineを実際に実行するためのリソースがTaskRunPiplineRunです。

TaskRunPipelineRunではこれまでに定義したTask、Pipelineに対してPipelineで定義したリソースおよび、トリガーの情報、引数などを実際に渡します。

PipelineResourceとTask、TaskRunの関係を大雑把に示したものが以下の図になります。Pipelineは少し違いますが考え方は大体同じです。

image.png

それでは実際に、Tektonを使ってGoのコードのテスト、Dockerイメージのビルド&GCRへのプッシュ、GKEへのデプロイを行って行きます。


下準備


GKEクラスタの構築とTektonのデプロイ

Google Cloudのクイックスタートを参考にして、GKEクラスタを構築、およびkubectlコマンドでGKEクラスタにアクセスできるようにしてきます。

またこちらを参考にcluster-admin権限を取得、TektonPipelineリソースをGKEにデプロイします。TektonリソースはCRDsとしてデプロイされるのでコマンド一つでGKE上で使用できるようになります。


Kanikoのためのサービスアカウントの登録

今回はDockerイメージのビルドにKanikoを利用しているのでこちらのサイトを参考にしてGCRのeditor権限を持ったサービスアカウントを作成してSecretとして登録しておきます。今回は単にSecretとして利用していますが、プロダクションで利用する際にはKMSなどを使用した方がセキュリティ的に安全です。


ClusterRoleBindの設定

今回のデモではkubernetesクラスタにデプロイするので、クラスタのAdmin権限を持ったServiceAccountが必要になります。exampleのClusterRoleBindingリソースを参考にAdmin権限を付与したServiceAccountを登録します。今回の例ではdefaultに付与しています。GKEにうまくデプロイできない場合にはこのあたりをもう一度見直す必要があります。


流れ

今回のデモでは、


  1. Goアプリケーションのテスト

  2. Dockerイメージのビルド

  3. kubectlコマンドでGKEクラスタにそのままデプロイ

の順番で行います。

今回使用したソースコードはこちらにおいてあります。


PipelineResourcesの登録

まずはPipelineで利用するPipelineResourcesを登録します。

今回使用するリソースは、アプリケーションのGitHubリポジトリのURLと、イメージをPushするGCRを指定しています。以下のようなYamlファイルを用意してapplyします。


resource.yaml

apiVersion: tekton.dev/v1alpha1

kind: PipelineResource
metadata:
name: tekton-sample-resource-image
spec:
type: image
params:
- name: url
value: gcr.io/${YOUR_PROJECT}}/tekton-sample-image # modify to your GCR path.
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: tekton-sample-resource-git
spec:
type: git
params:
- name: revision
value: master
- name: url
value: https://github.com/tommy-sho/tekton-sample.git # modify to your git repository


ここで重要なのは、spec.typeの部分です。Tektonでは各リソースの種類がtypeとして指定されています。

kg PipelineResourcePipelineResourceが以下のように登録されていることが確認できます。

NAME                           AGE

tekton-sample-resource-git 6m
tekton-sample-resource-image 6m


Taskの登録


イメージのビルドとプッシュ

次にTaskを登録します。KanikoによるDockerイメージのビルドとGCRへのプッシュを行うタスクを以下のようなYamlファイルで定義します。

apiVersion: tekton.dev/v1alpha1

kind: Task
metadata:
name: build-image
spec:
inputs:
resources:
- name: app
type: git
params:
- name: pathToDockerFile
description: The path to the dockerfile to build
default: /workspace/app/Dockerfile
- name: pathToContext
description: The build context used by Kaniko (https://github.com/GoogleContainerTools/kaniko#kaniko-build-contexts)
default: /workspace/app/ # <- ここのpathはworkspace/resource名/のプレフィックスがつく
outputs:
resources:
- name: builtImage
type: image
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor
command:
- /kaniko/executor
args:
- --dockerfile=${inputs.params.pathToDockerFile}
- --destination=${outputs.resources.builtImage.url}
- --context=${inputs.params.pathToContext}
volumeMounts:
- name: kaniko-secret
mountPath: /secret
env:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /secret/kaniko-secret.json
volumes:
- name: kaniko-secret
secret:
secretName: kaniko-secret

ここで注意する必要があるのはparmsで指定しているpathのプレフィックスです。現在(2019/5)では、type:gitPipelineResource/workspace/リソース名以下に配置されます。今回は、input.resourceappという名前のリソースにしているので/workspace/app以下にGitHubのコードが展開されます。


GKEへのデプロイ

GKEへのデプロイはkubectlが利用できるlachie83/k8s-kubectlイメージを利用しました。Yamlファイルは以下のようになっています。

apiVersion: tekton.dev/v1alpha1

kind: Task
metadata:
name: deploy-kubectl
spec:
inputs:
resources:
- name: app
type: git
params:
- name: path
description: Path to the manifest to apply
steps:
- name: run-kubectl
image: lachlanevenson/k8s-kubectl
command: ['kubectl']
args:
- 'apply'
- '-f'
- '${inputs.params.path}'

単純にkubetcl applyを叩いているだけです。デプロイに使うマニフェストを渡しています。


Pipelineの設定

さて、PipelineResourceとTaskが定義できたのでいよいよPipelineを定義していきます。Pipelineを定義したYamlファイルは以下のようになっています。

apiVersion: tekton.dev/v1alpha1

kind: Pipeline
metadata:
name: sample-pipline
spec:
resources:
- name: app
type: git
- name: image
type: image
tasks:
- name: build-push-image
taskRef:
name: build-image
params:
- name: pathToDockerFile
value: /workspace/app/Dockerfile
- name: pathToContext
value: /workspace/app
resources:
inputs:
- name: app
resource: app
outputs:
- name: builtImage
resource: image
- name: deploy
runAfter: [build-push-image]
taskRef:
name: deploy-kubectl
params:
- name: path
value: /workspace/app/manifest.yaml
resources:
inputs:
- name: app
resource: app

特に難しいことはありません。spec.resourcesでPipelineの中で利用するPipelineResourceを定義しておいて、spec.tasksで実行するTaskを並べています。

また、それぞれのTaskに対して、使用するparamsresourcesを定義します。

もしTaskに実行する順番(ex. line -> test -> build -> deployなど)がある場合には、runAfterで依存関係を明示することができます。宣言しなかった場合にはそれぞれPodが立って並列で実行されます。


PipelineRunの定義

さてまだあります。PipelineRunです。Pipelineでは最初にPipelineResourceを定義して、Taskの中でどのresourceを使用するかを定義していますが、またresourceのタイプのみしか明らかになっていないので、PipelineRunで実際にどのPipelineResourceを使用するのかを宣言します。

PipelineRunは以下のようにしました。

apiVersion: tekton.dev/v1alpha1

kind: PipelineRun
metadata:
name: pipeline-run
spec:
pipelineRef:
name: sample-pipline
trigger:
type: manual
resources:
- name: app
resourceRef:
name: tekton-sample-resource-git
- name: image
resourceRef:
name: tekton-sample-resource-image

使用するPipelineResourcetriggerが定義されています。最初の方で定義したPipelineResourcePipelineを結びつけています。

現在(2019/5)ではtriggerはGitHubへのPushや、Slackなどを使ったチャットオペレーションには対応していない状態です。こちらのRoadmapによると2019年以内には対応する予定のようです。


実際にPipelineRunしてみる

これで準備ができたので、今までに定義したリソースをapplyした後で、PipelineRunをapplyしてみます。

kubectl get tekton-pipelinesコマンドでTektonPipelineのリソースが確認できます。

$ > kubectl get tekton-pipelines

NAME AGE
pipeline.tekton.dev/sample-pipline 2m

NAME STATUS STARTTIME COMPLETIONTIME
pipelinerun.tekton.dev/pipeline-run True 2m 37s

NAME AGE
pipelineresource.tekton.dev/tekton-sample-resource-git 2m
pipelineresource.tekton.dev/tekton-sample-resource-image 2m

NAME AGE
task.tekton.dev/build-image 2m
task.tekton.dev/deploy-kubectl 2m

NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
taskrun.tekton.dev/pipeline-run-build-push-image-6jbcm True 2m 43s
taskrun.tekton.dev/pipeline-run-deploy-782tv True 43s 37s

一番下の部分がPipelineの中の各TaskでSUCCEEDEDTrueになっていることがわかります。

Taskが正しく完了しなかった場合にはSUCCEEDEDFalseになります。

実際にGKEにデプロイされたかどうかを確認します。

$ > kubectl get pods

NAME READY STATUS RESTARTS AGE
pipeline-run-build-push-image-dhjvh-pod-51492d 0/3 Completed 0 1m
pipeline-run-deploy-wr7cm-pod-1a4ff9 0/3 Completed 0 26s
sample-6d96898c4c-hk847 1/1 Running 0 20s
sample-6d96898c4c-tr4hd 1/1 Running 0 20s

正しくデプロイされているようです。Taskで利用されたPodも確認できます。


 まとめ

KnativeなCI/CDツールとして期待されているTektonを触って見ました。

今回は触っていませんが、DashBoradを作成してPipelineの実行状況の確認などもできるようです。

リポジトリをみるとTekton自体まだ開発が始まって間もないプロジェクトなのでまだ機能的には足りないと感じる部分はありますが、Kubernetes上でCI/CDパイプラインを構築できる点やカスタマイズ性の高さは触っていても非常に高いと感じたのでこれからの開発に要注目して行きたいとおもいます。

あとこのマスコットキャラも近未来感があって好きだったりします。

もし、うまく動かない、記事に変な点があったりする場合には気軽にコメントや連絡してください。


参考サイト、記事