Tekton Pipelinesを使ってKubernetes上にCI/CD Pipelineを構築する 1

# 今、パイプライン界隈がアツい
[Continuous Delivery Foundation (CDF)](https://cd.foundation/)が発足されたので、CI/CD関連ツールの足並みが揃えば、パイプラインおじさんが泥臭いコードでツール間を繋がなくても、スマートな定義ファイルで良しなに実行してくれる未来が来そうです。

# Tekton is 何？
Kubernetesを単なるコンテナマネージメントシステムとして使うのでは無く、開発のエコシステムとして使えるようにするぜ！という激アツなプロジェクト[Knative](https://www.knative.dev/docs/)のパイプライン担当です。最近は、Knative依存を減らして、より汎用的に使えるように進化中。
CDFの１プロジェクトでもあり、Cloud Nativeなパイプラインを構築するために、触れておいて損はないかと。

# 使ってみる

公式のGithub repositoryにドキュメントがあるので、インストール方法は割愛します。
https://github.com/tektoncd/pipeline

## git clone -> docker build -> docker push

今回は、とてもシンプルなビルドパイプラインです。
Git serverはGitHub（アクセストークン等が無くても、git cloneできる）、ビルドはDockerの[multistage-build](https://docs.docker.com/develop/develop-images/multistage-build/)を利用、ビルド環境自体には[Kaniko](https://github.com/GoogleContainerTools/kaniko)を利用しています。

Kubernetesの定義ファイルは、下記のリポジトリにコミットしてあります。
https://github.com/TakiTake/tekton-test/tree/sample/task/task/build

### 用語解説

処理を定義する方法は、大きく分けて２つあり、TaskとPipelineがあります。

#### Task

Taskは複数のStepによって構成されていて、各Stepは上から順番に実行されることが保証されています。また、各Stepはコンテナの中で実行されるので、Container Imageを指定する必要があります。Task内でビルドするアプリのリポジトリ、もしくは、Taskの成果物としてのContainer Image等は、PipelineResourceとして定義することが可能です。

#### Pipeline

Taskの実行フローを定義できます。Stepは上から下へ順次実行することしかできませんでしたが、PipelineはTaskを並列で実行することや、Task同士に依存を張ることが可能です。

### 定義ファイルの解説

まず、defaultのサービスアカウントにcluster-adminを紐付けておきます。本番で使用する場合は、defaultよりも専用の名前で用意した方が良いのですが、検証用ですのでこのまま進めます。

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: default-cluster-admin
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
```

次に、Tekton Pipelineリソースの定義です。定義したリソースは、Taskのinput/outputとして利用できます。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: hello-world-image
spec:
  type: image
  params:
  - name: url
    value: takitake/hello-world-go
```

```yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: hello-world-go-git
spec:
  type: git
  params:
  - name: revision
    value: master
  - name: url
    value: https://github.com/TakiTake/hello-world-go.git
```

いよいよTaskの定義です。理由は後ほど説明しますが、Taskのinput/outputには、gitリソースを使う、成果物としてimageを作るという抽象的な定義を記載します。また、仕様として**/workspace/リソース名**にinputリソースのデータが書き出されます。gitであれば、git clone先という意味です。

そして、Stepの解説です。ContainerのビルドにKanikoを使っており、ビルド後にDocker Hubへアップロードするためにtekton用のannotationを付与したSecretを作成します。annotationに**tekton.dev/docker-**というプレフィックス始まりのキーを付与すると、Taskの初期化時に**$HOME/.docker/config.json**ファイルを自動生成してくれます。詳しくは、[Authentication](https://github.com/tektoncd/pipeline/blob/master/docs/auth.md)をご覧ください。

```yaml:auth.yaml
apiVersion: v1
kind: Secret
metadata:
  name: basic-user-pass
  annotations:
    tekton.dev/docker-0: https://index.docker.io/v1/
type: kubernetes.io/basic-auth
stringData:
  username: <username>
  password: <password>
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-bot
secrets:
  - name: basic-user-pass
```

その他の変数は、input/outputの定義から参照できます。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: build-push-kaniko
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
  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}
```

最後に、Taskの実行方法です。YAML疲れするかもしれませんが、これもYAMLで定義します。Taskを実行するにあたって渡したい変数や、紐づけたいPipelineResourceを記載します。Taskの定義がやや抽象的だったのは、TaskRunで具体的な値を注入する思想だからです。これにより、Task定義の再利用がしやすくなっています。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: build-push-run
spec:
  serviceAccount: build-bot
  taskRef:
    name: build-push-kaniko
  trigger:
    type: manual
  inputs:
    resources:
    - name: app
      resourceRef:
        name: hello-world-go-git
    params:
    - name: pathToDockerFile
      value: /workspace/app/Dockerfile
    - name: pathToContext
      value: /workspace/app
  outputs:
    resources:
    - name: builtImage
      resourceRef:
        name: hello-world-image
```

# まとめ

Tektonで簡単なTaskを実行してみました。ローカルPCでマニュアル実行するなら、docker build, docker pushで済む話ですが、より複雑なフローや、似たようなフローを制御する内にありがたみを実感できるのではないかと自分も期待しています。

次回は、Pipelineを解説予定ですー