概要
-
Spring Boot + Kotlin
でHello World
を作成 - 作成したSpring Bootアプリが起動するDockerイメージを作成し、GKE(Google Kubernetes Engine)で動かす
- 地味に
WebFlux
を使ってるので、Netty
のイベントループで動いている
GitHub
必要なファイル
.
├── build.gradle
├── Dockerfile
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── kotlin
│ │ └── com
│ │ └── sugikeitter
│ │ └── kotlinboot
│ │ ├── controller
│ │ │ └── HelloController.kt
│ │ ├── data
│ │ │ └── Hello.kt
│ │ └── KotlinbootApplication.kt
│ └── resources
│ └── application.yml
└── test
└── kotlin
└── com
└── sugikeitter
└── kotlinboot
└── KotlinbootApplicationTests.kt
16 directories, 12 files
Kotling Bootアプリの作成
Project作成
-
IntelliJ IDEA Ulitimateの
Spring Intializer
からプロジェクトを作成する機能を使う
Contllerクラス作成
-
src/main/kotlin/com/sugikeitter/kotlingboot/controller
パッケージを作成し、HelloController.kt
を作成- クラスに
@RestController
をつけることでURLマッピング対象クラスに - メソッドに
@GetMapping("/hello")
をつけることで、GET /hello
のエントリポイントに対応
package com.sugikeitter.kotlingboot.controller import com.sugikeitter.kotlingboot.data.Hello import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @RestController class HelloController { @GetMapping("/hello") fun hell(): Hello { return Hello() } }
- クラスに
dataクラス作成
-
src/main/kotlin/com/sugikeitter/kotlingboot/data
パッケージを作成し、Hello.kt
を作成-
Kotlin
のdataクラスの機能を利用
package com.sugikeitter.kotlingboot.data import java.util.Date data class Hello ( val message: String = "Hello. World.", val date: Date = Date() )
-
設定ファイルの作成
-
今回は
src/main/resources/application.yml
を作成し、ここに設定を追記する- 利用するポートを
8888
にしてみた
server: port: 8888
- 利用するポートを
動作確認
-
Gradle
プラグインのbootRun
を使ってビルド&起動
$ ./gradlew bootRun
> Task :bootRun
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.4.RELEASE)
2018-08-26 23:14:33.612 INFO 10271 --- [ main] c.s.k.KotlingBootApplicationKt : Starting KotlingBootApplicationKt on MBP-13UAU-034 with PID 10271 (/Users/kesugimo/IdeaProjects/kotlingboot/build/classes/kotlin/main started by kesugimo in /Users/kesugimo/IdeaProjects/kotlingboot)
2018-08-26 23:14:33.619 INFO 10271 --- [ main] c.s.k.KotlingBootApplicationKt : No active profile set, falling back to default profiles: default
2018-08-26 23:14:33.679 INFO 10271 --- [ main] onfigReactiveWebServerApplicationContext : Refreshing org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@6a400542: startup date [Sun Aug 26 23:14:33 JST 2018]; root of context hierarchy
2018-08-26 23:14:34.729 INFO 10271 --- [ main] s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[/hello],methods=[GET]}" onto public com.sugikeitter.kotlingboot.data.Hello com.sugikeitter.kotlingboot.controller.HelloController.hell()
2018-08-26 23:14:34.798 INFO 10271 --- [ main] o.s.w.r.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
2018-08-26 23:14:34.799 INFO 10271 --- [ main] o.s.w.r.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
2018-08-26 23:14:34.969 INFO 10271 --- [ main] o.s.w.r.r.m.a.ControllerMethodResolver : Looking for @ControllerAdvice: org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@6a400542: startup date [Sun Aug 26 23:14:33 JST 2018]; root of context hierarchy
2018-08-26 23:14:35.436 INFO 10271 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-08-26 23:14:35.535 INFO 10271 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext : Started HttpServer on /0:0:0:0:0:0:0:0:8888
2018-08-26 23:14:35.535 INFO 10271 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8888
2018-08-26 23:14:35.539 INFO 10271 --- [ main] c.s.k.KotlingBootApplicationKt : Started KotlingBootApplicationKt in 2.414 seconds (JVM running for 2.805)
<==========---> 80% EXECUTING [12s]
> :bootRun
- リクエストが帰ってくることを確認
curl http://localhost:8888/hello
---
{"message":"Hello. World.","date":"2018-08-26T14:15:02.436+0000"}
---
Dockerfileの作成
- 最初にjavaビルド環境用のimageを作成し、
Gradle
でビルドしてjarファイルを作成する - 必要なjarファイルだけを配備してサイズを小さくし、container起動時にjarを起動させるimageを作成
- かなりえいやで作ったので他に良い方法がないかは調べたい
FROM openjdk:8-slim
RUN mkdir -p /opt/kotlingboot
ADD . /opt/kotlingboot
WORKDIR /opt/kotlingboot
RUN ./gradlew build
FROM openjdk:8-slim
COPY --from=0 /opt/kotlingboot/build/libs/kotlingboot-0.0.1-SNAPSHOT.jar /opt/app.jar
ENV PORT 8888
CMD ["java", "-jar", "/opt/app.jar"]
GKEで動作させる
-
コンテナ化されたウェブ アプリケーションのデプロイ | Kubernetes Engine のドキュメント | Google Cloudに沿って、今回作成した
Kotling Boot
コンテナをデプロイするように変更した - GCPを利用できる状態にしてプロジェクトも作成し、
Google Cloud Shell
を利用できる状態であることを前提に進める
初期設定
- 環境変数などを設定
# リージョンはとりあえず東京で
gcloud config set compute/zone asia-northeast1-c
# チュートリアルの通りPROJECT_IDを環境変数にしておく
export PROJECT_ID="$(gcloud config get-value project -q)"
Docker imageのビルドとプッシュ
# 作成したリポジトリをclone
git clone https://github.com/sugikeitter/KotlingBoot.git
# アプリのルートディレクトリへ移動
cd ./KotlingBoot
# imageのビルド(しばらく待つ)
docker build -t gcr.io/${PROJECT_ID}/hello-app-kotlingboot:v1 .
# 確認したら、ベースイメージ、ビルド用の一時イメージ(名無し)、最終イメージの3つが確認できる
docker images
---
REPOSITORY TAG IMAGE ID CREATED SIZE
gcr.io/kube-01-212312/hello-app-kotlingboot v1 4af1f5b45ade About a minute ago 264MB
<none> <none> 89727e75f7f8 About a minute ago 492MB
openjdk 8-slim e12b22a5b022 11 days ago 244MB
---
# Googleのリポジトリにpush
gcloud docker -- push gcr.io/${PROJECT_ID}/hello-app-kotlingboot:v1
プッシュしたimageをローカルで動作確認
# 8888ポートで起動
docker run --rm -p 8888:8888 gcr.io/${PROJECT_ID}/hello-app-kotlingboot:v1
- 別でGoogle Cloud Shellを開く
# 動作確認成功
curl http://localhost:8888/hello
---
{"message":"Hello. World.","date":"2018-08-26T15:16:59.591+0000"}
---
- KotlingBootを停止させる
# KotlingBootを起動しているShellで"Ctrl + c"
~
^C2018-08-26 15:19:00.735 INFO 1 --- [ Thread-7] onfigReactiveWebServerApplicationContext : Closing org.springframework.boot.web.reactive.contex
t.AnnotationConfigReactiveWebServerApplicationContext@b065c63: startup date [Sun Aug 26 15:16:41 UTC 2018]; root of context hierarchy
2018-08-26 15:19:00.744 INFO 1 --- [ Thread-7] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2018-08-26 15:19:00.757 INFO 1 --- [ Thread-7] r.ipc.netty.tcp.BlockingNettyContext : Stopped HttpServer on /0.0.0.0:8888
kubernetesでアプリを動作させる
クラスタ作成
# node3つでクラスタ作成(しばらく待つ)
gcloud container clusters create kotlingboot --num-nodes=3
# クラスタ作成確認
gcloud container clusters list
---
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
kotlingboot asia-northeast1-c 1.9.7-gke.6 35.200.10.183 n1-standard-1 1.9.7-gke.6 3 RUNNING
---
# 完了したらクラスタ認証情報を取得
gcloud container clusters get-credentials kotlingboot
デプロイ
# アプリのデプロイ
kubectl run hello-kotlingboot --image=gcr.io/${PROJECT_ID}/hello-app-kotlingboot:v1 --port 8888
# podが作成されていることを確認
kubectl get pods
---
NAME READY STATUS RESTARTS AGE
hello-kotlingboot-7c7dfcfdcc-t6s6n 0/1 ContainerCreating 0 7s
---
# 外部公開できるLBの作成
kubectl expose deployment hello-kotlingboot --type=LoadBalancer --port 80 --target-port 8888
# LBが作成されていることを確認
kubectl get deployment hello-kotlingboot
---
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-kotlingboot 1 1 1 1 1m
---
# 外部公開されているIPの確認
kubectl get service
---
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-kotlingboot LoadBalancer 10.31.254.26 35.221.107.65 80:31484/TCP 1m
kubernetes ClusterIP 10.31.240.1 <none> 443/TCP 5m
---
動作確認
スケールさせてみる
# レプリカを3に
kubectl scale deployment hello-kotlingboot --replicas=3
# deploymentが増えている
kubectl get deployment hello-kotlingboot
---
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-kotlingboot 3 3 3 3 10m
---
# podも増えている
kubectl get pods
---
NAME READY STATUS RESTARTS AGE
hello-kotlingboot-7c7dfcfdcc-4vk5l 1/1 Running 0 21s
hello-kotlingboot-7c7dfcfdcc-t6s6n 1/1 Running 0 10m
hello-kotlingboot-7c7dfcfdcc-wl8pl 1/1 Running 0 21s
---
作成したリソースのお掃除
# サービスを削除
kubectl delete service hello-kotlingboot
# ロードバランサが削除されるのを待つ
gcloud compute forwarding-rules list
# コンテナ クラスタを削除
gcloud container clusters delete kotlingboot
蛇足
-
Kotlin
+Spring Boot
を勝手にKotling Boot(KotlingBoot)
と呼んでみる