🎩

Dapr Tutorials - Hello World Kubernetes をやってみた

2023/11/30に公開

Dapr入門 です。
今回は、前回構築したアプリケーションをminikubeにデプロイします。

https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes

環境

WSL2 Ubuntu 22.04
minikube 1.32.0
dapr 1.12.0
Helm v3

構成

公式より拝借しました。
構成

手順としては2種類あるようで、dapr コマンドで一括ドカーンと作るパターンと kubectl で粛々と作っていくパターンがあるようです。
では、dapr コマンドで作るパターンから始めていきます。

Using Dapr Multi-app run with Dapr dev mode deployment

Prerequisites

使用するソースコードを git からクローンします。

$ git clone https://github.com/dapr/quickstarts.git
$ cd quickstarts/tutorials/hello-kubernetes

minikube は起動させておきます。(私は忘れてdaprインストールできなくてうんうんしてました笑)

$ minikube start

Step 1 - Setup Dapr dev mode on your Kubernetes cluster

minikube に Dapr をデプロイします。

$ dapr init -k --dev
⌛  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

ℹ️  Container images will be pulled from Docker Hub
✅  Deploying the Dapr control plane with latest version to your cluster...
✅  Deploying the Dapr dashboard with latest version to your cluster...
✅  Deploying the Dapr Redis with latest version to your cluster...
✅  Deploying the Dapr Zipkin with latest version to your cluster...
ℹ️  Applying "statestore" component to Kubernetes "default" namespace.
ℹ️  Applying "pubsub" component to Kubernetes "default" namespace.
ℹ️  Applying "appconfig" zipkin configuration to Kubernetes "default" namespace.
✅  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

Step 2 - Run the Multi-app run template to deploy both the Node.js and Python apps

Node.js と Python アプリの両方を実行します。

$ dapr run -k -f dapr.yaml
ℹ️  This is a preview feature and subject to change in future releases.
ℹ️  Validating config and starting app "nodeapp"
ℹ️  Deploying app "nodeapp" to Kubernetes
ℹ️  Deploying service YAML "/home/user/GitHub/dapr/quickstarts/tutorials/hello-kubernetes/node/.dapr/deploy/service.yaml" to Kubernetes
ℹ️  Deploying deployment YAML "/home/user/GitHub/dapr/quickstarts/tutorials/hello-kubernetes/node/.dapr/deploy/deployment.yaml" to Kubernetes
ℹ️  Streaming logs for containers in pod "nodeapp-6998f8844b-xhczb"
ℹ️  Writing log files to directory : /home/user/GitHub/dapr/quickstarts/tutorials/hello-kubernetes/node/.dapr/logs
ℹ️  Validating config and starting app "pythonapp"
ℹ️  Deploying app "pythonapp" to Kubernetes
ℹ️  Deploying deployment YAML "/home/user/GitHub/dapr/quickstarts/tutorials/hello-kubernetes/python/.dapr/deploy/deployment.yaml" to Kubernetes
== APP - nodeapp == Node App listening on port 3000!
ℹ️  Streaming logs for containers in pod "pythonapp-56675c86ff-q9vqq"
ℹ️  Writing log files to directory : /home/user/GitHub/dapr/quickstarts/tutorials/hello-kubernetes/python/.dapr/logs
ℹ️  Starting to monitor Kubernetes pods for deletion.
== APP - nodeapp == Got a new order! Order ID: 3
== APP - nodeapp == Successfully persisted state for Order ID: 3
== APP - nodeapp == Got a new order! Order ID: 4
== APP - nodeapp == Successfully persisted state for Order ID: 4

アプリを終了する場合は以下のコマンドか、Ctrl+C で止めます。
(止まるのに少し時間がかかります)

$ dapr stop -k -f dapr.yaml

Using the kubectl CLI

上記は、dapr コマンドで一括にデプロイする方法でした。
ここからはいつも通り kubectl を使ったやり方で、デプロイをしていきます。

Step 1 - Setup Dapr on your Kubernetes cluster

$ dapr init --kubernetes --wait
⌛  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

ℹ️  Container images will be pulled from Docker Hub
✅  Deploying the Dapr control plane with latest version to your cluster...
✅  Deploying the Dapr dashboard with latest version 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 のコントロールブレーンが完全にデプロイされているかは、以下のコマンドで確認できます。
全て Running になっていればOK。

$ dapr status -k
  NAME                   NAMESPACE    HEALTHY  STATUS   REPLICAS  VERSION  AGE  CREATED
  dapr-dashboard         dapr-system  True     Running  1         0.14.0   5m   2023-11-30 10:52.38
  dapr-sidecar-injector  dapr-system  True     Running  1         1.12.2   5m   2023-11-30 10:52.27
  dapr-operator          dapr-system  True     Running  1         1.12.2   5m   2023-11-30 10:52.27
  dapr-sentry            dapr-system  True     Running  1         1.12.2   5m   2023-11-30 10:52.27
  dapr-placement-server  dapr-system  True     Running  1         1.12.2   5m   2023-11-30 10:52.27

Step 2 - Create and configure a state store

状態ストアは Redis、CosmosDB、DynamoDB、Cassandra などいろいろ使えるようです。
ここではRedisを使います。

  1. まずは Redis を minikibe にインストールします。helmを使います。
    https://docs.dapr.io/getting-started/tutorials/configure-state-pubsub/#step-1-create-a-redis-store
$ helm repo add bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "argo" chart repository
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm install redis bitnami/redis --set image.tag=6.2
NAME: redis
LAST DEPLOYED: Thu Nov 30 11:02:30 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redis
CHART VERSION: 18.4.0
APP VERSION: 7.2.3

** Please be patient while the chart is being deployed **

Redis® can be accessed on the following DNS names from within your cluster:

    redis-master.default.svc.cluster.local for read/write operations (port 6379)
    redis-replicas.default.svc.cluster.local for read-only operations (port 6379)



To get your password run:

    export REDIS_PASSWORD=$(kubectl get secret --namespace default redis -o jsonpath="{.data.redis-password}" | base64 -d)

To connect to your Redis® server:

1. Run a Redis® pod that you can use as a client:

   kubectl run --namespace default redis-client --restart='Never'  --env REDIS_PASSWORD=$REDIS_PASSWORD  --image docker.io/bitnami/redis:6.2 --command -- sleep infinity

   Use the following command to attach to the pod:

   kubectl exec --tty -i redis-client \
   --namespace default -- bash

2. Connect using the Redis® CLI:
   REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis-master
   REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis-replicas

To connect to your database from outside the cluster execute the following commands:

    kubectl port-forward --namespace default svc/redis-master 6379:6379 &
    REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h 127.0.0.1 -p 6379
WARNING: Rolling tag detected (bitnami/redis:6.2), please note that it is strongly recommended to avoid using rolling tags in a production environment.
+info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/

Redis のコンテナが起動したか確認します。

$ kubectl get pods
NAME               READY   STATUS    RESTARTS   AGE
redis-master-0            1/1     Running   0          19s
redis-replicas-0          1/1     Running   0          19s
redis-replicas-1          1/1     Running   0          19s
redis-replicas-2          1/1     Running   0          18s
  1. ディレクトリのファイルにキーを追加します。

These settings will work out of the box if you use helm install bitnami/redis.

とあるので、今回はそのままで動くようです。

deploy/redis.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  # These settings will work out of the box if you use `helm install
  # bitnami/redis`.  If you have your own setup, replace
  # `redis-master:6379` with your own Redis master address, and the
  # Redis password with your own Secret's name. For more information,
  # see https://docs.dapr.io/operations/components/component-secrets .
  - name: redisHost
    value: redis-master:6379
  - name: redisPassword
    secretKeyRef:
      name: redis
      key: redis-password
auth:
  secretStore: kubernetes

The secret, redis, is created automatically

シークレットは redis という名前で自動作成してくれるようなので、そのままにします。

  1. ファイルを適用します。
$ kubectl apply -f ./deploy/redis.yaml
component.dapr.io/statestore configured

Step 3 - Deploy the Node.js app with the Dapr sidecar

Dapr サイドカーを使用して Node.js アプリをデプロイします。

$ kubectl apply -f ./deploy/node.yaml
service/nodeapp created
deployment.apps/nodeapp created

デプロイが完了したかどうか確認します。

$ kubectl rollout status deploy/nodeapp
deployment "nodeapp" successfully rolled out

よさそう。

このタイミングで自動的に dapr サイドカーも一緒にデプロイされているようです。
ちょっと見てみます。

$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
nodeapp-6b65576f5-br4h4   2/2     Running   0          2m12s
redis-master-0            1/1     Running   0          19m
redis-replicas-0          1/1     Running   0          19m
redis-replicas-1          1/1     Running   0          19m
redis-replicas-2          1/1     Running   0          18m

$ kubectl describe pod nodeapp-6b65576f5-br4h4
### 省略
Containers:
  node:
    Container ID:   docker://d9a6035ef5391daabe7709cb43212c8dbb7a207dd87a9478b2da88bd92590da4
    Image:          ghcr.io/dapr/samples/hello-k8s-node:latest
    Image ID:       docker-pullable://ghcr.io/dapr/samples/hello-k8s-node@sha256:0f51eef9148fc5f7cada346af20667216e3e6cbde372fa197524cd2946f83ebb
    Port:           3000/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Thu, 30 Nov 2023 11:20:17 +0900
    Ready:          True
    Restart Count:  0
    Environment:
      APP_PORT:        3000
      DAPR_HTTP_PORT:  3500
      DAPR_GRPC_PORT:  50001
      APP_PROTOCOL:    http
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pzjrw (ro)
  daprd:
    Container ID:  docker://efbcd6ef558c2dc8d6dc58470dd6af8e0b377c0a87b6917ae5ca7dde33ac2aa8
    Image:         docker.io/daprio/daprd:1.12.2
    Image ID:      docker-pullable://daprio/daprd@sha256:c9117a6131c3df620fef01a423dcb141b3c3202bf7f15a6eca7c347ae436f525
    Ports:         3500/TCP, 50001/TCP, 50002/TCP, 9090/TCP
    Host Ports:    0/TCP, 0/TCP, 0/TCP, 0/TCP
### 省略

おーいますねぇ daprd コンテナ。
仕組みとしては annotations をつけるだけで良いみたいです。

deploy/node.yaml
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "nodeapp"
        dapr.io/app-port: "3000"
        dapr.io/enable-api-logging: "true"

Node.js アプリが起動したので、8080をポートフォワードしてサービスを利用できるようにします。

$ kubectl port-forward service/nodeapp 8080:80
Forwarding from 127.0.0.1:8080 -> 3000
Forwarding from [::1]:8080 -> 3000

Step 4 - Verify Service

ポートフォワードしたサービスを以下のコマンドで確認します。

$ curl http://localhost:8080/ports
{"DAPR_HTTP_PORT":"3500","DAPR_GRPC_PORT":"50001"}

Node.js アプリに注文のリクエストを投げます。

$ curl --request POST --data "@sample.json" --header Content-Type:application/json http://localhost:8080/neworder

注文が永続化されたことを確認します。

$ curl http://localhost:8080/order
{"orderId":"42"}

うまくいきました。

Step 5 - Deploy the Python app with the Dapr sidecar

次はPythonアプリをデプロイします。
Python アプリは localhost:3500 に Postを1秒ごとに投げる子です。
3500 は dapr のデフォルト HTTPポートなので、 dapr runtime は受け流して nodepp に流す、ということをしてるらしいです。

url 的には v1.0/invoke/nodeapp/method/neworder に展開されるみたいですけど、アプリが複数あったらどこに行くかわからないのでは?と思いきや、HTTPヘッダでちゃんと宛先のアプリが指定されてました。

python/app.py
        response = requests.post(dapr_url, json=message, timeout=5, headers = {"dapr-app-id": "nodeapp"} )

というわけで、デプロイします。

$ kubectl apply -f ./deploy/python.yaml
deployment.apps/pythonapp created

デプロイも確認して。

$ kubectl rollout status deploy/pythonapp
deployment "pythonapp" successfully rolled out

Step 6 - Observe messages

Node.js のアプリの監視ログを確認します。
うまくいくとこのようなログが出るとか。

$ kubectl logs --selector=app=node -c node --tail=-1
Node App listening on port 3000!
DAPR_HTTP_PORT: 3500
DAPR_GRPC_PORT: 50001
Got a new order! Order ID: 42
Successfully persisted state for Order ID: 42
Got a new order! Order ID: 2
Successfully persisted state for Order ID: 2
Got a new order! Order ID: 3
Successfully persisted state for Order ID: 3
Got a new order! Order ID: 4
Successfully persisted state for Order ID: 4

Step 7 - Observe API call logs

API 呼び出しログも見てみます。
まずはNode.js 側から。

$ kubectl logs --selector=app=node -c daprd --tail=-1
### 
time="2023-11-30T06:57:20.841375634Z" level=info msg="HTTP API Called" app_id=nodeapp instance=nodeapp-6b65576f5-79zp5 method="POST /v1.0/state/statestore" scope=dapr.runtime.http-info type=log useragent="node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" ver=1.12.2
time="2023-11-30T06:57:21.848303956Z" level=info msg="HTTP API Called" app_id=nodeapp instance=nodeapp-6b65576f5-79zp5 method="POST /v1.0/state/statestore" scope=dapr.runtime.http-info type=log useragent="node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" ver=1.12.2

healthz のリクエストばっかりで見つけるのつらいですがいました。

次は Python 側。

$ kubectl logs --selector=app=python -c daprd --tail=-1
### 
time="2023-11-30T07:00:19.975003722Z" level=info msg="HTTP API Called" app_id=pythonapp instance=pythonapp-974db9877-7xwkt method="POST /neworder" scope=dapr.runtime.http-info type=log useragent=python-requests/2.31.0 ver=1.12.2
time="2023-11-30T07:00:20.980843313Z" level=info msg="HTTP API Called" app_id=pythonapp instance=pythonapp-974db9877-7xwkt method="POST /neworder" scope=dapr.runtime.http-info type=log useragent=python-requests/2.31.0 ver=1.12.2

Step 8 - Confirm successful persistence

Node.js の order エンドポイントを呼び出して、最新の注文を取得します。

$ curl http://localhost:8080/order
{"orderId":469}

増えてるのでよし👌

Step 9 - Cleanup

最後にお掃除です。

$ kubectl delete -f deploy/
service "nodeapp" deleted
deployment.apps "nodeapp" deleted
deployment.apps "pythonapp" deleted
component.dapr.io "statestore" deleted

おわりに

なんかstoreの設定の更新がうまくいかなくて、時間を溶かしたりしましたが、結果少しは慣れてきたのでよしとします😉

次はPub/Subのチュートリアルかな。
それでは。

Discussion