LoginSignup
1
0

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

Last updated at Posted at 2023-03-14

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

こんにちは、@studio_meowtoon です。今回は、Azure Kubernetes Service (AKS) 環境でコンテナアプリをブルーグリーンデプロイする方法の一例を紹介します。
spring-boot_on_azure-kubernetes-service.png

目的

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

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

実現すること

Microsoft Azure Kubernetes Service (AKS) にて、コンテナアプリのブルーグリーンデプロイを実践してみます。

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

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

技術トピック

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

こちらを展開してご覧いただけます。

ブルーグリーンデプロイメント

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

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

開発環境

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

WSL の Ubuntu を操作していきますので macOS の方も参考にして頂けます。

WSL (Microsoft Store アプリ版) ※ こちらの関連記事からインストール方法をご確認いただけます

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

Ubuntu ※ こちらの関連記事からインストール方法をご確認いただけます

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

Java JDK ※ こちらの関連記事からインストール方法をご確認いただけます

$ 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 ※ こちらの関連記事からインストール方法をご確認いただけます

$ 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 ※ こちらの関連記事からインストール方法をご確認いただけます

$ docker --version
Docker version 23.0.1, build a5ee5b1

kubectl ※ こちらの関連記事からインストール方法をご確認いただけます

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

Azure CLI ※ こちらの関連記事からインストール方法をご確認いただけます

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

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

ブルーグリーンデプロイする仕様

※ この記事での仕様となります。

識別するタグ 内容 エンドポイント 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 アプリのコンテナイメージの作成

こちらを展開して手順をご覧いただけます。

Java アプリ作成

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

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

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

$ cd ~/tmp/hello-spring-boot

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

$ vim src/main/java/com/example/springboot/controller/HelloController.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 アプリをビルドします。

$ mvn clean package

コンテナイメージ作成

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

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

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

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

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

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

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

$ 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 にログインします。

$ docker login
Login Succeeded

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

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

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

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

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

$ docker run --rm --name app-local -p 8080:8080 $USER/app-hello-spring-boot:v1
$ curl http://localhost:8080/api/data/
{"message":"Hello Blue!"}

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

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

Azure 環境にサインイン

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

Azure CLI でログインします。

$ az login

Azure 環境

リソースグループ

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

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

AKS 環境

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

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

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

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

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

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

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

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

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

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

AKS クラスターの操作

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

$ kubectl config current-context
aks-hello

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

Kubernetes マニュフェスト作成

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

$ vim service-prod.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 マニュフェストファイルを作成します。

$ vim deployment-v1.yaml

ファイルの内容

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

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 クラスターにデプロイします。

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

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

$ 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 を取得します。

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

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

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

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

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

こちらを展開して手順をご覧いただけます。

Java アプリ作成

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

$ vim src/main/java/com/example/springboot/controller/HelloController.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 アプリをビルドします。

$ mvn clean package

コンテナイメージ作成

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

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

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

$ 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 の部分はご自身のコンテナリポジトリに読み替えて下さい。

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

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

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

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

$ docker run --rm --name app-local -p 8080:8080 $USER/app-hello-spring-boot:v2
$ curl http://localhost:8080/api/data/ -w "\n"
{"message":"Hello Green!"}

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

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

Kubernetes マニュフェスト作成

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

$ vim service-dev.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 マニュフェストファイルを作成します。

$ vim deployment-v2.yaml

ファイルの内容

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

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 クラスターにデプロイします。

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

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

$ 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 を確認します。

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

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

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

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

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

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

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

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

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

$ vim service-prod.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 クラスターにデプロイします。

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

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

$ 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 を確認します。

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

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

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

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

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

$ vim service-prod.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 クラスターにデプロイします。

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

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

$ 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 を確認します。

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

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

デプロイ後の注意点

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

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

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

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

$ 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) 環境で、ブルーグリーンデプロイを実践することができました。

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

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0