今日から始めるKubernetes-nativeなGitOps【CI編 ~pipeline構築~】

この記事は [WESEEK Advent Calendar](https://qiita.com/advent-calendar/2020/weseek) 2020 16日目の記事です。

こんにちは！ [WESEEK, Inc.](https://weseek.co.jp/) で長期インターンをさせていただいております [yamagai] (https://twitter.com/yamagai_0919)と申します。

先日は [Kubernetes の Controller についての記事](https://qiita.com/yamagai/items/570b4626056d998b0431)を書きましたが、これから3回に分けて GitOps の構築について書いてみようと思います！

今回は、GitOps の中でも CI pipeline の構築までについて書きます。


CI/CDを導入する対象のプロジェクトは、フロントエンドが Next.jsでバックエンドが Rails のアプリです。
フロントエンドとバックエンドは一つのリポジトリにまとめています。


# 参考リポジトリ

- CIを使用するプロジェクトのリポジトリ
    - https://github.com/bamboooo-dev/alcatraz
    - /api 以下がバックエンドで、/ui 以下がフロントエンド

- 今回使用する CI の設定を書いたマニフェストのリポジトリ
    - https://github.com/bamboooo-dev/alcatraz-tekton



# 使うOSS
今回は Kubernetes-native な CI ということで、[Tekton](https://github.com/tektoncd)を使います。
Kubernetes のカスタムリソースとしてCIパイプラインを定義していくのが特徴です。

### Tektonのうち今回使うもの

- [Tekton Pipeline](https://github.com/tektoncd/pipeline/blob/master/docs/install.md#configuring-pipelineresource-storage)
CIパイプラインを構築するもの。

- [Tekton Triggers](https://github.com/tektoncd/triggers/blob/master/docs/install.md)
githubなどからの webhook event を受け付けるもの。


- [Tekton Dashboard](https://github.com/tektoncd/dashboard/blob/master/docs/install.md)
これは無くても良いですがデバッグに有用なので、今回は入れます。


- [Tekton CLI](https://github.com/tektoncd/cli) (optional)
これもデバッグに有用ですが、今回は触れません。


# とりあえずCIパイプラインを作る
目標 : image の build と push ができるようにする

## 各種インストール

### Tekton pipeline のインストール

**前提**

- cluster version 1.16以降
- user は cluster-admin 権限を持っている

```jsx
kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
```
とりあえず理由がない限り nightly とかじゃなくてこれでいい
これでcontrollerのpodなどができます

パイプライン内のタスク間で共有したいデータを置いておくStorageがある場合は以下を参考に設定が必要です
→[https://github.com/tektoncd/pipeline/blob/master/docs/install.md#configuring-pipelineresource-storage](https://github.com/tektoncd/pipeline/blob/master/docs/install.md#configuring-pipelineresource-storage)

### Tekton dashboard のインストール
**前提**

- cluster version 1.15.0以降
- tekton-pipelines がインストール済み

```jsx
kubectl apply --filename https://storage.googleapis.com/tekton-releases/dashboard/latest/tekton-dashboard-release.yaml
```
v0.6.1.4より古いのはセキュリティ上よろしくないみたいです

```jsx
(⎈ |jukai:tekton-pipelines)❯ kubectl get pod
NAME                                           READY   STATUS    RESTARTS   AGE
tekton-dashboard-6bdbc955c6-crfpt              1/1     Running   0          15s
tekton-pipelines-controller-6486ffc547-7xnwl   1/1     Running   0          16m
tekton-pipelines-webhook-77d7486ddf-hscxk      1/1     Running   0          16m
```
入っていそうですね

```jsx
(⎈ |jukai:tekton-pipelines)❯ kubectl --namespace tekton-pipelines port-forward svc/tekton-dashboard 9097:9097
```

port-forward で確認してみましょう！

![スクリーンショット 2020-12-15 21.44.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640444/2045211b-0d3a-d975-e432-5ffb78e2dbf9.png)

こんな感じで出たら Tekton dashboard のインストールはOKです！

### Tekton cli のインストール

[こちら](https://github.com/tektoncd/cli#installing-tkn)を参考にしてください


## パイプラインの構築
### 概念の説明

Tekton にはいろんな概念があってややこしいので、まずはその説明からします！

- Task
複数の steps を定義してそれを一連の task として定義するリソース
task は Pod として動き、step が container として動く

- TaskRun
走らせる task と、そこで使う resource (Pipelineで使う要素のこと。gitリポジトリなど。)を定義するリソース
こいつを apply すると定義した通りに task が実行される

- PipelineResource
pipeline で使いたいものを input / output として設定
今回だと input が alcatraz のソース(image の作成のため)で、output が image を指す

- Pipeline
複数の task を定義してそれを一連の pipeline として定義するリソース
task の上位の存在(？)と言える

- PipelineRun
実行する pipeline と、そこで使う resource を定義するリソース
これを apply したら pipeline が実行される
特に task と pipeline が似ているが異なることに注意

### 実際に構築
それでは、実際にそれぞれのカスタムリソースを定義していきましょう！
以下では、自分が実際に作った際の順番と同じになっています。

#### 1. PipelineResource

リポジトリでは、[tekton/pipeline-resouces](https://github.com/bamboooo-dev/alcatraz-tekton/tree/main/tekton/pipeline-resources) に定義しています。
定義の仕方以外は特に注意点などはないです。
ちなみに自分は、ブランチ名が master から main に変わったのを忘れ revision を master にしていて時間を溶かしました。

#### 2. Task

リポジトリでは、[tekton/tasks](https://github.com/bamboooo-dev/alcatraz-tekton/tree/main/tekton/tasks) に定義しています。

以下のように step では公式が推奨している[Kaniko](https://github.com/GoogleContainerTools/kaniko)を使用しています。
Kaniko とは Dockerデーモンに依存することなくコンテナ内でイメージをビルドするツールです。
Kaniko については、[こちらの記事](https://www.infoq.com/jp/news/2018/05/kaniko-container-image-builder/)がわかりやすかったです。

ちなみに、steps については Tekton 公式のチュートリアル通りに書くと動かなかったので注意してください。
理由は忘れてしまったので思い出したら追記します。。。

```jsx
steps:
    - name: ui-build-push
      image: gcr.io/kaniko-project/executor:latest
      # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential
      env:
        - name: "DOCKER_CONFIG"
          value: "/tekton/home/.docker/"
      command:
        - /kaniko/executor
      args: ["--dockerfile=$(params.pathToDockerfile)",
             "--context=$(params.pathToContext)",
             "--destination=$(resources.outputs.built-ui-image.url)"]
```

#### 3. Pipeline

リポジトリでは、[tekton/pipeline](https://github.com/bamboooo-dev/alcatraz-tekton/tree/main/tekton/pipeline) に定義しています。

以下のように task に渡す params の値に `/workspace/(repo名)-resouce` が挟まっていますが、これは Kaniko の仕様です。

```jsx
tasks:
    - name: api-image-build-push
      taskRef:
        name: api-image-build-push
      params:
        - name: pathToDockerfile
          value: /workspace/alcatraz-resource/api/Dockerfile
        - name: pathToContext
          value: /workspace/alcatraz-resource/api
```

#### 4. PipelineRun

リポジトリでは、[tekton/pipelinerun](https://github.com/bamboooo-dev/alcatraz-tekton/tree/main/tekton/pipelinerun) に定義しています。

以下のように、PipelineRunの際に使用する ServiceAccount が定義されています。

```jsx
spec:
  serviceAccountName: image-builder
```
これはリポジトリ内の[ここ](https://github.com/bamboooo-dev/alcatraz-tekton/blob/main/serviceaccount.yaml)で定義しています。

この ServiceAccount に紐づく Secret は Dockerhub のログイン情報で、 PipelineRun を apply する前に用意が必要です。
以下のようにして作成できます。

```jsx
kubectl create secret docker-registry dockerhub-cred \
                    --docker-username=<your-name> \
                    --docker-password=<your-pword> \
                    --docker-email=<your-email>
```

Dockerhub 以外の registry を使用する場合は、公式ドキュメントの[こちら](https://github.com/tektoncd/pipeline/blob/master/docs/tutorial.md#configuring-task-execution-credentials)を参考にしてください。

以上で CI Pipeline の構築は完了です！

それでは、実際に PipelineRun を apply して Pipeline を実行し、image が push されていることを確認してみましょう！

## Pipeline の実行

前提として、先ほど定義した PipelineRun 以外のカスタムリソースを全て apply しておいてください。

image を push先はここです。
現時点では何も入っていないですね。
![スクリーンショット 2020-12-16 20.59.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640444/72759fef-2f2d-ffac-8604-51c4dbbdd962.png)


それでは、PipelineRun を実行し Tekton Dashboard で確認してみましょう！

まずは Tekton Dashboard を見られるようにします

```jsx
(⎈ |jukai:tekton-pipelines)❯ kubectl port-forward svc/tekton-dashboard 9097:9097 -n tekton-pipelines
```

Task もキチンと定義できてますね
![スクリーンショット 2020-12-16 20.42.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640444/b38171ad-2063-77b3-6d2c-08b44d13ae6c.png)


それでは　Dashboard を見つつ、以下のコマンドで PipelineRun を apply します

```jsx
~/bamboooo/alcatraz-ci-cd/tekton
(⎈ |jukai:tekton-pipelines)❯ kubectl apply -f pipelinerun
```

PipelineRun が実行されている様子が確認できます！
![スクリーンショット 2020-12-16 20.46.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640444/c42f82ac-17d0-8a9f-6036-069deaf14024.png)


完了したみたいですね
![スクリーンショット 2020-12-16 21.24.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640444/eb34d28d-fa1d-ca87-7cd8-02e03fdfa282.png)



dockerhub を見てみましょう
![スクリーンショット 2020-12-16 21.16.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640444/bc5834e5-8803-bd24-6519-8cbab8c30eb1.png)

image が push できています！！


次回は、github の webhook と [Tekton Triggers](https://github.com/tektoncd/triggers) を使って、git push されるたびに image が build & push されるようにしますのでお楽しみに！


# 最後に
※この記事は [WESEEK Tips wiki](https://tips.weseek.co.jp/) に 2020/12/16 に投稿された記事の転載です。
Tips wiki では、IT企業の技術的な情報やプロジェクトの情報を公開可能な範囲で公開しています。