Azure Kubernetes Service (AKS) でブルーグリーンデプロイする

# Azure Kubernetes Service (AKS) でブルーグリーンデプロイする

こんにちは、@studio_meowtoon です。今回は、Azure Kubernetes Service (AKS) 環境でコンテナアプリをブルーグリーンデプロイする方法の一例を紹介します。
![spring-boot_on_azure-kubernetes-service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/38e84773-6f2f-dc78-1305-248623580dd0.png)

## 目的

Windows 11 の Linux でクラウド開発します。

こちらから記事の一覧がご覧いただけます。

https://qiita.com/studio_meowtoon/items/6119ab05d8b13527efd8

## 実現すること

[Microsoft Azure Kubernetes Service (AKS)](https://learn.microsoft.com/ja-jp/azure/aks/intro-kubernetes) にて、コンテナアプリのブルーグリーンデプロイを実践してみます。

:::note alert
この記事では、**Kubernetes におけるブルーグリーンデプロイの手順**を説明していますが、これが**唯一の正しい方法ではありません**。実際には、他にも多くの手順が存在します。したがって、この記事を参考にしながら、他の情報も収集することをお勧めします。
:::

:::note alert
また、この記事では、**Docker Hub** に公開する**パブリックアクセス可能なカスタムコンテナイメージ**を使用しています。実際のシステム開発では、どのレジストリからコンテナイメージを取得するかは異なる場合がありますので、適宜ご確認ください。
:::

## 技術トピック

### ブルーグリーンデプロイとは？  

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [ブルーグリーンデプロイメント](https://martinfowler.com/bliki/BlueGreenDeployment.html)

:::note info
ブルーグリーンデプロイは、アプリケーションの新しいバージョンを本番環境にデプロイする際に、従来の運用方法とは異なり、新しいバージョンを本番環境に構築し、そこでアプリケーションをテストした後、従来の本番環境と切り替える方法です。

|内容|
|:--|
通常、ブルーの本番環境とグリーンの新しい本番環境を用意します。最初はブルーがアクティブな本番環境として稼働し、グリーンはアクティブではありません。|
|新しいバージョンのアプリケーションをグリーン環境にデプロイしてテストし、問題がなければトラフィックをグリーン環境に切り替えます。|
|これにより、ダウンタイムを最小限に抑え、システムの信頼性を高めることができます。|

:::

</details>

## 開発環境

+ Windows 11 Home 22H2 を使用しています。  

:::note info
[WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作していきますので macOS の方も参考にして頂けます。  
:::

<details>

WSL (Microsoft Store アプリ版) [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/2aaa6579cb8e4fa1d874)

```sh
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
```

Ubuntu [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/2aaa6579cb8e4fa1d874)

```sh
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
```

Java JDK [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/4d11e94a2389758759cd)

```sh
$ java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)
```

Maven [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/f4cdc4039158153365fb)

```sh
$ mvn -version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.18, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
```

Docker [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/3bceee25ac67cc73ebbe)

```sh
$ docker --version
Docker version 23.0.1, build a5ee5b1
```

kubectl [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/ef38ba2d5e913e343380)

```sh
$ kubectl version --short
Client Version: v1.26.1
Kustomize Version: v4.5.7
Server Version: v1.26.1
```

Azure CLI [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/9721041f9e6e3e987cf0)

```sh
$ az --version
azure-cli                         2.45.0
core                              2.45.0
telemetry                          1.0.8
```

</details>

:::note warn
この記事では基本的に **Ubuntu のターミナルで操作**を行います。**Vim を使用してコピペする方法**を初めて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
:::

https://qiita.com/studio_meowtoon/items/7771ad48676926e41463

## ブルーグリーンデプロイする仕様
※ この記事での仕様となります。

|識別するタグ|内容|エンドポイント|JSON レスポンス|
|:--|:--|:--|:--|
|v1|現用のサービス|/api/data|{"message":"Hello **Blue**!"}|
|v2|更新するサービス|/api/data|{"message":"Hello **Green**!"}|

**Kubernetes マニュフェスト**

|No|kind|ファイル|内容|
|:--|:--|:--|:--|
|1|Service|service-prod.yaml|本番環境 エンドポイント|
|2|Service|service-dev.yaml|検証環境 エンドポイント|
|3|Deployment|deployment-v1.yaml|現用のアプリケーション|
|4|Deployment|deployment-v2.yaml|更新するアプリケーション|

## ブルーグリーンデプロイする手順

### v1 アプリのコンテナイメージの作成

<details>
<summary>こちらを展開して手順をご覧いただけます。</summary>

#### Java アプリ作成

こちらの関連記事で手順がご確認いただけます。 

https://qiita.com/studio_meowtoon/items/37ac0082a3228e4de570

プロジェクトフォルダに移動します。  
※ ~/tmp/hello-spring-boot をプロジェクトフォルダとします。    

```sh
$ cd ~/tmp/hello-spring-boot
```

v1 アプリのソースコードを作成します。

```sh
$ vim src/main/java/com/example/springboot/controller/HelloController.java
```

ファイルの内容

```java:HelloController.java
package com.example.springboot.controller;

import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {
    @GetMapping("/data")
    public Map<String, String> getData() {
        Map<String, String> map = Map.of("message", "Hello Blue!");
        return map;
    }
}
```

v1 アプリをビルドします。

```sh
$ mvn clean package
```

#### コンテナイメージ作成

こちらの関連記事で手順がご確認いただけます。 

https://qiita.com/studio_meowtoon/items/9c07e20b4124d8c5f972

Docker デーモンを起動します。

```sh
$ sudo service docker start
 * Starting Docker: docker      [ OK ]
```

v1 アプリをコンテナイメージにビルドします。

```sh
$ docker build --no-cache -t app-hello-spring-boot:v1 .
```

v1 アプリのコンテナイメージを確認します。

```sh
$ docker images | grep app-hello-spring-boot
app-hello-spring-boot   v1        c61d32929a90   58 seconds ago   390MB
```

#### コンテナイメージを Docker Hub にプッシュ

こちらの関連記事で手順がご確認いただけます。 

https://qiita.com/studio_meowtoon/items/cbcfe1433885bae514db

Docker Hub にログインします。  

```sh
$ docker login
Login Succeeded
```

v1 アプリのコンテナイメージにタグを付けます。
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh
$ docker tag app-hello-spring-boot:v1 $USER/app-hello-spring-boot:v1
```

Docker Hub に v1 アプリのコンテナイメージをプュシュします。

```sh
$ docker push $USER/app-hello-spring-boot:v1
```

ローカルでコンテナを起動させアプリの動作を確認します。
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh
$ docker run --rm --name app-local -p 8080:8080 $USER/app-hello-spring-boot:v1
```

```sh
$ curl http://localhost:8080/api/data/
{"message":"Hello Blue!"}
```

:::note warn 
コンテナイメージをビルドし、Docker Hub にプッシュする際、キャッシュが不適切に使用され、ソースコードの変更が反映されないことがあります。この問題を解決するために、事前に Docker Hub にプッシュしたコンテナイメージをローカルで起動し、正しい動作を確認することをお勧めします。
:::

</details>

:::note info
ここまでの作業で **v1 アプリのカスタムコンテナイメージ**が **Docker Hub に公開**できました。
:::

### Azure 環境にサインイン

こちらの関連記事から手順をご確認いただけます。

https://qiita.com/studio_meowtoon/items/9721041f9e6e3e987cf0

Azure CLI でログインします。  

```sh
$ az login
```

### Azure 環境

#### リソースグループ

リソースグループを作成します。

```sh:Microsoft.Resources/resourceGroups
$ az group create \
    --name rg-hello \
    --location japaneast
```

#### AKS 環境

こちらの関連記事から手順をご確認いただけます。

https://qiita.com/studio_meowtoon/items/9b3a861bbaeba1f56640

AKS クラスターを作成します。  
※ Kubernetes 基盤の環境作成に少し時間がかかります。  

```sh:Microsoft.ContainerService/ManagedClusters
$ az aks create \
    --resource-group rg-hello \
    --name aks-hello \
    --node-count 1 \
    --generate-ssh-keys
```

設定ファイルの権限を修正します。 
※ 初回のみ必要です。 

```sh
$ chmod 600 /home/$USER/.kube/config
```

AKS クラスターと接続します。  
※ 既存設定の上書きを許可する為、yes を選択します。    

```sh
$ az aks get-credentials \
    --resource-group rg-hello \
    --name aks-hello
```

接続設定が成功した場合の出力は、以下のようになります。

```sh
Merged "aks-hello" as current context in /home/$USER/.kube/config
```

:::note info
ここまでで **Azure** 上に構築した **Kubernetes クラスターに接続**できました。ここからはその Kubernetes クラスターをリモートでコマンド操作していきます。
:::

### AKS クラスターの操作

現在の接続先を確認します。

```sh
$ kubectl config current-context
aks-hello
```

### v1 アプリを AKS クラスターにデプロイ

#### Kubernetes マニュフェスト作成

本番環境 service マニュフェストファイルを作成します。

```sh
$ vim service-prod.yaml
```

ファイルの内容

```yaml:service-prod.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-service-prod
spec:
  type: LoadBalancer
  selector:
    app: app
    version: v1
  ports:
  - port: 80
    targetPort: 8080
```

v1 アプリ deployment マニュフェストファイルを作成します。

```sh
$ vim deployment-v1.yaml
```

ファイルの内容

:::note alert
**$USER** の部分はご自身のコンテナリポジトリに**書き換えて**下さい。  
:::

```yaml:deployment-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
        version: v1
    spec:
      containers:
      - name: app
        image: $USER/app-hello-spring-boot:v1
        ports:
        - containerPort: 8080
```

v1 アプリを AKS クラスターにデプロイします。

```sh
$ kubectl apply -f deployment-v1.yaml
deployment.apps/app-v1 created
```
```sh
$ kubectl apply -f service-prod.yaml
service/app-service-prod created
```

AKS クラスターの状態を確認します。

```sh
$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-777d85d649-r6tmk   1/1     Running   0          14m

NAME                       TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)        AGE
service/app-service-prod   LoadBalancer   10.0.98.40   xx.xx.xx.xx     80:30472/TCP   14m
service/kubernetes         ClusterIP      10.0.0.1     <none>          443/TCP        27m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v1   1/1     1            1           14m
```

**app-service-prod** サービスの EXTERNAL-IP を取得します。

```sh
$ kubectl get svc app-service-prod -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
xx.xx.xx.xx
```

別ターミナルから curl コマンドで **app-service-prod** サービスの URL を確認します。

```sh
$ curl http://xx.xx.xx.xx/api/data
{"message":"Hello Blue!"}
```

:::note info
ここまでの作業で **v1 アプリ**の Kubernetes クラスター への**デプロイが完了**しました。
:::

### v2 アプリのコンテナイメージの作成

<details>
<summary>こちらを展開して手順をご覧いただけます。</summary>

#### Java アプリ作成

v2 アプリのソースコードを作成します。

```sh
$ vim src/main/java/com/example/springboot/controller/HelloController.java
```

ファイルの内容

```java:HelloController.java
package com.example.springboot.controller;

import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {
    @GetMapping("/data")
    public Map<String, String> getData() {
        Map<String, String> map = Map.of("message", "Hello Green!");
        return map;
    }
}
```

v2 アプリをビルドします。

```sh
$ mvn clean package
```

#### コンテナイメージ作成

v2 アプリをコンテナイメージにビルドします。

```sh
$ docker build --no-cache -t app-hello-spring-boot:v2 .
```

v2 アプリのコンテナイメージを確認します。

```sh
$ docker images | grep app-hello-spring-boot
app-hello-spring-boot   v1        c61d32929a90   58 seconds ago   390MB
app-hello-spring-boot   v2        9d54d1056fb2    9 seconds ago   390MB
```

#### コンテナイメージを Docker Hub にプッシュ

v2 アプリのコンテナイメージにタグを付けます。
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh
$ docker tag app-hello-spring-boot:v2 $USER/app-hello-spring-boot:v2
```

Docker Hub に v2 アプリのコンテナイメージをプュシュします。

```sh
$ docker push $USER/app-hello-spring-boot:v2
```

ローカルでコンテナを起動させアプリの動作を確認します。
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh
$ docker run --rm --name app-local -p 8080:8080 $USER/app-hello-spring-boot:v2
```

```sh
$ curl http://localhost:8080/api/data/ -w "\n"
{"message":"Hello Green!"}
```

</details>

:::note info
ここまでの作業で **v2 アプリのカスタムコンテナイメージ**が **Docker Hub に公開**できました。
:::

### v2 アプリを AKS クラスターにデプロイ

#### Kubernetes マニュフェスト作成

検証環境 service マニュフェストファイルを作成します。

```sh
$ vim service-dev.yaml
```

ファイルの内容

```yaml:service-dev.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-service-dev
spec:
  type: LoadBalancer
  selector:
    app: app
    version: v2
  ports:
  - port: 80
    targetPort: 8080
```

v2 アプリ deployment マニュフェストファイルを作成します。

```sh
$ vim deployment-v2.yaml
```

ファイルの内容

:::note alert
**$USER** の部分はご自身のコンテナリポジトリに**書き換えて**下さい。  
:::

```yaml:deployment-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
        version: v2
    spec:
      containers:
      - name: app
        image: $USER/app-hello-spring-boot:v2
        ports:
        - containerPort: 8080
```

v2 アプリを AKS クラスターにデプロイします。

```sh
$ kubectl apply -f deployment-v2.yaml
deployment.apps/app-v2 created
```
```sh
$ kubectl apply -f service-dev.yaml
service/app-service-dev created
```

AKS クラスターの状態を確認します。

```sh
$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-777d85d649-r6tmk   1/1     Running   0          30m
pod/app-v2-555bf9fc8f-pj8c9   1/1     Running   0          9s

NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
service/app-service-dev    LoadBalancer   10.0.196.119   zz.zz.zz.zz     80:32645/TCP   67s
service/app-service-prod   LoadBalancer   10.0.98.40     xx.xx.xx.xx     80:30472/TCP   30m
service/kubernetes         ClusterIP      10.0.0.1       <none>          443/TCP        43m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v1   1/1     1            1           30m
deployment.apps/app-v2   1/1     1            1           2m32s
```

別ターミナルから curl コマンドで **app-service-prod** サービスの URL を確認します。

```sh
$ curl http://xx.xx.xx.xx/api/data -w "\n"
{"message":"Hello Blue!"}
```

:::note warn
**app-service-prod** サービスの URLをリクエストすると、更新前の **v1 アプリの出力が表示**されます。
:::

**app-service-dev** サービスの EXTERNAL-IP を取得します。

```sh
$ kubectl get svc app-service-dev -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
zz.zz.zz.zz
```

別ターミナルから curl コマンドで **app-service-dev** サービスの URL を確認します。

```sh
$ curl http://zz.zz.zz.zz/api/data -w "\n"
{"message":"Hello Green!"}
```

:::note info
AKS クラスターに v2 アプリを、**app-service-dev** サービスの URL からアクセス可能なアプリとしてデプロイすることができました。また、実際にリリースする前に **app-service-dev** サービスの URL を利用して**動作確認**を行うことができます。これは、**ブルーグリーンデプロイの目的の1つ**です。
:::

### 新しいデプロイメントへの切り替え

**app-service-prod** サービスの URL の向き先を **deployment-v2** デプロイメントに切り替えます。

```sh
$ vim service-prod.yaml
```

ファイルの内容

```yaml:service-prod.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-service-prod
spec:
  type: LoadBalancer
  selector:
    app: app
    version: v2
  ports:
  - port: 80
    targetPort: 8080
```

app-service-prod の更新を AKS クラスターにデプロイします。

```sh
$ kubectl apply -f service-prod.yaml
service/app-service-prod configured
```

AKS クラスターの状態を確認します。

```sh
$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-777d85d649-r6tmk   1/1     Running   0          36m
pod/app-v2-555bf9fc8f-pj8c9   1/1     Running   0          5m55s

NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
service/app-service-dev    LoadBalancer   10.0.196.119   zz.zz.zz.zz     80:32645/TCP   6m53s
service/app-service-prod   LoadBalancer   10.0.98.40     xx.xx.xx.xx     80:30472/TCP   36m
service/kubernetes         ClusterIP      10.0.0.1       <none>          443/TCP        49m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v1   1/1     1            1           36m
deployment.apps/app-v2   1/1     1            1           8m18s
```

別ターミナルから curl コマンドで **app-service-prod** サービスの URL を確認します。

```sh
$ curl http://xx.xx.xx.xx/api/data -w "\n"
{"message":"Hello Green!"}
```

:::note info
AKS **app-service-prod** サービスの URLをリクエストして、更新後の **v2 アプリの出力**が表示されました。**本番環境**への**デプロイ作業が完了**しました。
:::

### トラブル発生時の切り戻し

:::note alert
サービスを最新バージョンにデプロイした後に**トラブルが発生**した場合、以前に**正常に動作**していた**デプロイに戻す**必要があります。これは、**ブルーグリーンデプロイの目的の1つ**です。
:::

**app-service-prod** サービスの URL の向き先を **deployment-v1** デプロイメントに切り戻します。

```sh
$ vim service-prod.yaml
```

ファイルの内容

```yaml:service-prod.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-service-prod
spec:
  type: LoadBalancer
  selector:
    app: app
    version: v1
  ports:
  - port: 80
    targetPort: 8080
```

app-service-prod の更新を AKS クラスターにデプロイします。

```sh
$ kubectl apply -f service-prod.yaml
service/app-service-prod configured
```

AKS クラスターの状態を確認します。

```sh
$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-777d85d649-r6tmk   1/1     Running   0          38m
pod/app-v2-555bf9fc8f-pj8c9   1/1     Running   0          7m46s

NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
service/app-service-dev    LoadBalancer   10.0.196.119   zz.zz.zz.zz     80:32645/TCP   8m44s
service/app-service-prod   LoadBalancer   10.0.98.40     xx.xx.xx.xx     80:30472/TCP   37m
service/kubernetes         ClusterIP      10.0.0.1       <none>          443/TCP        51m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v1   1/1     1            1           38m
deployment.apps/app-v2   1/1     1            1           10m
```

別ターミナルから curl コマンドで **app-service-prod** サービスの URL を確認します。

```sh
$ curl http://xx.xx.xx.xx/api/data -w "\n"
{"message":"Hello Blue!"}
```

:::note info
AKS **app-service-prod** サービスの URLをリクエストして、更新前の **v1 アプリの出力**が表示されました。デプロイの**切り戻し**が完了しました。
:::

### デプロイ後の注意点

:::note alert
従量課金モデルでは、リソースの利用に応じて**課金**されます。新しいデプロイが正常に動作し、安定した状態になった後に、不要となったデプロイメントを削除することができます。これにより、必要以上に課金されることを防ぐことができます。
:::

v2 アプリのデプロイに成功したので v1 アプリの**デプロイメント**を AKS クラスターから削除します。

```sh
$ kubectl delete deployment app-v1
deployment.apps "app-v1" deleted
```

AKS クラスターの状態を確認します。

```sh
$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v2-555bf9fc8f-pj8c9   1/1     Running   0          9m23s

NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
service/app-service-dev    LoadBalancer   10.0.196.119   zz.zz.zz.zz     80:32645/TCP   10m
service/app-service-prod   LoadBalancer   10.0.98.40     xx.xx.xx.xx     80:30472/TCP   39m
service/kubernetes         ClusterIP      10.0.0.1       <none>          443/TCP        52m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v2   1/1     1            1           11m
```

v1 アプリのデプロイメントが削除されたことが確認できました。

## まとめ

Azure Kubernetes Service (AKS) 環境で、ブルーグリーンデプロイを実践することができました。

:::note warn
**Maven**、**Docker**、**kubectl**、**Azure CLI** を使って、Spring Boot アプリの開発からコンテナイメージの作成、Azure 環境へのデプロイまで、**すべてをターミナルから行うことができます**。このように、クラウドでのシステム開発に必要なスキルや理解を深めることができます。初めての人でも簡単に手順を追うことができるので、ぜひ挑戦してみてください。
:::

どうでしたか？ 検証目的の Azure Kubernetes Service (AKS) 環境で、コンテナアプリのブルーグリーンデプロイを手軽に体験することができます。ぜひお試しください。今後も Azure の開発環境などを紹介していきますので、ぜひお楽しみにしてください。