Kubernetes環境のLibertyでのConfigMapを使った環境変数とかserver.xmlの設定方法

Kubernetes環境にWebSphere Libertyのコンテナをデプロイする場合の、Libertyの設定方法の選択肢を調べました。

- server.xmlに設定を書いて、コンテナイメージ内にserver.xmlを含める
- 環境変数で渡す
- ConfigMapにserver.xmlを書いてマウントする

という方法がありそうです。

## LibertyのDockerイメージ

[公式Dockerイメージ](https://hub.docker.com/_/websphere-liberty/)では

```
/config -> /opt/ibm/wlp/usr/servers/defaultServer
/output -> /opt/ibm/wlp/output/defaultServer
```

というシンボリックリンクがあり、

```
WLP_OUTPUT_DIR=/opt/ibm/wlp/output
LOG_DIR=/logs
```

という環境変数がセットされています。
LibertyのKnowledgeCenter以下のトピックでも、このような構成が標準であることが言及されています。

[Liberty Helm chart](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/rwlp_icp_helm.html)

server.xmlは次の通り何も書かれておらず、

```xml
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <!-- <feature></feature> -->
    </featureManager>

</server>
```

次のようにDockerfileを書き、server.xmlを上書きして使うことが想定されています。

```dockerfile
FROM websphere-liberty:kernel
COPY server.xml /config/
RUN installUtility install --acceptLicense defaultServer
```

## 環境変数

一部の設定は環境変数としても定義できます。
また、`server.xml`では`${env.MYSQL_SERVERNAME}`のように記述することで環境変数から値を取得することもできます。

### Deploymentに直接定義

環境変数をDeploymentに直接定義する場合は以下のようにします。

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: liberty
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: websphere-liberty:kernel
        ports:
        - containerPort: 9080
        env:
        - name: WLP_LOGGING_CONSOLE_FORMAT
          value: "json"
        - name: WLP_LOGGING_CONSOLE_LOGLEVEL
          value: "info"
        - name: WLP_LOGGING_CONSOLE_SOURCE
          value: "message,trace,accessLog,ffdc"
```

### ConfigMapに環境変数を定義

ConfigMapに格納した環境変数をDeploymentから参照するには、以下のようにします。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: liberty-env-config
data:
  consoleFormat: "json"
  consoleLoglevel: "info"
  consoleSource: "message,trace,accessLog,ffdc"
```

キー毎に`configMapKeyRef`を記載します。

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: liberty
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: websphere-liberty:kernel
        ports:
        - containerPort: 9080
        env:
        - name: WLP_LOGGING_CONSOLE_FORMAT
          valueFrom:
            configMapKeyRef:
              name: liberty-env-config
              key: consoleFormat
        - name: WLP_LOGGING_CONSOLE_LOGLEVEL
          valueFrom:
            configMapKeyRef:
              name: liberty-env-config
              key: consoleLoglevel
        - name: WLP_LOGGING_CONSOLE_SOURCE
          valueFrom:
            configMapKeyRef:
              name: liberty-env-config
              key: consoleSource
```

### envFromで環境変数をまとめて渡す

環境変数をたくさん列挙するのが面倒な場合はまとめて渡すこともできます。
ConfigMapは先ほどと同じですが、ConfigMapのキー名には環境変数名を使うようにします。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: liberty-env-config
data:
  WLP_LOGGING_CONSOLE_FORMAT: "json"
  WLP_LOGGING_CONSOLE_LOGLEVEL: "info"
  WLP_LOGGING_CONSOLE_SOURCE: "message,trace,accessLog,ffdc"
```

Deploymentでは`env`の代わりに`envFrom`を指定し、`configMapRef`でConfigMapの名前を指定すると全てのキーが環境変数として展開されます。

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: liberty
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: websphere-liberty:kernel
        ports:
        - containerPort: 9080
        envFrom:
        - configMapRef:
            name: liberty-env-config
```

### server.env

メリットがあるかわかりませんが、ConfigMapに`server.env`を格納し、ファイルとしてマウントすることで環境変数を渡すことも可能です。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: server-env-config
data:
  server.env: |-
    WLP_LOGGING_CONSOLE_FORMAT=json
    WLP_LOGGING_CONSOLE_LOGLEVEL=info
    WLP_LOGGING_CONSOLE_SOURCE=message,trace,accessLog,ffdc
```

Deploymentでは、このConfigMapをファイルとしてマウントします。

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: liberty
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: websphere-liberty:kernel
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: server-env-vol
          mountPath: /config/server.env
          subPath: server.env
      volumes:
      - name: server-env-vol
        configMap:
          name: server-env-config
          items:
          - key: server.env
            path: server.env
```

## server.xmlをマウントする

Libertyの設定はserver.xmlに書かれているため、設定変更時には通常はイメージの再ビルドが必要になりますが、server.xmlをマウントするか、Libertyでは`configDropins`ディレクトリーに`server.xml`のサブセットを含めることができるので、ConfigMapを使って設定を外部からコンテナにDrop inすることもできます。

xmlを`configDropins/defaults`に配置した場合はその設定が`server.xml`に存在しない場合のデフォルト値となり、`configDropins/overrides`に配置した場合は`server.xml`の設定を上書きします。

ログの設定を記述したserver.xmlを含むConfigMapを作成します。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: logging-config
data:
  logging.xml: |-
    <?xml version="1.0" encoding="UTF-8"?>
    <server>
      <httpAccessLogging id="accessLogging" />
      <httpEndpoint id="defaultHttpEndpoint" accessLoggingRef="accessLogging" />
      <logging consoleFormat="json" consoleLoglevel="info" consoleSource="message,trace,accessLog,ffdc" />
    </server>
```

Deploymentでは、このConfigMapをファイルとしてマウントします。
`mountPath`に`configDropins`ディレクトリーを指定してしまうと、この下に複数のxmlをマウントできないので、`mountPath`にはファイルパスを書き、さらに`subPath`にファイル名を指定しています。ただしこの方法だとConfigMapの変更が動的にPodに反映されないと思われます。

```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: liberty
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: websphere-liberty:kernel
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: logging-config-vol
          mountPath: /config/configDropins/overrides/logging.xml
          subPath: logging.xml
      volumes:
      - name: logging-config-vol
        configMap:
          name: logging-config
          items:
          - key: logging.xml
            path: logging.xml
```

## 参考リンク

[WAS V9 Liberty基盤設計セミナー資料](https://www.ibm.com/developerworks/jp/websphere/library/was/liberty_v9_infradesign/index.html)

[Running Liberty applications in IBM Cloud Private](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_icp.html)

[Logging and Trace](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/rwlp_logging.html)

[Kubernetes: ConfigMap / Secret の内容を一度に環境変数として読み込む (envFrom)](https://qiita.com/tkusumi/items/cf7b096972bfa2810800)

[Configuring environment variables during container startup](https://www.ibm.com/support/knowledgecenter/en/SS5PWC/config_consume_during_container_startup.html)

[Liberty サーバーでの Microservice Builder ファブリックの使用](https://www.ibm.com/support/knowledgecenter/ja/SS5PWC/fabric_task.html)