TektonをMinikubeで試す2

- [TektonをMinikubeで試す1](https://qiita.com/sotoiwa/items/7ffd415185d2cbb9f1a1)

の続き。前回でTask/TaskRunを試したので、今回はPipeline/PipelineRunを試す。

## Pipeline

前回はHello Worldを表示するイメージをビルドするTaskを作成したが、今回は同じTaskを使い、すぐ終了するイメージではなくWebサーバーのイメージを作る。そして、イメージのビルドのTaskに加えて、KubernetesへデプロイするTaskを加えたPipelineを作成する。

### PipelineResource

Nginxのイメージを作るDockerfileを置いたリポジトリーを用意し、このリポジトリーを参照するPipelineResourceを作成する。

- https://github.com/sotoiwa/nginx-sample

```yaml:nginx-sample-git.yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: nginx-sample-git
spec:
  type: git
  params:
  - name: url
    value: https://github.com/sotoiwa/nginx-sample.git
```

```shell
kubectl apply -f nginx-sample-git.yaml
```

イメージのPush先となるDockerレジストリーを参照するPipelineResourceを作成する。

```yaml:nginx-sample-image.yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: nginx-sample-image
spec:
  type: image
  params:
  - name: url
    value: sotoiwa540/nginx-sample:1.0
```

```shell
kubectl apply -f nginx-sample-image.yaml
```

### マニフェスト

Dockerfileのリポジトリーとマニフェストのリポジトリーは別にしてもよいが、今回は同じリポジトリーを使うこととし、Gitリポジトリーに、Deploymentのマニフェストを配置しておく。

- https://github.com/sotoiwa/nginx-sample

```yaml:deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  labels:
    app: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: hogehoge
```

### イメージビルドのTask

前回作成したイメージビルドのTaskと、レジストリーにPushするためのSecretとServiceAccountが存在することを確認する。

```shell-session
$ kubectl get task
NAME                 AGE
build-docker-image   8m32s
$ kubectl get secret
NAME                    TYPE                                  DATA   AGE
basic-user-pass         kubernetes.io/basic-auth              2      4d21h
build-bot-token-xz77w   kubernetes.io/service-account-token   3      4d21h
default-token-86vrg     kubernetes.io/service-account-token   3      4d22h
$ kubectl get sa
NAME        SECRETS   AGE
build-bot   2         4d21h
default     1         4d22h
$
```

### RBAC

Pipelineは`build-bot`のServiceAccountで実行する。このアカウントにPodをデプロイする権限が必要なため、手っ取り早く`cluster-admin`を付与する。

```shell
kubectl create clusterrolebinding build-bot \
  --serviceaccount=default:build-bot \
  --clusterrole=cluster-admin
```

### デプロイのTask

このTaskでは、Gitリポジトリからマニフェストを取得し、[`yq`](https://github.com/mikefarah/yq)を使ってイメージタグをを置き換え、`kubectl`でデプロイする。

なお`yq`や`kubeclt`のパラメータを`${inputs.hogehoge}`のように指定しているところは、そのうち`$(inputs.hogehoge)`に変わる予定のようだ（[#1170](https://github.com/tektoncd/pipeline/issues/1170)）。

```yaml:deploy-using-kubectl.yaml
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: deploy-using-kubectl
spec:
  inputs:
    resources:
    - name: manifest-source
      type: git
    - name: image
      type: image
    params:
    - name: path
      type: string
      description: Path to the manifest to apply
    - name: yamlPathToImage
      type: string
      description: The path to the image to replace in the yaml manifest {arg to yq}
  steps:
  - name: replace-image
    image: mikefarah/yq
    command: ["yq"]
    args:
    - "w"
    - "-i"
    - "${inputs.params.path}"
    - "${inputs.params.yamlPathToImage}"
    - "${inputs.resources.image.url}"
  - name: run-kubectl
    image: lachlanevenson/k8s-kubectl
    command: ["kubectl"]
    args:
    - "apply"
    - "-f"
    - "${inputs.params.path}"
```

```shell
kubectl apply -f deploy-using-kubectl.yaml
```

### Pipeline

イメージのビルドとデプロイの2つのTaskを定義した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-docker-image
    taskRef:
      name: build-docker-image
    params:
    - name: pathToDockerFile
      value: Dockerfile
    - name: pathToContext
      value: /workspace/docker-source
    resources:
      inputs:
      - name: docker-source
        resource: source-repo
      outputs:
      - name: builtImage
        resource: web-image
  - name: deploy-web
    taskRef:
      name: deploy-using-kubectl
    runAfter:
    - build-docker-image
    params:
    - name: path
      value: /workspace/manifest-source/deployment.yaml
    - name: yamlPathToImage
      value: "spec.template.spec.containers[0].image"
    resources:
      inputs:
      - name: manifest-source
        resource: source-repo
      - name: image
        resource: web-image
        from:
        - build-docker-image
```

```shell
kubectl apply -f tutorial-pipeline.yaml
```

### PipelineRun

パイプラインを実行する。

```yaml:tutorial-pipeline-run-1.yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: tutorial-pipeline-run-1
spec:
  serviceAccount: build-bot
  pipelineRef:
    name: tutorial-pipeline
  resources:
  - name: source-repo
    resourceRef:
      name: nginx-sample-git
  - name: web-image
    resourceRef:
      name: nginx-sample-image
```

```shell
kubectl apply -f tutorial-pipeline-run-1.yaml
```

パイプラインが正常終了し、Deploymentリソースが作成されていることを確認する。

```
$ kubectl get pipelinerun
NAME                      SUCCEEDED   REASON    STARTTIME   COMPLETIONTIME
tutorial-pipeline-run-1   Unknown     Running   20s
$ kubectl get pipelinerun
NAME                      SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
tutorial-pipeline-run-1   True        Succeeded   54s         15s
$ kubectl get taskrun
NAME                                               SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
tutorial-pipeline-run-1-build-docker-image-t4hrh   True        Succeeded   59s         36s
tutorial-pipeline-run-1-deploy-web-tc5k2           True        Succeeded   36s         20s
$ kubectl get po
NAME                                                          READY   STATUS      RESTARTS   AGE
tutorial-pipeline-run-1-build-docker-image-t4hrh-pod-2ea398   0/3     Completed   0          62s
tutorial-pipeline-run-1-deploy-web-tc5k2-pod-4c4dfd           0/3     Completed   0          40s
web-d9f5894b5-cqq9h                                           1/1     Running     0          25s
$ kubectl get deploy -o wide
NAME   READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                        SELECTOR
web    1/1     1            1           33s   web          sotoiwa540/nginx-sample:1.0   app=web
$
```

Deploymentを公開するServiceを作成してアクセスしてみる。

```shell
kubectl expose deployment web --type=NodePort --port=80
```

MinikubeのIPアドレスと、SerivceのNodePort番号を取得。

```shell
IP=$(minikube ip)
PORT=$(kubectl get svc web -o jsonpath='{.spec.ports[0].nodePort}')
```

curlでアクセスできることを確認。

```shell-session
$ curl http://$IP:$PORT/
Hello World!!!
$
```

## TODO

- コミットをトリガーにビルドする方法を確認する
- イメージのタグに何を設定すればよいのか確認する