Dockerコンテナ起動時に環境変数をquarkusのapplication.propertiesに渡す方法

##はじめに
quarkusでは以下のようにapplication.propertiesに設定した値を変数に代入することができます。
https://quarkus.io/guides/config

開発環境、ステージング環境、本番環境など異なる環境によって変数の値が異なる場合以下のように記載することもできますが、
ビルドした成果物を管理する際は環境ごとに管理しなければいけません。

```{#lst:application.properties}
quarkus.http.port=9090
%dev.quarkus.http.port=8181
%staging.quarkus.http.port=9999
```

ちょうど業務で成果物をDockerイメージで管理することがあり、環境ごとに成果物が異なるのは管理の面で嫌だなぁと思っておりました。
そこで本記事では、環境によって変数の値が異なる場合でも、管理するDockerイメージを一つで済ませる方法を記載します。

※サンプルのプロジェクトを修正し説明します

##準備
以下のコマンドでサンプルプロジェクトを作成します。

```
$ mvn io.quarkus:quarkus-maven-plugin:1.13.2.Final:create \
      -DprojectGroupId=org.acme \
      -DprojectArtifactId=config-quickstart \
      -DclassName="org.acme.config.GreetingResource" \
      -Dpath="/greeting"
$ cd config-quickstart
```

ディレクトリ構造は以下のようになっていると思います。

```
.
├── mvnw
├── mvnw.cmd
├── pom.xml
├── README.md
└── src
    ├── main
    │   ├── docker
    │   │   ├── Dockerfile.jvm
    │   │   ├── Dockerfile.legacy-jar
    │   │   ├── Dockerfile.native
    │   │   └── Dockerfile.native-distroless
    │   ├── java
    │   │   └── org
    │   │       └── acme
    │   │           └── config
    │   │               └── GreetingResource.java
    │   └── resources
    │       ├── application.properties
    │       └── META-INF
    │           └── resources
    │               └── index.html
    └── test
        └── java
            └── org
                └── acme
                    └── config
                        ├── GreetingResourceTest.java
                        └── NativeGreetingResourceIT.java
```

##application.properties修正
現段階では何も記載されていないので、以下を記載します。

```{lst:src/main/resources/application.properties}
greeting.message = hello
greeting.name = ${NAME:quarkus}  # ${環境変数名:デフォルト値}
```

##ソース修正
以下のように修正します

```{lst:src/main/java/org/acme/config/GreetingResource.java}
package org.acme.config;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.config.inject.ConfigProperty;　//★追加

@Path("/greeting")
public class GreetingResource {

    @ConfigProperty(name = "greeting.message")　//★追加
    String message;　//★追加

    @ConfigProperty(name = "greeting.name")　//★追加
    String name;　//★追加

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return message + " " + name; //★修正
    }
}
```

##修正したソースコードをbuild
以下のコマンドを実行するとquarkus-run.jarというファイルが作成されます。(testはskipしてます)

```
$ mvn package -Pnative -Dnative-image.docker-build=true -Dmaven.test.skip=true

$ ls target/quarkus-app/
app  lib  quarkus  quarkus-app-dependencies.txt  quarkus-run.jar
```


##Dockerコンテナイメージ作成
以下のコマンドでDockerのコンテナイメージを作成します。

```
$ docker build -f src/main/docker/Dockerfile.jvm -t quarkus/greeting

$ docker image ls | grep greeting
quarkus/greeting     latest          10466a00a3a4        2 hours ago         330MB
```
作成されてますね。


##環境変数を設定して作成したイメージを起動
docker-composeを使用し、イメージを起動したいと思います。
以下のyamlを作成し、application.propertiesに記載した環境変数を設定します。

```{lst:docker-compose.yaml}
version: '3.3'
services:
  quarkus-greeting:
    image: quarkus/greeting:latest
    container_name: quarkus-greeting
    environment:
      - NAME=docker
    ports:
      - 8080:8080
```

以下のコマンドでイメージを起動し、起動確認します。

```
$ docker-compose up -d
$ docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED              STATUS              PORTS                    NAMES
9a93d018db6e        quarkus/greeting:latest   "/deployments/run-ja…"   About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp   quarkus-greeting
```

念のため環境変数が設定されているか確認

```
$ docker exec -it 9a93d018db6e env | grep NAME=docker
NAME=docker
```

##アプリケーションの動作確認
curlコマンドで起動したイメージに対してリクエストを投げてみます

```
$ curl localhost:8080/greeting
hello docker
```

意図した値が入ってますね。

ちなみに、
環境変数を設定しない場合は[application.properties](#applicationproperties修正)で設定したデフォルト値が使用され、以下のような結果になります。

```
$ curl localhost:8080/greeting
hello quarkus
```

このように、環境ごとに変数の値が異なる場合でもイメージは1つで済みそうですね。

今回はdocker-composeでしたがkubernetesの場合でもmanifestfileに環境変数を設定することで同様のことができます。