QuarkusのDevServicesを試す
はじめに
先日、Quarkusの1.13がリリースされので、リリースブログを眺めていたのですがDevServicesという便利そうな機能が追加されていたので試してみようかと思います。
DevServicesとは
DevモードでQuarkusを起動した場合、追加の設定無しでDBを起動してくれてDevモードのコンフィグとバインドしてくれるようです。
例えば、PostgresSQL JDBCの拡張がPomの依存に追加されている場合Testcontainersを使って(もしくはJavaのプロセス内で)自動的にDBを立ち上げてくれます。(今回は試しませんがReactiveクライアントにも対応しているようです)
現在DevSercicesは以下のDBに対応しているようです。
- Postgresql (コンテナ)
- MySQL (コンテナ)
- MariaDB (コンテナ)
- H2 (プロセス内)
- Apache Derby (プロセス内)
- DB2 (コンテナ)
- MSSQL (コンテナ)
また、DB2とMSSQLに関してはライセンスへの同意が必要です。src/main/resources/container-license-acceptance.txt
を作成して以下のようなテキストを記述する必要があります。
ibmcom/db2:11.5.0.0a mcr.microsoft.com/mssql/server:2017-CU12
使ってみる
環境
今回は以下の環境でアプリを動かします。
$ java --version openjdk 16 2021-03-16 OpenJDK Runtime Environment (build 16+36-2231) OpenJDK 64-Bit Server VM (build 16+36-2231, mixed mode, sharing) $ mvn --version Apache Maven 3.6.3 Maven home: /usr/share/maven Java version: 16, vendor: Oracle Corporation, runtime: /home/username/.sdkman/candidates/java/16-open Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-70-generic", arch: "amd64", family: "unix" $ docker version Client: Docker Engine - Community Version: 20.10.5 API version: 1.41 Go version: go1.13.15 Git commit: 55c4c88 Built: Tue Mar 2 20:18:20 2021 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.5 API version: 1.41 (minimum version 1.12) Go version: go1.13.15 Git commit: 363e9a8 Built: Tue Mar 2 20:16:15 2021 OS/Arch: linux/amd64 Experimental: true containerd: Version: 1.4.4 GitCommit: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e runc: Version: 1.0.0-rc93 GitCommit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec docker-init: Version: 0.19.0 GitCommit: de40ad0
プロジェクトを作成する
今回はPosgresSQLを利用して、DBに保存されたデータを返す簡単なAPIを記述しようと思います。
以下の構成でプロジェクトを作成します。
Devモードでアプリケーションを起動する
DevServcesはデフォルトでオンになっており、DB URLやパスワード、ユーザ名が設定されていなければTestcontainersを使ってDBを立ち上げてくれます。
先程、作成したプロジェクトをunzipしてなにも変更せずにDevモードで起動すると以下のようなログを出力してDBも立ち上げてくれます。
$ ./mvnw compile quarkus:dev [INFO] Scanning for projects... [INFO] [INFO] ----------------------< dev.hirooka:devservices >----------------------- [INFO] Building devservices 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- quarkus-maven-plugin:1.13.0.Final:generate-code (default) @ devservices --- [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ devservices --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 2 resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ devservices --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- quarkus-maven-plugin:1.13.0.Final:dev (default-cli) @ devservices --- Listening for transport dt_socket at address: 5005 2021-04-05 12:13:24,948 INFO [org.tes.doc.DockerClientProviderStrategy] (build-28) Loaded org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy from ~/.testcontainers.properties, will try it first 2021-04-05 12:13:25,299 INFO [org.tes.doc.DockerClientProviderStrategy] (build-28) Found Docker environment with Environment variables, system properties and defaults. Resolved dockerHost=unix:///var/run/docker.sock 2021-04-05 12:13:25,300 INFO [org.tes.DockerClientFactory] (build-28) Docker host IP address is localhost 2021-04-05 12:13:25,324 INFO [org.tes.DockerClientFactory] (build-28) Connected to docker: Server Version: 20.10.5 API Version: 1.41 Operating System: Ubuntu 20.04.2 LTS Total Memory: 31741 MB 2021-04-05 12:13:25,326 INFO [org.tes.uti.ImageNameSubstitutor] (build-28) Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor') 2021-04-05 12:13:25,352 INFO [org.tes.uti.RegistryAuthLocator] (build-28) Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: testcontainers/ryuk:0.3.1, configFile: /home/yuya-hirooka/.docker/config.json. Falling back to docker-java default behaviour. Exception message: /home/yuya-hirooka/.docker/config.json (そのようなファイルやディレクトリはありません) 2021-04-05 12:13:26,102 INFO [org.tes.DockerClientFactory] (build-28) Ryuk started - will monitor and terminate Testcontainers containers on JVM exit 2021-04-05 12:13:26,103 INFO [org.tes.DockerClientFactory] (build-28) Checking the system... 2021-04-05 12:13:26,103 INFO [org.tes.DockerClientFactory] (build-28) ✔︎ Docker server version should be at least 1.6.0 2021-04-05 12:13:26,185 INFO [org.tes.DockerClientFactory] (build-28) ✔︎ Docker environment should have more than 2GB free disk space 2021-04-05 12:13:26,295 INFO [🐳 .6.12]] (build-28) Creating container for image: postgres:9.6.12 2021-04-05 12:13:26,337 INFO [🐳 .6.12]] (build-28) Starting container with ID: 33b42f67a20ed4d4ff1b2f0135ec06b13c3444e5782567e4d30395e0c5741fd3 2021-04-05 12:13:26,710 INFO [🐳 .6.12]] (build-28) Container postgres:9.6.12 is starting: 33b42f67a20ed4d4ff1b2f0135ec06b13c3444e5782567e4d30395e0c5741fd3 2021-04-05 12:13:30,167 INFO [🐳 .6.12]] (build-28) Container postgres:9.6.12 started in PT3.98152593S __ ____ __ _____ ___ __ ____ ______ --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ 2021-04-05 12:13:30,588 INFO [io.quarkus] (Quarkus Main Thread) devservices 1.0.0-SNAPSHOT on JVM (powered by Quarkus 1.13.0.Final) started in 6.064s. Listening on: http://localhost:8080 2021-04-05 12:13:30,589 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. 2021-04-05 12:13:30,589 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, hibernate-orm, jdbc-postgresql, mutiny, narayana-jta, resteasy, smallrye-context-propagation]
docker psコマンドで確認してみるとPostgresとTestcontainersのコンテナがきどうしているのが確認できます。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 74541a57e8cd postgres:9.6.12 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:49164->5432/tcp great_blackburn 72f55524eecf testcontainers/ryuk:0.3.1 "/app" 3 minutes ago Up 3 minutes 0.0.0.0:49163->8080/tcp testcontainers-ryuk-42c2bcf5-1ddc-415d-b694-3f7f311d885e
データを取得してみる
それでは、実際にこの起動したDB利用してみようと思います。
まずは初期データを投入します。
まずはapplication.properties
を以下のように修正します。
%dev.quarkus.hibernate-orm.log.sql=true %dev.quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.database.generation=drop-and-create
を指定することで、Quarkusのアプリは起動時にsqlファイルを読み取ってテーブルを作成してくれるようになります。
また、デフォルトではresources
のimport.sql
という名前のファイルを読み取るようになっているのでそちらも用意しておきます。
drop table if exists message; create table message( id int, content varchar(100) ); insert into message values (1, 'hello, dev service1'), (2, 'hello, dev service2'), (3, 'hello, dev service3');
quarkus.hibernate-orm.log.sql
はSQLの実行がわかりやすいように設定しています。また%dev
はDevモードで起動時に有効になる設定を示します。
この状態でアプリケーションを再起動します。
すると、ここには記述しませんが実行されたSQLのログが出力されるはずです。
ここまでで、起動したDBを利用できていることががある程度確認できたかもしれませんが。
EntityとControllerを作成してmessage
を取得してみようと思います。
MessageEntity.java
@Entity public class MessageEntity { @Id private int id; private String content; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
GreetingResource .java
@Path("/messages") public class GreetingResource { private EntityManager em; public GreetingResource(EntityManager em) { this.em = em; } @GET @Produces(MediaType.APPLICATION_JSON) public List<MessageEntity> hello() { return em.createNativeQuery("select id, content from message", MessageEntity.class).getResultList(); } }
コントローラーはデフォルトで作成されたGreetingResource.java
を少し改造して作っています。また、少し筋は悪いかもしれませんがEntityをそのままレスポンスとして返すようにしています。
アプリケーションがリロードされたらcURLを叩いてみます。
$ curl localhost:8080/messages [{"id":1,"content":"hello, dev service1"},{"id":2,"content":"hello, dev service2"},{"id":3,"content":"hello, dev service3"}]
import.sql
でセットしていた値が帰ってきていることが確認できました。
本番用の設定を記述する
前述したとおりDevServicesはDB URLなどがセットされている場合においてDBを起動しないようになっています。
例えば、以下のように設定を記述してアプリケーションを起動すると、DBが起動されません。
quarkus.datasource.db-kind=postgresql quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/hibernate_orm_test quarkus.datasource.username=username quarkus.datasource.password=password
起動すると、import.sql
の実行に失敗したエラーログが出力されたと思います。
application.properites
に本番用の設定値を書きたいが、ローカルでの開発ではDevServicesを利用したい場合は設定のプリフィクスとして%prod
を以下のように付与します。
%prod.quarkus.datasource.db-kind=postgresql %prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/hibernate_orm_test %prod.quarkus.datasource.username=username %prod.quarkus.datasource.password=password
これで上記の設定はDevモードでは用いられることはなくDevServicesはDBを立ち上げてくれます。
その他の設定値
最後にDevServicesの設定をいくつかまとめておこうと思います。完全なリストはこちら をご覧ください。
設定値 | 説明 | デフォルト値(型) |
---|---|---|
quarkus.datasource.devservices | DevServicesを明示的に有効化するかのフラグ | true(boolean) |
quarkus.datasource.devservices.image-name | 利用するコンテナイメージ名を指定する。もしH2などコンテナを起動しないサービスの場合は影響を及ぼさない | (string) |
また、ここにはまとめてませんが、名前付きデータソースごとにそれぞれの設定を行なうことも可能なようです。