CloudRunでNativeImageのJavaアプリを起動する
CloudRunは未使用時はノード数が0まで落ちるGCPのサーバーレス環境のひとつです。
気が付けは東京リージョンでも使えるようになっていたので、久しぶりに使うがてらNativeImageとmicronautを触ってみました。
今回の技術要素は以下
- GraalVM(NativeImage)
- Micronaut
- gcloud
- ContainerRegistory
- CloudRun
MacにGraalVMをインストール
GraalVMをインストール
graalvm-ce-darwin-amd64-19.2.0.tar.gz をダウンロード。(バージョンはその時の最新で)
展開して、JavaVirtualMachinesに設定
tar xvzf graalvm-ce-darwin-amd64-19.2.0.tar.gz
sudo mv graalvm-ce-19.2.0 /Library/Java/JavaVirtualMachines/.
GraalVMが認識されていることを確認
yosistamp:tool katsuhiro$ /usr/libexec/java_home -V
Matching Java Virtual Machines (3):
11.0.2, x86_64: "OpenJDK 11.0.2" /Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home
1.8.0_221, x86_64: "GraalVM CE 19.2.0" /Library/Java/JavaVirtualMachines/graalvm-ce-19.2.0/Contents/Home
1.8.0_101, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home
環境変数を設定
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
export PATH=$JAVA_HOME/bin:$PATH
バージョン確認
yosistamp:tool katsuhiro$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-20190711112007.graal.jdk8u-src-tar-gz-b08)
OpenJDK 64-Bit GraalVM CE 19.2.0 (build 25.222-b08-jvmci-19.2-b02, mixed mode)
NativeImageのコンポーネントをインストール
gu install native-image
アプリ開発の準備(sdkmanとmicronautのインストール)
sdkman
curl -s "https://get.sdkman.io" | bash
source .bash_profile
※インストールしたら、.bash_profileの最後に設定が追加されるので、.bash_profileをリロードしている。
gradleとmicronautをインストール
2019/9/7時点で、gradle5.6.2、micronaut1.2.1がインストールされます。
バージョンを指定する場合は、最後にバージョンを指定する。(sdk install micronaut 1.2.1 etc)
sdk install gradle
sdk install micronaut
micronautアプリケーションの作成
プロジェクトフォルダを作って、そこでプロジェクトを作成
mn create-app <プロジェクト名> --features graal-native-image
サンプルアプリ
demo/controller/DemoController.javaを作成
package micronaut.demo.controller;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
@Controller("/usagisan")
public class DemoController {
@Get("/")
public String index() {
return "Hello Usagisan!";
}
}
実行してみる
./gradlew run
ブラウザでアクセス
→ Hello Usagisan! と表示されたらOK
イメージの作成
create-appで --features graal-native-imageをつけておくと、Dockerfileにnative-image作成の手順が自動で入ります。
create-appで --features graal-native-imageをつけない場合
FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim
COPY build/libs/demoapp-*-all.jar demoapp.jar
EXPOSE 8080
CMD java -Dcom.sun.management.jmxremote -noverify ${JAVA_OPTS} -jar demoapp.jar
create-appで --features graal-native-imageをつけた場合
FROM oracle/graalvm-ce:19.0.0 as graalvm
COPY . /home/app/micronaut-demo
WORKDIR /home/app/micronaut-demo
RUN gu install native-image
RUN native-image --no-server -cp build/libs/micronaut-demo-*-all.jar
FROM frolvlad/alpine-glibc
EXPOSE 8080
COPY --from=graalvm /home/app/micronaut-demo .
ENTRYPOINT ["./micronaut-demo"]
CloudRepository(GCP)にアップ
ビルドして、dockerイメージ作成
./gradlew build
./docker-build.sh
10分ほど待つと、micronaut-demoというイメージが出来上がります。(長い。。。)
yosistamp:micronaut-demo katsuhiro$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
micronaut-demo latest ea22c441c083 13 minutes ago 124MB
<none> <none> 706b1ee85c04 13 minutes ago 1.91GB
ContainerRegistoryにアップ
gcloud auth configure-docker
docker tag micronaut-demo asia.gcr.io/<プロジェクトID>/micronaut-demo
docker tag micronaut-demo asia.gcr.io/<プロジェクトID>/micronaut-demo:latest
docker push asia.gcr.io/<プロジェクトID>/micronaut-demo:latest
CloudRunにデプロイ
gcloud beta run deploy sample-app --allow-unauthenticated --memory 128Mi --region asia-northeast1 --timeout 30 --image <イメージ名>
※イメージ名はContainerRegistoryで確認
デプロイが完了したら、URLが払い出されます。
yosistamp:micronaut-demo katsuhiro$ gcloud beta run deploy sample-app --allow-unauthenticated --memory 128Mi --region asia-northeast1 --timeout 30 --image <イメージ名>
Deploying container to Cloud Run service [sample-app] in project [プロジェクトID] region [asia-northeast1]
✓ Deploying new service... Done.
✓ Creating Revision...
✓ Routing traffic...
✓ Setting IAM Policy...
Done.
Service [sample-app] revision [sample-app-00001] has been deployed and is serving traffic at https://sample-app-xxxxxx.run.app
あとはブラウザでURLにアクセスすればHello Usagisan!と表示されるはず。
補足
ローカルでのイメージ作成ではなく、CloudSourceRepository→CloudBuild→ContainerRepositoryと流す場合は、基本的には以下のような手順になると思います。
ほんとはそうしたかったが、実行したところメモリ不足でイメージ作成が最後まで進みませんでした。。。
(なので、ローカルでイメージを作る方法に切り替えた)
CloudBuildでワーカーのメモリ増やす方法ってあるのかな。。。
Gradle5のイメージ作成
gradleでビルドするのでGradleのイメージが必要ですが、公式のCloud-BuilderはGradle4.6のため、micronautのビルドに失敗します。(5.0+)
そのため、Gradle5のカスタムイメージを準備して、ビルドします。
私は、下記のDockerfileを参考にしました。
これをCloudSourceRepositoryに入れてCloudBuildでビルドすると、Gradle5のカスタムイメージができます。
cloudbuild.yamlの用意
steps:
- name: 'gcr.io/$PROJECT_ID/<イメージ>:<タグ>'
args: ['./gradlew', 'build']
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/micronaut-demo', '.' ]
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/micronaut-demo']
images:
- 'gcr.io/$PROJECT_ID/micronaut-demo'
これで、CloudBuildでcloudbuild.yamlを指定してビルドするようにすれば、手順としてはいけるはずなんだけど。。。