Kotlin (Ktor & Docker)でHello Worldしてみる

先日書いた通り、今年はKotlinに挑戦してみます。

その第一歩としてとりあえずHello Worldしてみるところから始めてみました。

今回はKtorを使ってみることにします。

Ktor

KtorはKotlinを開発しているJetBrains社製のWebフレームワークです。

Ktor自体もKotlinで書かれており、軽量で柔軟性に富んだ (Lightweight and Flexible) フレームワークとのことです。

JavaJVM言語のフレームワークと言えばSpring Bootが有名かと思います。

当初Spring Bootを使ってやってみようと進めていたのですが、JetBrains社製のKtorは言わばKotlinの公式フレームワークなのでこちらで再度やり直すことにしました。

Hello Worldしてみる

今回は上記2つをDocker上で動くようにしてみたいと思います。

こちらのKtor公式ドキュメントを参考に進めていきます。

Ktorのプロジェクトを作成

Ktorのプロジェクトの作り方は色々あります。

IntelliJ IDEA Ultimateを使っていればIDE上で作成することもできるようですが、まだ無課金なので今回はKtor Project Generatorを使います。

プロジェクト名やバージョン等を設定したら「Add plugins」をクリックします。

認証やルーティング等、様々なプラグインを追加できます。これらは後からでも追加できるので後回しでも良さそうです。

とりあえず今回はRoutingCORSを追加しました。

「Generate project」をクリックするとzipファイルのダウンロードが始まります。解凍するとプロジェクトに必要なファイルが一式揃っています。

Dockerの設定

Dockerの設定を行っていきます。今回はDBも用意したいのでDocker composeを使います。

まずはDockerfileをプロジェクトルート直下に作成します。

FROM eclipse-temurin:17
EXPOSE 8080:8080
RUN mkdir /app
COPY ./build/libs/*-all.jar /app/blog.jar
ENTRYPOINT ["java", "-jar", "/app/blog.jar"]

上記公式ではopenjdkのイメージを使用していますが、OpenJDKのDockerイメージは非推奨となり今後更新されないため、eclipse-temurinを代わりに使用します。

参考: Docker HubのOpenJDKイメージの利用を更新するためのアドバイス - 赤帽エンジニアブログ

続いてdocker-compose.ymlを作成します。

version: "3"
services:
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - 8080:8080

Dockerの設定は取り急ぎ以上です。

ビルド

先程のDockerfileから分かる通り、ビルド済みのjarファイルをローカルからコンテナ上の/app/hoge.jarにコピーしています。

なのでDockerイメージのビルド前にKotlinのビルドが必要です。

./gradlew buildFatJar

完了したら今度はDockerイメージをビルドします。

docker compose build

そして最後にコンテナを立ち上げます。

docker compose up -d

無事起動したらhttp://localhost:8080にアクセスして以下のように表示されたらOKです。

が、これだと都度Kotlinのビルド⇒Dockerイメージのビルド⇒コンテナ起動しないと変更が反映されないので修正していきます。

Dockerfileを修正

以下のように修正します。

FROM eclipse-temurin:17
EXPOSE 8080:8080
RUN mkdir /app
WORKDIR /app/

docker-compose.yml修正

以下のように修正します。

version: "3"
services:
  app:
    volumes:
      - .:/app/
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - 8080:8080
    tty: true

tty: trueを追加してコンテナの起動状態を継続させています。

Auto-reload

KtorにはAuto-reloadという機能があり、変更を検知して再コンパイルしてくれます。

これを有効にするにはdevelopment modeをONにして監視対象のパスを追加します。

ktor {
    deployment {
        port = 8080
        watch = [ classes ] // 追加
    }
    application {
        modules = [ com.example.ApplicationKt.module ]
    }
    development = true // 追加
}

ここまで設定したら再度イメージをビルドして立ち上げます。

docker compose build --no-cache
docker compose up -d

appコンテナ内でバックグラウンドでビルドします。

docker compose exec app ./gradlew -t build -x test

以下のように表示されたらOK。

BUILD SUCCESSFUL in 2m 16s
11 actionable tasks: 11 up-to-date

Waiting for changes to input files... (ctrl-d to exit)
<-------------> 0% WAITING

別タスクでアプリケーションを起動します。

docker compose exec app ./gradlew run

しばらく待つと以下のように表示されます。

2023-01-12 13:01:17.457 [main] INFO  Application - Application started in 2.62 seconds.
2023-01-12 13:01:18.126 [main] INFO  Application - Responding at http://0.0.0.0:8080
<===========--> 85% EXECUTING [51s]
> :run

この状態でコードを修正すると再度./gradlew -t build -x testが走り、変更が反映されます。

まとめ

取り急ぎ開発できる体制は整いました。

が、まだわからないことだらけです。./gradlew -t build -x testすると毎回zipファイルがダウンロードされるし、その他不要なタスクも大量にありそうです。

そのあたりの設定も少しずつ見ていきたいと思います。