Google Kubernetes Engine 上の Kubernetes に Spring Boot Java アプリをデプロイする

Kubernetes はオープンソースのプロジェクトで、ノートパソコンから可用性の高いマルチノード クラスタ、パブリック クラウドからオンプレミスのデプロイ、仮想マシン(VM)インスタンスからベアメタルまで、さまざまな環境で実行できます。

この Codelab では、シンプルな Spring Boot Java ウェブアプリを GKE の Kubernetes にデプロイします。この Codelab の目的は、ウェブアプリを Kubernetes で複製されたアプリとして実行することです。自分のマシンで開発したコードを Docker コンテナ イメージに変換してから、そのイメージを GKE で実行します。

このラボでは、基盤となるインフラストラクチャの設定ではなく、Kubernetes の操作に集中できるように、Google Cloud のフルマネージド Kubernetes サービスである GKE を使用します。

Kubernetes を開発用のノートパソコンなどのローカルのマシンで実行したい場合は、Minikube について調べることをおすすめします。Minikube では、開発とテスト用に単一ノードの Kubernetes クラスタを簡単に設定できます。Minikube をこの Codelab の学習に使用することも可能です。

この Codelab では、Spring Boot を使用したアプリの構築に関するガイドのサンプルコードを使用します。

前提条件

  • Java プログラミング言語とツールに関する知識
  • Linux の標準的なテキスト エディタ(Vim、Emacs、nano など)に関する知識

演習内容

  • シンプルな Java アプリを Docker コンテナとしてパッケージ化する。
  • GKE で Kubernetes クラスタを作成します。
  • Java アプリを GKE の Kubernetes にデプロイします。
  • サービスをスケールアップし、アップグレードをロールアウトする。
  • ウェブベースの Kubernetes ユーザー インターフェースである Access Dashboard にアクセスします。

必要なもの

  • Google Cloud プロジェクト
  • ブラウザ(Google Chrome など)

セルフペース型の環境設定

  1. Cloud コンソールにログインして、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します。(Gmail アカウントまたは G Suite アカウントをお持ちでない場合は、アカウントを作成する必要があります)。

プロジェクト ID を忘れないようにしてください。プロジェクト ID はすべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているので使用できません)。以降、このコードラボでは PROJECT_ID と呼びます。

  1. 次に、Google Cloud リソースを使用するために、Cloud Console で課金を有効にする必要があります。

この Codelab の操作をすべて行って、費用が生じたとしても、少額です。ただし、リソースの使用量を増やしたり、実行したままにしたりすると、費用が増加する可能性があります。

Google Cloud の新規ユーザーは、300 ドル分の無料トライアルの特典があります。

Cloud Shell をアクティブにする

  1. Cloud コンソールで、[Cloud Shell をアクティブにする] をクリックします。

Cloud Shell を起動したことがない場合、その内容を説明する中間画面が(スクロールしなければ見えない範囲に)が表示されます。その場合は、[続行] をクリックします(以後表示されなくなります)。この中間画面は次のようになります。

Cloud Shell のプロビジョニングと接続に少し時間がかかる程度です。

この仮想マシンには、必要な開発ツールがすべて用意されています。5 GB の永続ホーム ディレクトリが用意されており、Google Cloud で稼働するため、ネットワーク パフォーマンスが充実しており認証もスムーズです。このコードラボでの作業のほとんどは、ブラウザまたは Chromebook から実行できます。

Cloud Shell に接続すると、すでに認証は完了しており、プロジェクトに各自のプロジェクト ID が設定されていることがわかります。

  1. Cloud Shell で次のコマンドを実行して、認証されたことを確認します。
gcloud auth list

コマンド出力

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

コマンド出力

[core]
project = <PROJECT_ID>

上記のようになっていない場合は、次のコマンドで設定できます。

gcloud config set project <PROJECT_ID>

コマンド出力

Updated property [core/project].

Cloud Shell の起動後に以下のコマンドラインを使用すると、ホーム ディレクトリ内にサンプル ソースコードのクローンを作成できます。

$ git clone https://github.com/spring-guides/gs-spring-boot.git
$ cd gs-spring-boot/complete
  1. Spring Boot プラグインを使用して、Spring Boot アプリを通常どおりに起動できます。
$ ./mvnw -DskipTests spring-boot:run
  1. アプリが起動したら、Cloud Shell ツールバーの [ウェブでプレビュー] アイコンをクリックし、[ポート 8080 でプレビュー] を選択します。

ブラウザのタブが開き、起動したサーバーに接続されます。

次に、アプリを Kubernetes で実行するための準備を行います。最初のステップとして、コンテナとその内容を定義します。

  1. アプリのデプロイ可能な JAR を作成します。
$ ./mvnw -DskipTests package
  1. 作成するコンテナ イメージを保存するように Container Registry を有効にします。
$ gcloud services enable containerregistry.googleapis.com
  1. Jib を使用してコンテナ イメージを作成し、Container Registry に push します。
$ ./mvnw -DskipTests com.google.cloud.tools:jib-maven-plugin:build \
  -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. すべてが正常に実行されると、[Container Registry] > [イメージ] に移動して、コンテナ イメージがコンソールに表示されることを確認できます。これで、Docker イメージをプロジェクト全体で利用できるようになりました。数分後に実演するとおり、Kubernetes でこのイメージにアクセスし、オーケストレートできます。
  1. この処理が完了したら(すべてをダウンロードして抽出するのに時間がかかります)、次のコマンドを使用してイメージをローカルでテストできます。このコマンドは、新たに作成したコンテナ イメージから Docker コンテナをポート 8080 上のデーモンとして実行します。
$ docker run -ti --rm -p 8080:8080 \
  gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. ここでも Cloud Shell のウェブ プレビュー機能を利用します。

  1. 新しいタブにデフォルトのページが表示されます。アプリが Docker コンテナでローカルに実行されていることを確認したら、Control+C を押して実行中のコンテナを停止できます。

これで、GKE クラスタを作成する準備が整いました。クラスタは、Google が管理する Kubernetes API サーバーと一連のワーカーノードで構成されます。ワーカーノードは Compute Engine VM です。

  1. まず、関連する API 機能が有効になっていることを確認します。
$ gcloud services enable compute.googleapis.com container.googleapis.com
Operation "operations/..." finished successfully
  1. 2 つの n1-standard-1 ノードを含むクラスタを作成します(完了するまでに数分かかります)。
$ gcloud container clusters create hello-java-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

最終的に、作成されたクラスタが表示されます。

Creating cluster hello-java-cluster...done.
Created [https://container.googleapis.com/v1/projects/...].
kubeconfig entry generated for hello-dotnet-cluster.
NAME                  ZONE            MASTER_VERSION  
hello-java-cluster  us-central1-c  ...

これで、GKE を搭載した、完全版の Kubernetes クラスタが作成されました。

次に、コンテナ化されたアプリを Kubernetes クラスタにデプロイします。ここからは kubectl コマンドライン(Cloud Shell 環境で設定済み)を使用します。この Codelab の残りの部分では、Kubernetes のクライアントとサーバーがどちらもバージョン 1.2 以降である必要があります。kubectl version を実行すると、コマンドの現在のバージョンが表示されます。

  1. Kubernetes Deployment は、作成したコンテナ イメージを使用して、アプリの複数のインスタンスを作成、管理、スケーリングできます。kubectl run コマンドを使用して、アプリの 1 つのインスタンスを Kubernetes にデプロイします。
$ kubectl create deployment hello-java \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. 作成したデプロイを表示するには、次のコマンドを実行します。
$ kubectl get deployments
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   1         1         1            1           37s
  1. デプロイによって作成されたアプリ インスタンスを表示するには、次のコマンドを実行します。
$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
hello-java-714049816-ztzrb   1/1       Running   0          57s

この時点で、コンテナは Kubernetes の制御の下に動作するようになりますが、外部からはまだアクセスできないので、アクセスを許可する必要があります。

デフォルトでは、Pod にはクラスタ内の内部 IP からしかアクセスできません。hello-java コンテナに Kubernetes 仮想ネットワークの外部からアクセスできるようにするには、Pod を Kubernetes Service として公開する必要があります。

  1. Cloud Shell で、kubectl expose コマンドを --type=LoadBalancer フラグ付きで実行すると、Pod をインターネットで公開できます。外部からアクセスできる IP を作成するには、このフラグが必要です。
$ kubectl create service loadbalancer hello-java --tcp=8080:8080

このコマンドで使用したフラグは、基盤となるインフラストラクチャからロードバランサを使用することを指定します。Pod ではなく、Deployment を直接公開していることに注意してください。これにより、Deployment で管理されるすべての Pod でトラフィックをロードバランスする Service が作成されます(ここでは 1 つの Pod だけですが、後でレプリカを追加します)。

Kubernetes マスターによってロードバランサ、それに関連する Compute Engine 転送ルール、ターゲット プール、ファイアウォール ルールが作成され、Google Cloud の外部からこの Service に完全にアクセスできるようになります。

  1. サービスのパブリック IP アドレスを確認するには、kubectl をリクエストしてすべてのクラスタ サービスを一覧表示します。
$ kubectl get services
NAME         CLUSTER-IP     EXTERNAL-IP      PORT(S)    AGE
Hello-java   10.3.253.62    aaa.bbb.ccc.ddd  8080/TCP    1m
kubernetes   10.3.240.1     <none>           443/TCP    5m
  1. サービスに対して 2 つの IP アドレスが表示されます。いずれもポート 8080 を使用しています。1 つは、Virtual Private Cloud 内でのみ表示される内部 IP アドレスです。もう 1 つは外部ロードバランス IP アドレスです。この例では、外部 IP アドレスは aaa.bbb.ccc.ddd です。ブラウザで http://<EXTERNAL_IP>:8080 を指定すれば、対象のサービスにアクセスできるようになっています。

Kubernetes の優れた特長の一つは、アプリのスケールが容易なことです。アプリの容量が突然必要になったとします。レプリケーション コントローラに、アプリ インスタンスの新しいレプリカ数を管理するよう指示するだけで簡単に対応できます。

$ kubectl scale deployment hello-java --replicas=3
deployment "hello-java" scaled

$ kubectl get deployment
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   3         3         3            3           22m

宣言型アプローチに注目してください。新しいインスタンスの起動や停止を行うのではなく、実行するインスタンスの数を宣言します。Kubernetes の調整ループは、リクエストした内容と実際の状態が一致しているかどうかが照合され、必要に応じて調整が行われます。

本番環境にデプロイしたアプリは、いずれかの時点でバグ修正や追加機能の実装が必要になります。Kubernetes を使用すると、ユーザーに影響を及ぼすことなく、新しいバージョンを本番環境にデプロイできます。

  1. Cloud Shell メニューの [エディタを起動 ] をクリックして、コードエディタを開きます。
  2. src/main/java/hello/HelloController.java に移動して、レスポンスの値を更新します。
package hello;

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

@RestController
public class HelloController {    
    @RequestMapping("/")
    public String index() {
        return "Greetings from Google Kubernetes Engine!";
    }
}
  1. Jib を使用して、コンテナ イメージの新しいバージョンをビルドして push します。
$ ./mvnw -DskipTests package \
  com.google.cloud.tools:jib-maven-plugin:build \
  -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v2

これで、Kubernetes がレプリケーション コントローラを新しいバージョンのアプリにスムーズに更新する準備が整いました。

  1. コンテナの実行中にイメージラベルを変更するには、既存の hello-java デプロイを編集し、イメージを gcr.io/PROJECT_ID/hello-java:v1 から gcr.io/PROJECT_ID/hello-java:v2 に変更する必要があります。
  1. kubectl set image コマンドを使用すると、ローリング アップデートで新しいバージョンのアプリをクラスタ全体に一度に 1 つのインスタンスでデプロイするように Kubernetes に指示できます。
$ kubectl set image deployment/hello-java \
  hello-java=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v2

deployment "hello-java" image updated
  1. http://EXTERNAL_IP:8080 を再度確認し、新しいレスポンスが返されていることを確認します。

エラー: アプリの新しいバージョンで間違いがありましたか?新しいバージョンにエラーが含まれており、迅速にロールバックする必要がある場合などです。Kubernetes を使用すると、以前の状態に簡単にロールバックできます。次のコマンドを実行して、アプリをロールバックします。

$ kubectl rollout undo deployment/hello-java

新しい Java ベースのウェブアプリをビルドして GKE の Kubernetes にデプロイする方法を学習しました。

詳細