3
0

Kubernetes でブルーグリーンデプロイする

Last updated at Posted at 2023-03-14

Kubernetes でブルーグリーンデプロイする

こんにちは、@studio_meowtoon です。今回は、ローカル Ubuntu の Kubernetes クラスターでブルーグリーンデプロイする方法の一例を紹介します。
spring-boot_on_kubernetes.png

目的

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

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

実現すること

Windows 11 の WSL で稼働する Ubuntu の Kubernetes クラスターにて、コンテナアプリのブルーグリーンデプロイを実践してみます。

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

技術トピック

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

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

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

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

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

開発環境

  • 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

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

$ minikube version
minikube version: v1.29.0
commit: ddac20b4b34a9c8c857fc602203b6ba2679794d3

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

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

この記事では基本的に 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
@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

ここまでの作業で v1 アプリのカスタムコンテナイメージが作成できました。

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

コンテナイメージの取り込み

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

Kubernetes クラスターを開始します。

$ minikube start

v1 アプリのコンテナイメージを Minikube に取り込みます。

$ minikube image load app-hello-spring-boot:v1

Minikube 上のコンテナイメージを確認します。

$ minikube image ls | grep app-hello-spring-boot
docker.io/library/app-hello-spring-boot:v1

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

ファイルの内容

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: app-hello-spring-boot:v1
        ports:
        - containerPort: 8080

Kubernetes クラスター接続先を確認します。

$ kubectl config current-context
minikube

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

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

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

$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-56dddcc497-s9gd6   1/1     Running   0          19m

NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/app-service-prod   LoadBalancer   10.101.34.176   <pending>     80:31015/TCP     19m
service/kubernetes         ClusterIP      10.96.0.1       <none>        443/TCP          21m

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

Minikube はローカルで稼働する Kubernetes クラスターであり、LoadBalancer タイプのサービスに外部 IP を割り当てる機能が備わっていないため、EXTERNAL-IP<pending> になります。しかし、minikube service コマンドを使用することで、Minikube の仮想マシン上で、Service リソースに割り当てられた LoadBalancer にアクセスすることができます。

別ターミナルから app-service-prod に接続する URL を取得します。

$ minikube service app-service-prod
🎉  デフォルトブラウザーで default/app-service-prod サービスを開いています...
👉  http://127.0.0.1:41087
❗  Docker ドライバーを linux 上で使用しているため、実行するにはターミナルを開く必要があります。

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

$ curl http://127.0.0.1:41087/api/data
{"message":"Hello Blue!"}

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

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

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

Java アプリ作成

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

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

ファイルの内容
※ コードの内容を一部省略しています。

HelloController.java
@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 .

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

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

ここまでの作業で v2 アプリのカスタムコンテナイメージが作成できました。

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

コンテナイメージの取り込み

v2 アプリのコンテナイメージを Minikube に取り込みます。

$ minikube image load app-hello-spring-boot:v2

Minikube 上のコンテナイメージを確認します。

$ minikube image ls | grep app-hello-spring-boot
docker.io/library/app-hello-spring-boot:v2
docker.io/library/app-hello-spring-boot:v1

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

ファイルの内容

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: app-hello-spring-boot:v2
        ports:
        - containerPort: 8080

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

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

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

$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-56dddcc497-s9gd6   1/1     Running   0          34m
pod/app-v2-6b587b579-zpxlp    1/1     Running   0          26s

NAME                       TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/app-service-dev    LoadBalancer   10.106.214.150   <pending>     80:32513/TCP     13s
service/app-service-prod   LoadBalancer   10.101.34.176    <pending>     80:31015/TCP     34m
service/kubernetes         ClusterIP      10.96.0.1        <none>        443/TCP          36m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v1   1/1     1            1           34m
deployment.apps/app-v2   1/1     1            1           26s

別ターミナルから app-service-dev に接続する URL を取得します。

$ minikube service app-service-dev
🎉  デフォルトブラウザーで default/app-service-dev サービスを開いています...
👉  http://127.0.0.1:34167
❗  Docker ドライバーを linux 上で使用しているため、実行するにはターミナルを開く必要があります。

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

$ curl http://127.0.0.1:41087/api/data
{"message":"Hello Blue!"}

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

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

$ curl http://127.0.0.1:34167/api/data
{"message":"Hello Green!"}

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

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

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

$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-56dddcc497-s9gd6   1/1     Running   0          44m
pod/app-v2-6b587b579-zpxlp    1/1     Running   0          10m

NAME                       TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/app-service-dev    LoadBalancer   10.106.214.150   <pending>     80:32513/TCP     10m
service/app-service-prod   LoadBalancer   10.101.34.176    <pending>     80:31015/TCP     44m
service/kubernetes         ClusterIP      10.96.0.1        <none>        443/TCP          46m

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

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

$ curl http://127.0.0.1:41087/api/data
{"message":"Hello Green!"}

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

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

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

$ kubectl get pods,services,deployments
NAME                          READY   STATUS    RESTARTS   AGE
pod/app-v1-56dddcc497-s9gd6   1/1     Running   0          49m
pod/app-v2-6b587b579-zpxlp    1/1     Running   0          15m

NAME                       TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/app-service-dev    LoadBalancer   10.106.214.150   <pending>     80:32513/TCP     15m
service/app-service-prod   LoadBalancer   10.101.34.176    <pending>     80:31015/TCP     49m
service/kubernetes         ClusterIP      10.96.0.1        <none>        443/TCP          51m

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-v1   1/1     1            1           49m
deployment.apps/app-v2   1/1     1            1           15m

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

$ curl http://127.0.0.1:41087/api/data
{"message":"Hello Blue!"}

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

デプロイ後の注意点

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

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

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

$ kubectl get pods,services,deployments
NAME                         READY   STATUS    RESTARTS   AGE
pod/app-v2-6b587b579-zpxlp   1/1     Running   0          27m

NAME                       TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/app-service-dev    LoadBalancer   10.106.214.150   <pending>     80:32513/TCP     26m
service/app-service-prod   LoadBalancer   10.101.34.176    <pending>     80:31015/TCP     60m
service/kubernetes         ClusterIP      10.96.0.1        <none>        443/TCP          63m

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

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

まとめ

WSL Ubuntu の Kubernetes クラスターでブルーグリーンデプロイを実践することができました。

クラウド開発においては、Kubernetes の基本的な理解は重要です。また、Ubuntu を使用することで Linux の知識も身につけることができます。最初は難しく感じるかもしれませんが、少しずつ進めていくことで自信を持って取り組むことができるようになります。

どうでしたか? WSL Ubuntu で、Kubernetes クラスターでのブルーグリーンデプロイを手軽に体験することができます。ぜひお試しください。今後もクラウド開発手法などを紹介していきますので、ぜひお楽しみにしてください。

推奨コンテンツ

3
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
3
0