HarnessでGKEクラスタにCDパイプラインを構築する

# はじめに

実務において[Harness](https://www.harness.io/)を使用する機会があったので、お試しがてらGKEクラスタ上にCDパイプラインの構築を行います。

（※なお、今回はHarnessの使用に焦点を当てているため、CIの実装については考慮しておりません）

【対象】
- [Harness](https://www.harness.io/)に初めて触れる方

### Harnessとは？
- 一言でいうと、**CI/CDツール**
    - https://harness.dxable.com/
- 多様なクラウドプロバイダーと連携可能な点が個人的には最大の魅力だと思っています！




### 使用環境
今回、実践する環境は以下です。

- Artifact Registory
    - [Github Container Registory](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry)
- クラスター
    - GKE
- マニフェストファイル
    - helm
- CD
    - Harness

### 前提

- GKEクラスタが作成されていること
- helmがインストールされていること

# 手順

大まかな手順とやることとしては以下になります。

1. `helm create` でマニフェストファイルを作成し、github リポジトリにpush
2. Github PackegesのContainer Registoryにイメージをpush
3. GKEクラスタがプライベートレジストリにアクセスできるように`ImagePullSecrets`を作成する
4. Harness上でCDパイプラインを構築
    
    Harnessで作成が必要なコンポーネントは以下
    
    ```txt
    - Github Connector
    - GoogleCloud Connector
    - Harness Components
        - Service
        - Environment
    - Pipeline Trigger
    ```
    

# helm

`helm create` で簡易的なマニフェストファイルを作成します。

```bash
$ mkdir harness-sample-dir && cd harness-sample-dir
$ helm create harness-sample && cd harness-sample

$ tree
.
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml
```

これに追加で、stg環境用とprod環境用の2つのvalusファイルを作成します。

```bash
$ tree
.
├── Chart.yaml
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   └── serviceaccount.yaml
├── values
│   ├── prod.yaml
│   └── stg.yaml
└── values.yaml
```

CDパイプラインの確認ができれば良いので、中身はreplica数のみ記述した簡易的なものにします。

```yaml:values/stg.yaml
replicaCount: 1
```

```yaml:values/prod.yaml
replicaCount: 2
```

今回はHarnessを使用してデプロイを行いますが、手動でクラスタへデプロイしたい場合は以下コマンドでデプロイできます。
`NAMESPACES`は自分でstg環境用のものと、prod環境用のものを作成します。

```bash
# /harness-sample-dir
helm install harness-sample ./harness-sample -f ./harness-sample/values.yaml -n NAMESPACES
```

# Github Container Registory

次に、[公式doc](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry#container-registry%E3%81%A7%E3%81%AE%E8%AA%8D%E8%A8%BC)を参照してGithub Container Registoryの設定を行います。

### Dockerfile
dockerfileはシンプルなものを用意し、プロジェクトのルートディレクトリにおきます。
```dockerfile
FROM --platform=linux/amd64 nginx:1.25.1-alpine-slim
```

### 認証手順

[personal access token (classic)](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry#personal-access-token-classic)で認証を行います

作成するpersonal access token (classic)の権限は以下を付与

```text
- admin:repo_hook
- write:packages
- delete:packages
- repo
- user
```

認証が完了して、`docker build`,  `docker push` をし、Github Container Registoryにイメージが登録されていることを確認します。

# **ImagePullSecrets**の作成

[Kubernetesで private registry のイメージをPull する場合には ImagePullSecretsを使う](https://medium.com/makotows-blog/kubernetes-private-registry-tips-image-pullsecretse-20dfb808dfc-e20dfb808dfc)必要があるため、以下コマンドでsecretの作成を行います。

**secretはnamespaceごとに設定する必要があります。**

（GKEクラスタから ghcr.io へアクセスするために必要）

`GITHUB_USER_NAME`, `GITHUB_ACCESS_TOKEN`にgithubのユーザー名、アクセストークンを設定します。

また、`NAMESPACES`にデプロイするnamaspaceを設定します。

```bash
kubectl create secret docker-registry regcred --docker-server=https://ghcr.io --docker-username=GITHUB_USER_NAME --docker-password=GITHUB_ACCESS_TOKEN -n NAMESPACES
```

**※**`ImagePullSecrets`を設定しないと、Pipeline実行時にイメージ取得のエラー（`ErrImagePull`）になります。

# Harness
Harnessでパイプラインを構築していきます。基本的には、GUI上でポチポチしていくだけなのですが、初めて触るとコンポーネントの概念が少しややこしかったりするので、[公式doc](https://developer.harness.io/docs/getting-started/harness-first-gen-vs-harness-next-gen/#mapping-firstgen-to-nextgen-entities)に目を通してから実践すると良いと思います。

### Pipeline

デプロイや承認などのフローに関する設定を行います。

今回のパイプラインの流れは下記のようにしました。

```text
1. stg deploy 承認
2. stg deploy
3. prod deploy 承認
4. prod deploy
```

![スクリーンショット 2023-08-10 14.06.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669969/34b1569c-ee37-bf1e-87bf-8443c9c60475.png)


### Services

デプロイするサービスに関する設定。

まず、サービスがどのようにデプロイされるか（例えば、Kubernetes、Native Helm、Serverlessなど）デプロイのプラットフォームを選択します。

その後、デプロイするマニフェストファイルや、イメージを取得するArtifactsを設定します。（今回は、ここをGithub Container Registoryに指定）

### Environments
デプロイ先のクラスターなどの環境に関する設定を行います。

今回は、単一GKEクラスター上に、`prod` と `stg` の namespace を作成し、それらを別の環境に見立てて Environments を作成しました。

```bash
kubectl create ns stg
```

### Trigger

パイプラインのトリガーに関するリソース。パイプラインの編集画面から作成できます。

今回は、指定のブランチへpushされたタイミングでパイプラインが実行されるようにしました。


### Google Cloud Connector

GoogleCloudとHarnessを接続するために、Connectorを作成します。

認証情報には、[サービス アカウント キーの作成と管理](https://cloud.google.com/iam/docs/creating-managing-service-account-keys?hl=ja#iam-service-account-keys-create-console)を参考に、今回はサービスアカウントキーを使用しました。

### 動作確認

パイプラインの実行が完了すると以下のようになります。

![スクリーンショット 2023-08-10 14.13.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669969/e3be7c61-73f1-54f9-9e46-bad50785399f.png)

GKEを確認すると、指定したnamespaceにデプロイされています。

![スクリーンショット 2023-08-10 14.15.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669969/510b4cea-07fe-95d8-2505-9170403f788c.png)

# ハマりそうなポイント

- `Github Access Token`の権限設定はよく確認
- `ImagePullSecrets`はnamespaceごとに作成する必要がある
- Github Connector , GoogleCloud Connectorの疎通テストを行うこと


# 参考
https://github.com/harness/harness-cd-community