.NET 6 と Daprを使った分散サービス開発 その13 Kubernetesにデプロイ

# Kubernetes

前回までは、Dockerイメージを作成し、レジストリにPushするところまでを行いました。
今回は、Kubernetes にデプロイします。

----
https://qiita.com/kazumihirose/items/f3ef40e1c1abaa7743f3

https://qiita.com/kazumihirose/items/ec98a49743d24702cce5

https://qiita.com/kazumihirose/items/d6d98d2e482947aad936

https://qiita.com/kazumihirose/items/aa34373369ce818e8027

https://qiita.com/kazumihirose/items/ff13fa45bf797e6eb878

https://qiita.com/kazumihirose/items/58d0127212068563fe27

https://qiita.com/kazumihirose/items/45b0ea36dd50d63f1d86

https://qiita.com/kazumihirose/items/701fcbfb397fe8670bf7

https://qiita.com/kazumihirose/items/016dde8ca9b35d1030cc

https://qiita.com/kazumihirose/items/e996e3cc34c511bc1124

https://qiita.com/kazumihirose/items/f7811bf3e5abe405a551

https://qiita.com/kazumihirose/items/57e3aeaab65a1a68977b

## Kubernetes にデプロイ

まず、Kubernetes にデプロイする為に、あらかじめkubectlが扱える環境である必要があります。インストールできていない方は、各Windowsなり、Macなり、Linuxなり環境に合わせてkubectlが実行できるようにダウンロードし、Pathを通してください。

https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/

私の場合は面倒だったので、Daprのインストールフォルダにそのままkubectlをダウンロードしました。

```bash
C:\dapr>curl -LO "https://dl.k8s.io/release/v1.23.0/bin/windows/amd64/kubectl.exe"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   154  100   154    0     0    380      0 --:--:-- --:--:-- --:--:--   381
100 45.6M  100 45.6M    0     0  14.3M      0  0:00:03  0:00:03 --:--:-- 21.9M

```

```bash
$ kubectl
kubectl controls the Kubernetes cluster manager.

 Find more information at: https://kubernetes.io/docs/reference/kubectl/overview/
```

### AKS (Azure Kubernetes Service) とACRの統合

もし、今から新規作成でAKSを作成するのであれば、オプションでACR (Azure Container Registry)との統合を選んで新規に作成するAKSからアタッチしてください。面倒な認証周りで、AKSとACRの統合をしてくれます。

もし、既にAKSを統合せずに作成している場合は、設定の更新を行い統合してください。

https://docs.microsoft.com/ja-jp/azure/aks/cluster-container-registry-integration?tabs=azure-cli

```bash
$ az aks update -n AKS名 -g リソースグループ名 --attach-acr ACR名
```

### Kubernetes にログイン

kubectlでログインできるのであれば、どの Kubernetes でも大丈夫です。ここでは、Azure で AKS (Azure Kubernetes Service) を一つ作り、ログインする為にクレデンシャルを取得しています。

```bash
$ az aks get-credentials --resource-group リソースグループ名 --name AKSの名称
Merged "AKS名称" as current context in C:\Users\kahiro\.kube\config
```

#### 接続の確認

クレデンシャルを取得したら、Kubernetes 管理APIに接続してみます。ここでは、デプロイメントの状況をリストで表示しています。

```bash
$ kubectl get deployments --all-namespaces=true
NAMESPACE     NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   coredns              2/2     2            2           20m
kube-system   coredns-autoscaler   1/1     1            1           20m
kube-system   konnectivity-agent   2/2     2            2           20m
kube-system   metrics-server       1/1     1            1           20m
```

### Dapr を Kubernetes にインストール(初回のみ）

ローカルでの環境整備の際にDaprをインストールしましたが、新しく作成した Kubernetes 環境にDaprはインストールされていませんので、サイドカーとして起動できるようにインストールします。

なお、今回は開発チームで共有している Kubernetes へのデプロイとして解説しています。もし、プロダクション環境などにインストールする場合 dapr init -k --enable-ha=true を実行してください。3つのレプリカが起動するようになります。

また、試験環境など Kubernetes のノード性能によっては、セットアップに時間がかかるケースもあります。その場合は、 dapr init -k --wait --timeout 600 のようにタイムアウトを指定して待ってあげてください。

```bash
$ dapr init -k
Making the jump to hyperspace...
Note: To install Dapr using Helm, see here: https://docs.dapr.io/getting-started/install-dapr-kubernetes/#install-with-helm-advanced

Deploying the Dapr control plane to your cluster...
Success! Dapr has been installed to namespace dapr-system. To verify, run `dapr status -k' in your terminal. To get started, go here: https://aka.ms/dapr-getting-started
```

#### Daprインストール状況の確認

デプロイできたか確認しましょう、以下のようにdapr-systemのNAMESPACEで起動していればOKです。

```bash
$ kubectl get deployments --all-namespaces=true
NAMESPACE     NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
dapr-system   dapr-dashboard          1/1     1            1           87s
dapr-system   dapr-operator           1/1     1            1           87s
dapr-system   dapr-sentry             1/1     1            1           87s
dapr-system   dapr-sidecar-injector   1/1     1            1           87s
kube-system   coredns                 2/2     2            2           25m
kube-system   coredns-autoscaler      1/1     1            1           25m
kube-system   konnectivity-agent      2/2     2            2           25m
kube-system   metrics-server          1/1     1            1           25m
```

### tyeでデプロイ
Daprのセットアップも終わったら、tyeを使ってデプロイしてみます。
基本的に、tye deployコマンドは以下のことを自動でやってくれます。

#### 前処理 Namespace設定

まず、今まで名前空間の設定を一切行ってなくて、お行儀が悪かったので、きちんとnamespaceを設定します。

```bash:(名前空間作成)
$ kubectl create namespace daprqiitaaks
namespace/daprqiitaaks created
```

#### component設定

componentsフォルダに移動し、 Kubernetes に設定を適用します。
が、metanameの命名規則に沿ってなかった為にエラーが出てしまいましたので、修正して再度適用します。
加えて、 Kubernetes の名前空間に合わせて、NAMESPACEを設定します。

```bash
$ kubectl apply -f cron-binding.yaml
The Component "Job" is invalid: metadata.name: Invalid value: "Job": a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')
```

- Jobからjobへ変更
- namespaceの適用

```yaml:cron-binding.yaml (修正後)
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: job
  namespace: daprqiitaaks
spec:
  type: bindings.cron
  version: v1
  metadata:
  - name: schedule
    value: "@every 10s"
scopes:
- servicea
```

以下コマンドで適用処理

```bash
$ kubectl apply -f cron-binding.yaml
component.dapr.io/job created
```

#### tye.yamlにも名前空間を追加
デプロイを行う際に、tyeは名前空間に合わせてマニフェストを作成し、デプロイをしてくれます。

```YAML:tye.yaml
# tye application configuration file
# read all about it at https://github.com/dotnet/tye
#
# when you've given us a try, we'd love to know what you think:
#    https://aka.ms/AA7q20u
#
name: daprqiitaaks
namespace: daprqiitaaks # 名前空間を追加
registry: kahiro.azurecr.io
extensions:
- name: dapr
  log-level: debug
  components-path: "./components/"
services:
- name: servicea
  project: ServiceA/ServiceA.csproj
- name: serviceb
  project: ServiceB/ServiceB.csproj
```

以下のコマンドでデプロイします。

```bash:(tyeを使ったKubernetes へのデプロイ）
$ tye deploy
Loading Application Details...
Verifying kubectl installation...
Verifying kubectl connection to cluster...
Processing Service 'servicea'...
    Applying container defaults...
    Compiling Services...
    Publishing Project...
    Building Docker Image...
            #1 [internal] load build definition from Dockerfile
            # ... ... ...中略 ... ... ...
            #8 DONE 0.0s

            Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
        Created Docker Image: 'kahiro.azurecr.io/servicea:1.0.0'
    Pushing Docker Image...
        Pushed docker image: 'kahiro.azurecr.io/servicea:1.0.0'
    Validating Secrets...
    Generating Manifests...
Processing Service 'serviceb'...
    Applying container defaults...
    Compiling Services...
    Publishing Project...
    Building Docker Image...
            #1 [internal] load build definition from Dockerfile
            # ... ... ...中略 ... ... ...
            #8 DONE 0.0s

            Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
        Created Docker Image: 'kahiro.azurecr.io/serviceb:1.0.0'
    Pushing Docker Image...
        Pushed docker image: 'kahiro.azurecr.io/serviceb:1.0.0'
    Validating Secrets...
    Generating Manifests...
Deploying Application Manifests...
    Applying Kubernetes Manifests...
        Verifying kubectl installation...
        Verifying kubectl connection to cluster...
        Writing output to 'tmp5997.tmp'.
        Deployed application 'daprqiitaaks'.
Time Elapsed: 00:00:12:51
```

#### デプロイの確認

デプロイできたか確認しましょう、以下のようにdaprqiitaaksのNAMESPACEで起動していればOKです。

```bash
$ kubectl get deployments --all-namespaces=true
NAMESPACE      NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
dapr-system    dapr-dashboard          1/1     1            1           34m
dapr-system    dapr-operator           1/1     1            1           34m
dapr-system    dapr-sentry             1/1     1            1           34m
dapr-system    dapr-sidecar-injector   1/1     1            1           34m
daprqiitaaks   servicea                1/1     1            1           45s
daprqiitaaks   serviceb                1/1     1            1           45s
kube-system    coredns                 2/2     2            2           58m
kube-system    coredns-autoscaler      1/1     1            1           58m
kube-system    konnectivity-agent      2/2     2            2           58m
kube-system    metrics-server          1/1     1            1           58m
```

ポータルからも確認できます。また、サイドカーとしてDaprが動作している様子も確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/439706fc-63c4-85ba-ac9b-2d162ab42c5c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/129d6780-0694-2fce-8f52-93dccb8b4a33.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/360152c5-e58e-4327-e729-b1d4e3cc4430.png)

#### Dapr dashboard

Tyeでもダッシュボードがありましたが、今までは使ってきませんでしたが、Daprにもダッシュボードがあります。

```bash
$ dapr dashboard -k
```

Kubernetes からポートがトンネリングされ、localhost:8080からダッシュボードを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/89494698-79d2-a62e-7861-c2e7c60ff9d0.png)

#### ログの確認

設定したコンポーネントが正しく動作しているか確認します。
以下のように　kubectl logs Podの名称 -c コンテナー名 -n NAMESPACE でログを確認します。
私の場合は、以下のような名称でPodが作成されていました。
問題なく、Cronコンポーネントによる呼び出しが行えているようです。

```bash
$ kubectl logs servicea-857468694f-59cmj -c servicea -n daprqiitaaks
{"EventId":14,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Now listening on: http://[::]:80","State":{"Message":"Now listening on: http://[::]:80","address":"http://[::]:80","{OriginalFormat}":"Now listening on: {address}"}}
{"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Application started. Press Ctrl\u002BC to shut down.","State":{"Message":"Application started. Press Ctrl\u002BC to shut down.","{OriginalFormat}":"Application started. Press Ctrl\u002BC to shut down."}}
{"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Hosting environment: Production","State":{"Message":"Hosting environment: Production","envName":"Production","{OriginalFormat}":"Hosting environment: {envName}"}}
{"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Content root path: /app/","State":{"Message":"Content root path: /app/","contentRoot":"/app/","{OriginalFormat}":"Content root path: {contentRoot}"}}
ServiceA.JobResponse
ServiceA.JobResponse
ServiceA.JobResponse
ServiceA.JobResponse
ServiceA.JobResponse
ServiceA.JobResponse
ServiceA.JobResponse
```

### レプリカを増やす

詳しくはTyeのリファレンスを見てくださいとなってしまうのですが、ポートの設定やレプリカの設定などをtye.yamlに行っておく事ができます。ここでは、レプリカ数を増やしてみます。

https://github.com/dotnet/tye/blob/main/docs/reference/schema.md

```YAML:tye.yaml
# tye application configuration file
# read all about it at https://github.com/dotnet/tye
#
# when you've given us a try, we'd love to know what you think:
#    https://aka.ms/AA7q20u
#
name: daprqiitaaks
namespace: daprqiitaaks
registry: kahiro.azurecr.io
extensions:
- name: dapr
  log-level: debug
  components-path: "./components/"
services:
- name: servicea
  project: ServiceA/ServiceA.csproj
  replicas: 2
- name: serviceb
  project: ServiceB/ServiceB.csproj
  replicas: 2
```

設定したら、以下のコマンドで設定を適用します。

```bash
$ tye deploy
```

servicea , serviceb 共に、READYが1から2に変わりました。

```bash
$ kubectl get deployments --all-namespaces=true
NAMESPACE      NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
dapr-system    dapr-dashboard          1/1     1            1           10h
dapr-system    dapr-operator           1/1     1            1           10h
dapr-system    dapr-sentry             1/1     1            1           10h
dapr-system    dapr-sidecar-injector   1/1     1            1           10h
daprqiitaaks   servicea                2/2     2            2           15m
daprqiitaaks   serviceb                2/2     2            2           15m
kube-system    coredns                 2/2     2            2           11h
kube-system    coredns-autoscaler      1/1     1            1           11h
kube-system    konnectivity-agent      2/2     2            2           11h
kube-system    metrics-server          1/1     1            1           11h
```