1. 概要
Micronaut について
Micronaut は、簡単にテストできるモジュール型のマイクロサービス アプリケーションやサーバーレス アプリケーションを構築するための、JVM ベースの最新のフルスタック フレームワークです。Micronaut は、最小限のメモリ使用量で、優れた起動時間と高速なスループットを実現することを目指しています。Micronaut は、Java、Groovy、Kotlin のいずれかで開発できます。
Micronaut が提供するもの:
- 高速起動と低いメモリ消費量 - リフレクション ベースの IoC フレームワークは、コード内のすべてのフィールド、メソッド、コンストラクタについてリフレクション データを読み込んでキャッシュしますが、Micronaut ではアプリケーションの起動時間とメモリ消費量がコードベースのサイズの制約を受けることはありません。
- 宣言型、リアクティブ、コンパイル時 HTTP クライアント - リアクティブの HTTP クライアントを宣言的に構築します。このクライアントはコンパイル時に実装され、メモリ使用量を削減します。
- Netty 上に構築されたノンブロッキング HTTP サーバー - Micronaut の HTTP サーバーは、習得が容易で、HTTP クライアントで使用できる API を可能な限り簡単に公開できます。
- 迅速で簡単なテスト - 単体テストでサーバーやクライアントを簡単にスピンアップし、即座に実行できます。
- 効率的なコンパイル時の依存関係インジェクションと AOP - Micronaut は、リフレクションを使用しないシンプルなコンパイル時アスペクト指向プログラミング API を提供しています。
- 完全にリアクティブでブロックしないアプリの構築 - Micronaut は、RxJava や Reactor など、リアクティブ ストリームを実装するあらゆるフレームワークをサポートしています。
詳しくは、Micronaut のウェブサイトをご覧ください。
Kubernetes について
Kubernetes はオープンソースのプロジェクトで、ノートパソコンから可用性の高いマルチノード クラスタ、パブリック クラウドからオンプレミスのデプロイ、仮想マシンからベアメタルまで、さまざまな環境で実行できます。
このラボでは、Groovy ベースのシンプルな Micronaut マイクロサービスを、Kubernetes Engine で実行されている Kubernetes にデプロイします。
この Codelab の目標は、Kubernetes で実行される複製されたサービスとしてマイクロサービスを実行することです。マシンで開発したコードを Docker コンテナ イメージに変換し、そのイメージを Kubernetes Engine で実行します。
次の図に、この Codelab で使用されるさまざまな部分を示します。これは、要素がどのように組み合わされているのかを理解するのに役立ちます。Codelab を進める際の参考としてご利用ください。終わりに近づく頃には、すべて理解できるはずです(ただし、今は無視してかまいません)。
この Codelab では、Kubernetes Engine(Google がホストする Compute Engine で実行される Kubernetes のバージョン)などのマネージド環境を使用することで、基盤となるインフラストラクチャの設定ではなく、Kubernetes を体験することに集中できます。
Kubernetes を開発用のノートパソコンなどのローカルのマシンで実行したい場合は、Minikube について調べることをおすすめします。この機能を使うと、単一ノードの Kubernetes クラスタをシンプルな設定で構築し、開発やテストに利用できます。必要に応じて、Minikube を使用してこの Codelab を完了できます。
Jib について
Jib は、Java アプリケーション用の Docker イメージと OCI イメージをビルドできるオープンソース ツールです。Maven と Gradle 用のプラグイン、および Java ライブラリとして利用できます。
Jib の目標は次のとおりです。
- 迅速 - 変更を迅速にデプロイできます。Jib は、アプリケーションを複数のレイヤに分割し、依存関係をクラスから分割します。Docker によって Java アプリケーション全体が再ビルドされるのを待つ必要がなくなり、変更されたレイヤをデプロイするだけです。
- 再現可能 - 同じ内容でコンテナ イメージを再ビルドすると、常に同じイメージが生成されます。二度と不要な更新をトリガーしないようにします。
- デーモンレス - CLI の依存関係を減らします。Maven または Gradle 内から Docker イメージをビルドし、任意のレジストリに push します。Dockerfile の書き込みや Docker ビルド / push の呼び出しが不要。
Jib について詳しくは、GitHub のプロジェクト ページをご覧ください。
このチュートリアルについて
このチュートリアルでは、Jib ツールのサンプルコードを使用して Java アプリケーション用のコンテナをビルドします。
サンプルは、Micronaut フレームワークと Apache Groovy プログラミング言語を使用したシンプルな hello world サービスです。
学習内容
- Jib を使用してシンプルな Java アプリケーションを Docker コンテナとしてパッケージ化する方法
- Kubernetes Engine で Kubernetes クラスタを作成する方法
- Kubernetes Engine で Kubernetes に Micronaut サービスをデプロイする方法
- サービスをスケールアップし、アップグレードをロールアウトする
- Kubernetes のグラフィカル ダッシュボードにアクセスする方法。
必要なもの
- Google Cloud Platform プロジェクト
- Chrome や Firefox などのブラウザ
- Linux の標準的なテキスト エディタ(vim、emacs、nano など)を使い慣れていること
このチュートリアルの利用方法をお選びください。
HTML/CSS ウェブアプリの作成経験をどのように評価されますか。
Google Cloud Platform サービスのご利用経験についてどのように評価されますか?
<ph type="x-smartling-placeholder">2. 設定と要件
セルフペース型の環境設定
- Cloud Console にログインし、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します(Gmail アカウントまたは G Suite アカウントをお持ちでない場合は、アカウントを作成する必要があります)。
プロジェクト ID を忘れないようにしてください。プロジェクト ID はすべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているので使用できません)。以降、このコードラボでは PROJECT_ID
と呼びます。
- 次に、Google Cloud リソースを使用するために、Cloud Console で課金を有効にする必要があります。
このコードラボを実行しても、費用はほとんどかからないはずです。このチュートリアル以外で請求が発生しないように、リソースのシャットダウン方法を説明する「クリーンアップ」セクションの手順に従うようにしてください。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。
3. Micronaut のサンプル ソースコードを入手する
Cloud Shell が起動したら、コマンドラインを使用してサンプル ソースコードのクローンをホーム ディレクトリに作成し、サンプル サービスを含むディレクトリに移動します。
$ git clone https://github.com/GoogleContainerTools/jib.git
$ cd jib/examples/micronaut/
4. コードの概要
Micronaut のシンプル サービスは、悪名高い Hello World メッセージを出力するコントローラで構成されています。
@Controller("/hello") class HelloController { @Get("/") String index() { "Hello World" } }
HelloController
コントローラは /hello
パスのリクエストに応答し、index()
メソッドは HTTP GET リクエストを受け入れます。
Spock テストクラスを使用して、正しいメッセージが出力されているかを確認することもできます。
class HelloControllerSpec extends Specification { @Shared @AutoCleanup EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer) @Shared @AutoCleanup RxHttpClient client = embeddedServer.applicationContext.createBean(RxHttpClient, embeddedServer.getURL()) void "test hello world response"() { when: HttpRequest request = HttpRequest.GET('/hello') String rsp = client.toBlocking().retrieve(request) then: rsp == "Hello World" } }
このテストでは、単純な単体テストというよりも、本番環境と同じ Micronaut サーバー スタック(Netty フレームワークに基づく)を実際に実行します。そのため、コードの動作はプロダクト内でもテスト時とまったく同じになります。
テストを実行するには、次のコマンドを実行して、すべてに問題がないことを確認します。
./gradlew test
5. アプリケーションをローカルで実行する
Micronaut サービスは通常、次の Gradle コマンドを使用して起動できます。
$ ./gradlew run
アプリケーションが開始したら、小さな「+」アイコンを使用して追加の Cloud Shell インスタンスを開き、期待される出力が表示されることを curl で確認できます。
$ curl localhost:8080/hello
シンプルな「Hello World」と表示されるはずです。メッセージが表示されます。
6. Jib を使用してアプリケーションを Docker コンテナとしてパッケージ化する
次に、アプリを Kubernetes で実行するための準備を行います。この目的には、Jib を利用して Dockerfile
に手を触れる必要がないので、手間のかかる作業をこなします。
コンテナをビルドするコマンドを実行しましょう。
$ ./gradlew jibDockerBuild
出力は次のようになります。
Tagging image with generated image reference micronaut-jib:0.1. If you'd like to specify a different tag, you can set the jib.to.image parameter in your build.gradle, or use the --im age=<MY IMAGE> commandline flag. Containerizing application to Docker daemon as micronaut-jib:0.1... warning: Base image 'gcr.io/distroless/java' does not use a specific image digest - build may not be reproducible Getting base image gcr.io/distroless/java... Building dependencies layer... Building resources layer... Building classes layer... Finalizing... Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, example.micronaut.Application] Loading to Docker daemon... Built image to Docker daemon as micronaut-jib:0.1
イメージがビルドされたので、Cloud Shell の最初のタブで Docker イメージを実行して、わかりやすい hello メッセージが表示されるかどうかを確認しましょう。
$ docker run -it -p 8080:8080 micronaut-jib:0.1 16:57:20.255 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [cloud, gcp] 16:57:23.203 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 2926ms. Server Running: http://97b7d76ccf3f:8080
サービスが実行されているので、2 番目の Cloud Shell タブで curl コマンドを実行し、期待どおりに動作しているかどうかを確認します。
$ curl localhost:8080/hello Hello World
コンテナを停止するには、Cloud Shell で Ctrl+C
キーを押します。
7. コンテナ化されたサービスをレジストリに push する
イメージが意図したとおりに機能するようになったので、このイメージを Google Container Registry に push します。Google Container Registry は、すべての Google Cloud プロジェクトから(ただし Google Cloud Platform の外部からも)アクセス可能な Docker イメージの非公開リポジトリです。
レジストリに push できるようにする前に、[Tools] > [Container Registry。有効になっていない場合は、次のダイアログが表示されたら、[Container Registry API を有効にする] をクリックします。有効にするには次のようにします。
レジストリの準備ができたら、イメージをレジストリに push するために次のコマンドを実行します。
$ gcloud auth configure-docker $ docker tag micronaut-jib:0.1 \ gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1 $ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1
上記のコマンドを使用すると、gcloud SDK で Docker を構成して承認し、Container Registry のインスタンスにイメージを push し、レジストリ内の場所を指すようにイメージにタグを付けてレジストリに push します。
問題がなければ、しばらくすると、コンソールにコンテナ イメージが表示されます。[Tools] >Container Registry。この時点で Docker イメージはプロジェクト全体で使用できる状態になっており、数分後に実演するとおり、Kubernetes からアクセスしてオーケストレートできます。
8. クラスタを作成する
これで、Kubernetes Engine クラスタを作成する準備が整いました。その前に、ウェブ コンソールの Google Kubernetes Engine セクションに移動し、システムが初期化されるまで待ちます(数秒しかかかりません)。
クラスタは、Google が管理する Kubernetes マスター API サーバーと、一連のワーカーノードから構成されます。ワーカーノードは Compute Engine 仮想マシンです。CloudShell セッションの gcloud
CLI を使用して、2 つの n1-standard-1
ノードを持つクラスタを作成します(完了するまでに数分かかります)。
$ gcloud container clusters create hello-cluster \ --num-nodes 2 \ --machine-type n1-standard-1 \ --zone us-central1-c
最終的に、作成されたクラスタが表示されます。
Creating cluster hello-cluster in us-central1-c...done. Created [https://container.googleapis.com/v1/projects/mn-gke-test/zones/us-central1-c/clusters/hello-cluster]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-c/hello-cluster?project=mn-gke-test kubeconfig entry generated for hello-cluster. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS hello-cluster us-central1-c 1.9.7-gke.7 35.239.224.115 n1-standard-1 1.9.7-gke.7 2 RUNNING
これで、Google Kubernetes Engine を基盤とする、完全に機能する Kubernetes クラスタが準備できました。
次に、コンテナ化されたアプリケーションを Kubernetes クラスタにデプロイします。ここからは kubectl
コマンドライン(Cloud Shell 環境で設定済み)を使用します。この Codelab の残りの部分では、Kubernetes クライアントとサーバーの両方のバージョンを 1.2 以降にする必要があります。kubectl version
により、コマンドの現在のバージョンが表示されます。
9. アプリケーションを Kubernetes にデプロイする
Kubernetes Deployment では、作成したコンテナ イメージを使用して、アプリケーションの複数のインスタンスを作成、管理、スケーリングできます。kubectl create deployment
コマンドを使用して、Kubernetes へのアプリケーションの Deployment を作成しましょう。
$ kubectl create deployment hello-micronaut \ --image=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1
作成したデプロイを表示するには、次のコマンドを実行します。
$ kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE hello-micronaut 1 1 1 1 5m
デプロイによって作成されたアプリケーション インスタンスを表示するには、次のコマンドを実行します。
$ kubectl get pods NAME READY STATUS RESTARTS AGE hello-micronaut-5647fb98c5-lh5h7 1/1 Running 0 5m
この時点で、コンテナは Kubernetes の制御下で実行されているはずですが、外部からアクセス可能な状態にする必要があります。
10. 外部トラフィックを許可する
デフォルトでは、ポッドにはクラスタ内の内部 IP からしかアクセスできません。Kubernetes 仮想ネットワークの外部から hello-micronaut
コンテナにアクセスできるようにするには、Pod を Kubernetes Service として公開する必要があります。
Cloud Shell から kubectl expose
コマンドと --type=LoadBalancer
フラグを組み合わせて使用すると、Pod を公共のインターネットに公開できます。外部からアクセスできる IP を作成するには、このフラグが必要です。
$ kubectl expose deployment hello-micronaut --type=LoadBalancer --port=8080
このコマンドで使用されているフラグは、基盤となるインフラストラクチャで提供されるロードバランサ(この場合は Compute Engine ロードバランサ)を使用することを指定します。ポッドを直接公開するのではなく、デプロイを公開していることに注意してください。これによって、Deployment で管理されるすべての Pod でトラフィックをロードバランスする Service が作成されます(ここでは 1 つの Pod だけですが、後でレプリカを追加します)。
Kubernetes マスターによってロードバランサ、それに関連する Compute Engine 転送ルール、ターゲット プール、ファイアウォール ルールが作成され、Google Cloud Platform の外部からこのサービスに完全にアクセスできるようになります。
Service の一般公開されている IP アドレスを確認するには、kubectl
をリクエストして、すべてのクラスタ サービスを一覧表示します。
$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-micronaut LoadBalancer 10.39.243.251 aaa.bbb.ccc.ddd 8080:30354/TCP 1m kubernetes ClusterIP 10.39.240.1 <none> 443/TCP 31m
Service について 2 つの IP アドレスが表示されています。どちらもポート 8080
を使用しています。1 つは内部 IP で、Cloud Virtual Network 内でのみ表示されます。もう 1 つは外部負荷分散 IP です。この例では、外部 IP アドレスは aaa.bbb.ccc.ddd
です。
ブラウザでアドレス http://<EXTERNAL_IP>
:8080
/hello
を指定して、サービスにアクセスできるようになりました。
11. サービスをスケールアップする
Kubernetes の優れた特長の一つは、アプリケーションのスケールが容易なことです。アプリケーションで突然、容量の増加が必要になったとします。レプリケーション コントローラに、アプリケーション インスタンスの新しい数のレプリカを管理するよう指示するだけで済みます。
$ kubectl scale deployment hello-micronaut --replicas=3 deployment.extensions "hello-micronaut" scaled $ kubectl get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE hello-micronaut 3 3 3 3 16m
ここでは、宣言型のアプローチに注意してください。新しいインスタンスを起動または停止するのではなく、常に実行するインスタンスの数を宣言します。Kubernetes の調整ループは、ユーザーがリクエストしたものと一致することを確認したうえで、必要に応じてアクションを実行します。
12. サービスへのアップグレードをロールアウトする
本番環境にデプロイしたアプリケーションは、いずれかの時点でバグ修正や追加機能の実装が必要になります。Kubernetes を使えば、ユーザーに影響を与えることなく、新しいバージョンを本番環境にデプロイできます。
まず、アプリケーションを修正しましょう。Cloud Shell からコードエディタを開きます。
/jib/examples/micronaut/src/main/groovy/example/micronaut/HelloController.groovy
に移動し、レスポンスの値を更新します。
@Controller("/hello") class HelloController { @Get("/") String index() { "Hello Kubernetes World" } }
/jib/examples/micronaut/build.gradle
では、次の行を更新して、イメージのバージョンを 0.1 から 0.2 にアップグレードします。
version '0.2'
次に、アプリケーションを再ビルドし、最新の変更を含めてパッケージ化します。
$ ./gradlew jibDockerBuild
イメージにタグを付けて、コンテナ イメージ レジストリに push します。
$ docker tag micronaut-jib:0.2 \ gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2 $ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2
これで、Kubernetes がレプリケーション コントローラを新しいバージョンのアプリケーションにスムーズに更新する準備が整いました。実行中のコンテナのイメージラベルを変更するには、既存の hello-micronaut deployment
を編集して、イメージを gcr.io/PROJECT_ID/micronaut-jib:0.1
から gcr.io/PROJECT_ID/micronaut-jib:0.2
に変更する必要があります。
kubectl set image
コマンドを使用して、ローリング アップデートでクラスタ全体にアプリケーションの新しいバージョンを一度に 1 インスタンスずつデプロイするよう Kubernetes に指示できます。
$ kubectl set image deployment/hello-micronaut \ micronaut-jib=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2 deployment.apps "hello-micronaut" image updated
http://EXTERNAL_IP:8080 をもう一度確認して、新しいレスポンスを返していることを確認します。
13. ロールバック
アプリケーションの新しいバージョンに間違いはありませんか?新しいバージョンにエラーがあり、迅速にロールバックする必要がある可能性があります。Kubernetes を使用すると、以前の状態に簡単にロールバックできます。次のコマンドを実行して、アプリケーションをロールバックします。
$ kubectl rollout undo deployment/hello-micronaut
Service の出力を確認すると、最初の「Hello World」に戻ります。表示されます。
14.まとめ
このステップでは、Apache Groovy ベースのシンプルな Micronaut hello world サービスを設定し、それを Cloud Shell 内で直接実行し、Jib でコンテナとしてパッケージ化して Google Kubernetes Engine にデプロイしました。
15. 完了
新しい Apache Groovy / Micronaut ウェブベースのマイクロサービスを構築して Google Kubernetes Engine の Kubernetes にデプロイする方法を学びました。
詳細
- Jib のドキュメントとサンプル: https://github.com/GoogleContainerTools/jib/
- Micronaut のウェブサイト: http://micronaut.io/
- Google Cloud Platform での Java: https://cloud.google.com/java/
- Java の例: https://cloud.google.com/java/samples
- Kubernetes の詳細なチュートリアルについては、bit.ly/k8s-lab をご覧ください。フルスタック アプリケーションのデプロイ手順について説明しています。
ライセンス
この作業はクリエイティブ・コモンズの表示 2.0 汎用ライセンスにより使用許諾されています。