AKS を使いこなす : チュートリアルの深堀り - アプリケーションの実行

今回は[チュートリアル:Azure Kubernetes Service (AKS) でのアプリケーションの実行](https://docs.microsoft.com/ja-jp/azure/aks/tutorial-kubernetes-deploy-application?view=azure-cli-latest)の深堀をしていきます。

このチュートリアルでは作成した AKS クラスタに ACR よりアプリケーションを展開して実行します。

# チュートリアルの深堀

このチュートリアルではマニフェストを適用する事しか説明していませんが、この記事ではその結果どのようなリソースが作成されるか k8s の観点からも詳しく見ていきます。

## デプロイマニフェストの確認と変更

AKS に対する展開はマニフェストを k8s 渡すことで実行します。今回利用するマニフェストはサンプルの [azure-vote-all-in-one-redis.yaml](https://raw.githubusercontent.com/Azure-Samples/azure-voting-app-redis/master/azure-vote-all-in-one-redis.yaml) です。

このマニフェストは「**---**」で仕切られた 4 つのセクションから構成されています。

### 1 つ目のセクション

このセクションはアプリのバックエンドである Redis の展開です。

- apiVersion: 利用する API のバージョン
- kind: 操作の種類。ここでは Deployment が指定されているためポッドのデプロイを実施
- spec.replicas: ポッドの複製を何個作成するか指定。ここでは 1 つ
- spec.template.spec.nodeSelector: ポッドをどのノードに配置するかラベルを使って指定。ここでは "beta.kubernetes.io/os" の値が linux となっているノードを指定しているが、クラスタのデプロイで説明した通り、既定で作成される AKS Linux ノードはこのラベルを持つ
- spec.template.spec.containers.image: image として redis を利用。明示的な指定がないため Docker Hub から取得

```yaml
apiVersion: apps/v1beta1 
kind: Deployment 
metadata:
  name: azure-vote-back
spec: 
  replicas: 1 
  template:
    metadata:
      labels:
        app: azure-vote-back
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: azure-vote-back
        image: redis
        ports:
        - containerPort: 6379
          name: redis
```
尚、この Deployment にはリソースの明示的な指定がないため、VSCode でも指定を推奨するメッセージが出ています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/4e95c370-200c-dab8-a187-ba9982acd091.png)

### 2 つ目のセクション

このセクションは Redis に対するサービスの作成です。

- kind: 操作の種類。ここでは Service を指定しているためサービスを作成
- spec.ports.port: ポート番号
- spec.selector: サービスがルーティングするポッドをラベルで指定

```yaml
apiVersion: v1
kind: Service
metadata:
  name: azure-vote-back
spec:
  ports:
  - port: 6379
  selector:
    app: azure-vote-back
```

### 3 つ目のセクション

このセクションは アプリのフロントエンドの展開です。より詳細な設定が記述されています。ここで元々はイメージのレポジトリとして ```microsoft/azure-vote-front:v1``` が指定されていますが、作成済の ACR から取得できるよう ```kenakamuacr.azurecr.io/azure-vote-front:v1``` に書き換えています。

- spec.strategy.rollingUpdate.maxSurge: アプリを更新する場合、現在のレプリカ数に対して最大何個のポッドを追加できるか指定。パーセンテージでも指定可能。
- spec.strategy.rollingUpdate.maxUnavailable: アプリを更新する場合、既存のポッドで最大何個まで利用不可になってもいいか指定。パーセンテージでも指定可能。
- spec.minReadySeconds: 準備が整うまでに許容される時間(秒)
- containers.resource: コンテナが利用するリソースの要求と制限の指定

```yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: azure-vote-front
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5 
  template:
    metadata:
      labels:
        app: azure-vote-front
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: azure-vote-front
        image: kenakamuacr.azurecr.io/azure-vote-front:v1
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 250m
          limits:
            cpu: 500m
        env:
        - name: REDIS
          value: "azure-vote-back"
```

### 4 つ目のセクション

このセクションはフロントエンドに対するサービスの作成です。

- spec.type: サービスのタイプとしてロードバランサーを指定しているため、背後のポッドに対してラウンドロビンで通信をルーティングする

```yaml
apiVersion: v1
kind: Service
metadata:
  name: azure-vote-front
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: azure-vote-front
```

## アプリケーションのデプロイとテスト

1\. apply コマンドで編集済のマニフェストを AKS に適用する。結果各セクションで指定したリソースが作成される。

```shell
kubectl apply -f azure-vote-all-in-one-redis.yaml
```
```shell
deployment.apps/azure-vote-back created
service/azure-vote-back created
deployment.apps/azure-vote-front created
service/azure-vote-front created
```

2\. フロントエンド用のサービスを確認。外部 IP がアサインされていることを確認。

```shell
kubectl get services azure-vote-front
```
```shell
NAME               TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
azure-vote-front   LoadBalancer   10.0.10.225   20.43.78.36   80:32491/TCP   100s
```

3\. ブラウザで外部 IP へアクセスし、アプリケーションが機能することを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/b45964b5-fbda-b1ef-9ac5-be26a5ff58bd.png)

チュートリアルの手順はこれで終わりですが、ここから詳細を見ていきましょう。

# k8s での動作を確認

k8s にマニフェストを適用すると、裏側で指定された内容に応じで作業が行われます。

## デプロイメント、レプリカセット、ポッド

今回のマニフェストでは 2 つの Deployment が指定されており、以下コマンドで状態を確認できます。

```shell
> kubectl get deployments -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS         IMAGES                                       SELECTOR
azure-vote-back    1/1     1            1           6m11s   azure-vote-back    redis                                        app=azure-vote-back
azure-vote-front   1/1     1            1           6m11s   azure-vote-front   kenakamuacr.azurecr.io/azure-vote-front:v1   app=azure-vote-front
```

また詳細を確認したい場合は ```describe```　を利用します。

- Namespece: 明示的に指定しなかったため既定の名前空間に展開
- Replicas: レプリカセットの状態。ここではすべてが正常
- NewReplicaSet/OldReplicaSet: 現在と以前のレプリカセットの情報。まだ一度しかデプロイしていないため NewReplicaSet のみ存在

```shell
> kubectl describe deployment azure-vote-front
Name:                   azure-vote-front
Namespace:              default
CreationTimestamp:      Tue, 24 Sep 2019 16:27:19 +0900
Labels:                 app=azure-vote-front
Annotations:            deployment.kubernetes.io/revision: 1
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1beta1","kind":"Deployment","metadata":{"annotations":{},"name":"azure-vote-front","namespace":"default"},"spec":{"mi..."}
Selector:               app=azure-vote-front
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        5
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:  app=azure-vote-front
  Containers:
   azure-vote-front:
    Image:      kenakamuacr.azurecr.io/azure-vote-front:v1
    Port:       80/TCP
    Host Port:  0/TCP
    Limits:
      cpu:  500m
    Requests:
      cpu:  250m
    Environment:
      REDIS:  azure-vote-back
    Mounts:   <none>
  Volumes:    <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   azure-vote-front-c857778b (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  10m   deployment-controller  Scaled up replica set azure-vote-front-c857778b to 1
```

関連するレプリカセットも確認します。

- Annotations: max-replicas が 2 になっているのは、Desired が 1 で、アップデート時の MaxSurge が 1 のため、最大 2 つのレプリカが許容されるため
- Replicas: レプリカの情報
- Pod Status: 展開されてたポッドの情報
- pod-template-hash: レプリカセットによって展開されたポッドを区別するためハッシュ値が付与される。ここでは ```c857778b``` を付与

```shell
> kubectl describe replicaset azure-vote-front-c857778b
Name:           azure-vote-front-c857778b
Namespace:      default
Selector:       app=azure-vote-front,pod-template-hash=c857778b
Labels:         app=azure-vote-front
                pod-template-hash=c857778b
Annotations:    deployment.kubernetes.io/desired-replicas: 1
                deployment.kubernetes.io/max-replicas: 2
                deployment.kubernetes.io/revision: 1
Controlled By:  Deployment/azure-vote-front
Replicas:       1 current / 1 desired
Pods Status:    1 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=azure-vote-front
           pod-template-hash=c857778b
  Containers:
   azure-vote-front:
    Image:      kenakamuacr.azurecr.io/azure-vote-front:v1
    Port:       80/TCP
    Host Port:  0/TCP
    Limits:
      cpu:  500m
    Requests:
      cpu:  250m
    Environment:
      REDIS:  azure-vote-back
    Mounts:   <none>
  Volumes:    <none>
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  40m   replicaset-controller  Created pod: azure-vote-front-c857778b-ttlx2
```

ポッドの情報を取得します。

- NAME: ポットの名前は上記で確認したハッシュ値+ポッド毎のユニークな値が付与
- IP: ポッドに割り当てられた IP アドレス
- NODE: ポッドが展開されたノードの名前

```shell
kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE                       NOMINATED NODE   READINESS GATES
azure-vote-back-847fc9bcb9-p7m9x   1/1     Running   0          44m   10.244.1.2   aks-nodepool1-34717040-0   <none>           <none>
azure-vote-front-c857778b-ttlx2    1/1     Running   0          44m   10.244.1.3   aks-nodepool1-34717040-0   <none>           <none>
```
## サービス

デプロイメントと同様にサービスも 2 つ展開されています。

TYPE: サービスの分類
EXTERNAL-IP: 外部向けの IP

```shell
> kubectl get services -o wide
NAME               TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE     SELECTOR
azure-vote-back    ClusterIP      10.0.225.3    <none>        6379/TCP       48m     app=azure-vote-back
azure-vote-front   LoadBalancer   10.0.10.225   20.43.78.36   80:32491/TCP   48m     app=azure-vote-front
kubernetes         ClusterIP      10.0.0.1      <none>        443/TCP        3h29m   <none>
```
バックエンド向けサービスの詳細を確認します。

- TargetPort: サービスとポッドのポートマッピング
- Endpoints: サービスにリクエストが来た際のルーティング先
- Session Affinity: セッションのアフィニティ有無

```shell
> kubectl describe service azure-vote-back
Name:              azure-vote-back
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"azure-vote-back","namespace":"default"},"spec":{"ports":[{"port":...
Selector:          app=azure-vote-back
Type:              ClusterIP
IP:                10.0.225.3
Port:              <unset>  6379/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.1.2:6379
Session Affinity:  None
Events:            <none>
```
同様にフロントエンドも確認。

- LoadBalancer Ingress: イングレスのパブリック IP

```shell
> kubectl describe service azure-vote-front
Name:                     azure-vote-front
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"azure-vote-front","namespace":"default"},"spec":{"ports":[{"port"...
Selector:                 app=azure-vote-front
Type:                     LoadBalancer
IP:                       10.0.10.225
LoadBalancer Ingress:     20.43.78.36
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  32491/TCP
Endpoints:                10.244.1.3:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason                Age   From                Message
  ----    ------                ----  ----                -------
  Normal  EnsuringLoadBalancer  53m   service-controller  Ensuring load balancer
  Normal  EnsuredLoadBalancer   51m   service-controller  Ensured load balancer
```

## Web ダッシュボードでの確認

```az aks browse -g akstutorial -n myfirstaks``` でダッシュボードを起動するとトップページに各リソースの状況が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/da3b4e0f-78a0-3528-4ea6-5586e52e1ac6.png)

# まとめ

マニフェストファイルで展開ができるため、CI/CD も容易そうですが、```apply``` した際に実際になにが起きるかを理解することは大切です。次回は展開したアプリケーションのスケールを見ていきます。

[次の記事へ](https://qiita.com/kenakamu/items/af537527d4d899a8f80e)
[目次に戻る](https://qiita.com/kenakamu/items/e155740aa60c85a3d867)

# 参考
[Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)