Kubernetes ネイティブな CI/CD パイプラインフレームワーク Tekton について調査してみた件

# はじめに
2019年3月に CI/CD の普及とエコシステムの促進を目的に "Continuous Delivery Foundation" が発足されました。
この "Continuous Delivery Foundation" がホストしているプロジェクトは以下の4つですが、Jenkins や Spinnaker を知っている人は多いと思いますが、一番右の "Tekton" について知っている人は少ないと思います。

![スクリーンショット 2019-05-27 18.38.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/2988afa2-8e6a-0a27-c2b0-8e00e782abf8.png)


しかし、Tekton はクラウドプラットフォームに依存しない CI/CD パイプラインの標準化を目指しており、今後注目されるオープンソースのフレームワークであると考えています。
本記事では、Tekton の概要と簡単なパイプラインの設定方法について説明したいと思います。


# Tekton 概要
Tekton とは、Kubernetes ネイティブな CI/CD パイプラインを作るオープンソースのフレームワークです。
コンテナを実行ブロックの単位として利用することができることや、Kubernetes で書き慣れたYAMLファイルと同じ書き方で CI/CD パイプラインを定義することができます。


# インストール方法
インストール手順は以下のURLに記載されています。

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

`kubectl apply` コマンドの実行前に、ユーザに cluster-admin 権限を付与する必要がありますが、以下のコマンドでインストールすることができます。

```console
$ kubectl apply --filename https://storage.googleapis.com/tekton-releases/latest/release.yaml
```

上記の release.yaml ファイルでは、カスタムコントローラのデプロイと CRD (Custom Resource Definition) の作成を行なっています。
デプロイが完了すると controller と webhook の2つの Pod が作成されます。


# Custom Resource Definition 種別
作成される CRD (Custom Resource Definition) の種別は以下の通りです。

* PipelineResource: Task で利用するインプット/アウトプットを指定するリソース
* Task: 最小の実行単位、複数の Step から構成されたリソース
* TaskRun: Task を実行するためのリソース
* Pipeline: 複数の Task から構成されたリソース
* PipelineRun: Pipeline を実行するためのリソース

Pipeline は、CI/CD パイプラインを定義しており、複数の Task から構成されています。
Task は複数の Step から構成されており、Step では一つのコンテナイメージを利用して処理を実行しています。

以下ではそれぞれの CRD (Custome Resource Definition) について説明をしたいと考えております。


## PipelineResource 設定例
Task で利用するインプット/アウトプットを定義します。PipelineResource の設定例は以下の通りです。

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

* type: インプット/アウトプットのタイプを指定

上記のYAMLファイルは Git をインプットする場合の設定例ですが、2019年5月時点でサポート対象のタイプは以下の通りです。

* Git Resource
* Image Resource: インプット/アウトプットにコンテナレジストリを指定
* Cluster Resource: 他の Kubernetes クラスタへのアプリケーションのデプロイなどに利用
* Storage Resource: ストレージ上のファイル/ディレクトリをインプット/アウトプットに利用。GCS(Google Cloud Storage)のみサポート対象。


## Task 設定例
パイプラインを構成するタスクを定義します。Task の設定例は以下の通りですが、複数の Step から構成することも可能です。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: build-docker-image-from-git-source
spec:
  inputs:
    resources:
      - name: docker-source
        type: git
    params:
      - name: pathToDockerFile
        description: The path to the dockerfile to build
        default: /workspace/docker-source/Dockerfile
      - name: pathToContext
        description:
          The build context used by Kaniko
          (https://github.com/GoogleContainerTools/kaniko#kaniko-build-contexts)
        default: /workspace/docker-source
  outputs:
    resources:
      - name: builtImage
        type: image
  steps:
    - name: build-and-push
      image: gcr.io/kaniko-project/executor:v0.9.0
      # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential
      env:
        - name: "DOCKER_CONFIG"
          value: "/builder/home/.docker/"
      command:
        - /kaniko/executor
      args:
        - --dockerfile=${inputs.params.pathToDockerFile}
        - --destination=${outputs.resources.builtImage.url}
        - --context=${inputs.params.pathToContext}
```

* inputs: インプットに必要な PipelineResource とパラメータを指定
* outputs: Task によって作成される PipelineResource を指定
* steps: 実行したいコンテナイメージを指定、コンテナが実行ブロックの単位となります

上記の設定例からも分かるように、Kubernetes のYAMLファイルの書き方に非常に似ており、Kubernetes を利用している開発者がパイプラインの定義も書きやすいようになっています。


## TaskRun 設定例
Task を実行するためのリソースです。実行したい Task やインプット/アウトプットとなる PipelineResource を指定します。TaskRun の設定例は以下の通りです。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: build-docker-image-from-git-source-task-run
spec:
  taskRef:
    name: build-docker-image-from-git-source
  inputs:
    resources:
      - name: docker-source
        resourceRef:
          name: skaffold-git
    params:
      - name: pathToDockerFile
        value: Dockerfile
      - name: pathToContext
        value: /workspace/docker-source/examples/microservices/leeroy-web #configure: may change according to your source
  outputs:
    resources:
      - name: builtImage
        resourceRef:
          name: skaffold-image-leeroy-web
```

* taskRef: 実行したい Task を指定
* resources: インプット/アウトプットとなる PipelineResource を指定

また、上記の設定例では記載されておりませんが、Pod などの設定と同様に以下を設定することも可能です。

* serviceAccount: Task を実行するサービスアカウントを指定
* nodeSelector / tolerations / affinity: Pod と同様に Task を実行するノードを制御可能 


## Pipeline 設定例
パイプラインを定義します。Pipeline の設定例は以下の通りです。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: tutorial-pipeline
spec:
  resources:
    - name: source-repo
      type: git
    - name: web-image
      type: image
  tasks:
    - name: build-skaffold-web
      taskRef:
        name: build-docker-image-from-git-source
      params:
        - name: pathToDockerFile
          value: Dockerfile
        - name: pathToContext
          value: /workspace/docker-source/examples/microservices/leeroy-web #configure: may change according to your source
      resources:
        inputs:
          - name: docker-source
            resource: source-repo
        outputs:
          - name: builtImage
            resource: web-image
    - name: deploy-web
      taskRef:
        name: deploy-using-kubectl
      resources:
        inputs:
          - name: source
            resource: source-repo
          - name: image
            resource: web-image
            from:
              - build-skaffold-web
      params:
        - name: path
          value: /workspace/source/examples/microservices/leeroy-web/kubernetes/deployment.yaml #configure: may change according to your source
        - name: yqArg
          value: "-d1"
        - name: yamlPathToImage
          value: "spec.template.spec.containers[0].image"
```

* tasks: 実行する一連の Task を指定
* from: 先行する Task のアウトプットの PipelineResource がある場合に指定

また、上記の設定例には記載されておりませんが、以下の設定によりパイプラインの実行順を制御することもできます。

* runAfter:	 別の Task の完了後に実行する場合に指定、アウトプットを連携する必要はない
* retries: Task の実行に失敗した際にリトライしたい場合に指定


## PipelineRun 設定例
パイプラインを実行するためのリソースです。実行したい Pipeline やインプット/アウトプットとなる PipelineResource を指定します。PipelineRun の設定例は以下の通りです。

```yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: tutorial-pipeline-run-1
spec:
  pipelineRef:
    name: tutorial-pipeline
  resources:
    - name: source-repo
      resourceRef:
        name: skaffold-git
    - name: web-image
      resourceRef:
        name: skaffold-image-leeroy-web
```

* pipelineRef: 実行したい Pipeline を指定
* resources:  インプット/アウトプットとなる PipelineResource を指定

また、上記の設定例は記載されておりませんが、Pod などの設定と同様に以下を設定することも可能です。

* serviceAccount: Task を実行するサービスアカウントを指定
* nodeSelector / tolerations / affinity: Pod と同様に Task を実行するノードを制御可能 


# パイプライン実行方法
パイプラインを実行する方法は、これまで説明してきたリソースを以下のコマンドにより作成するだけです。

```sh
$ kubectl apply -f <name-of-file.yaml>
```

実行結果は以下のコマンド例のように確認することができます。

```console
$ kubectl get pipelineruns/tutorial-pipeline-run-1 -o yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  annotations:
  creationTimestamp: 2018-12-11T20:30:19Z
  generation: 1
  name: tutorial-pipeline-run-1
  namespace: default
  resourceVersion: "6760151"
  selfLink: /apis/tekton.dev/v1alpha1/namespaces/default/pipelineruns/tutorial-pipeline-run-1
  uid: 93acb0ea-fd83-11e8-9129-42010a8a0fdc
spec:
  generation: 1
  pipelineRef:
    name: tutorial-pipeline
  resources:
    - name: source-repo
      paths: null
      resourceRef:
        name: skaffold-git
    - name: web-image
      paths: null
      resourceRef:
        name: skaffold-image-leeroy-web
  serviceAccount: ""
status:
  conditions:
    - lastTransitionTime: 2018-12-11T20:32:41Z
      message: All Tasks have completed executing
      reason: Succeeded
      status: "True"
      type: Succeeded
  taskRuns:
    tutorial-pipeline-run-1-build-skaffold-web:
      conditions:
        - lastTransitionTime: 2018-12-11T20:31:41Z
          status: "True"
          type: Succeeded
      podName: tutorial-pipeline-run-1-build-skaffold-web-pod-21ddf0
      startTime: 2018-12-11T20:30:19Z
      steps:
        - terminated:
            containerID: docker://c699fcba94....f96108ac9f4db22b94e0c
            exitCode: 0
            finishedAt: 2018-12-11T20:30:36Z
            reason: Completed
            startedAt: 2018-12-11T20:30:36Z
        - terminated:
            containerID: docker://f5f752d....824262ad6ce7675
            exitCode: 0
            finishedAt: 2018-12-11T20:31:17Z
            reason: Completed
            startedAt: 2018-12-11T20:30:37Z
    tutorial-pipeline-run-1-deploy-web:
      conditions:
        - lastTransitionTime: 2018-12-11T20:32:41Z
          status: "True"
          type: Succeeded
      podName: tutorial-pipeline-run-1-deploy-web-pod-7a796b
      startTime: 2018-12-11T20:32:11Z
      steps:
        - terminated:
            containerID: docker://eaefb7b6d685....f001f895430f71374
            exitCode: 0
            finishedAt: 2018-12-11T20:32:28Z
            reason: Completed
            startedAt: 2018-12-11T20:32:28Z
        - terminated:
            containerID: docker://4cfc6eba47a7a....dcaef1e9b1eee3661b8a85f
            exitCode: 0
            finishedAt: 2018-12-11T20:32:31Z
            reason: Completed
            startedAt: 2018-12-11T20:32:31Z
        - terminated:
            containerID: docker://01b376b92....dce4ccec9641d77
            exitCode: 0
            finishedAt: 2018-12-11T20:32:35Z
            reason: Completed
            startedAt: 2018-12-11T20:32:34Z
```


# さいごに
本記事では、Tekton の概要と簡単なパイプラインの設定方法について説明してきました。
また、最後にこっそりネタバレになりますが、本記事は 2019/5/28 に開催された Red Hat Tech Night でLT発表したネタの流用となります。

https://speakerdeck.com/mamoru1112/tekton-ru-men

LTだと時間が短く説明できなかった箇所もあったため、Qiitaに記事を書かせてもらいました。
個人的には、インストールが非常に簡単であり、各リソースのYAMLファイルも非常に読みやすく理解し易かったので、今後も注目が必要なオープンソースのフレームワークであると考えています。


# 参考情報
* [Tekton](https://github.com/tektoncd)