Help us understand the problem. What is going on with this article?

CloudRunでNativeImageのJavaアプリを起動する

CloudRunでNativeImageのJavaアプリを起動する

CloudRunは未使用時はノード数が0まで落ちるGCPのサーバーレス環境のひとつです。
気が付けは東京リージョンでも使えるようになっていたので、久しぶりに使うがてらNativeImageとmicronautを触ってみました。

今回の技術要素は以下

  • GraalVM(NativeImage)
  • Micronaut
  • gcloud
  • ContainerRegistory
  • CloudRun

MacにGraalVMをインストール

GraalVMをインストール

https://github.com/oracle/graal/releases

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

ブラウザでアクセス

http://localhost:8080/usagisan

→ 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を参考にしました。

https://github.com/keeganwitt/docker-gradle

これを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を指定してビルドするようにすれば、手順としてはいけるはずなんだけど。。。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away