【Podman】Payara と PostgreSQL の JavaEE Web アプリ Pod 作成方法

Java EE の WAR を Payara 4 と PostgreSQL を使って Windows 上の Podman で動かす手順です。 古い構成なので、ドキュメント調べるのに苦労したので、ここにメモとして残します。

PowerShell 上での操作を前提とします。


Podman インストール

念のため Podman のインストールから。

WSL 未導入の場合は、PowerShell または コマンドプロンプトを管理者モードで開き、以下でインストールしてマシンを再起動しておきます。

> wsl --install

Winget で Podman をインストールします(Podman Desktop は使いません)。

> winget add RedHat.Podman

VM作成して Podman を起動します。

> podman machine init
> podman machine start

次回からは以下のようにVMだけ起動すればOKです。

> podman machine start


Payara Docker イメージのビルド

JDBC ドライバの導入やJDBCリソース設定などが必要なため、公式の Payara Docker イメージ を元にビルドします。

Dockerfile を作成します。

FROM payara/server-full:4.181

USER payara

COPY postgresql-42.6.0.jar /opt/payara41/glassfish/domains/domain1/lib/postgresql-42.6.0.jar
COPY post-boot-commands.asadmin $POSTBOOT_COMMANDS

ここでは、payara4 系を使うので、ベースイメージとして payara/server-full:4.181 を使用します。

JDBCドライバは /opt/payara41/glassfish/domains/domain1/lib/ 配下に配備します。現在の payara5 系 /opt/payara/appserver/glassfish/domains/domain1/lib とは異なるため注意が必要です。

$POSTBOOT_COMMANDS に asadmin コマンドのファイルを配備すればドメイン起動後の初期化で自動実行されます(ドメイン起動前に実行したい場合は $PREBOOT_COMMANDS を使うことができます)。このスクリプトは $CONFIG_DIR/post-boot-commands.asadmin がデフォルトなので、ローカルの設定ディレクトリを $CONFIG_DIR にマウントしてあげれば良いです。が、ここでは面倒なので、イメージに含めることにします。

なお、war 自体をイメージに含める場合は COPY myapplication.war $DEPLOY_DIR のようにすることができます。


postgres ドライバ

postgres ドライバをダウンロードします。

> Invoke-WebRequest -Uri https://jdbc.postgresql.org/download/postgresql-42.6.0.jar -OutFile postgresql-42.6.0.jar


post-boot-commands.asadmin

post-boot-commands.asadmin ファイルを作成します。このファイルは、実行したい asadmin コマンドを羅列したものです。

以下は、JDBC設定と、Auth Realm、JavaMail の設定例です。

# Connection Pool
create-jdbc-connection-pool --datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property user=POSTGRES_USER:password=POSTGRES_PASS:url=jdbc\:postgresql\://localhost\:5432/POSTGRES_DB POSTGRES_POOL

# JDBC Resource
create-jdbc-resource --connectionpoolid POSTGRES_POOL jdbc/POSTGRES_POOL

# Create Auth Realm
create-auth-realm --classname com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm --property jaas-context=jdbcRealm:datasource-jndi=jdbc/POSTGRES_POOL:user-table=USERS:user-name-column=NAME:password-column=PASSWORD:group-table=USER_GROUPS:group-name-column=GROUP_NAME:digest-algorithm=SHA-512 JDBC_REALM

# JavaMail Resource
create-javamail-resource --mailhost smtp.gmail.com --mailuser <gmail_user>@gmail.com --fromaddress <gmail_user>@gmail.com --storeprotocol=imap --storeprotocolclass=com.sun.mail.imap.IMAPStore --transprotocol=smtp --transprotocolclass=com.sun.mail.smtp.SMTPTransport --property mail-smtps-host=smtp.gmail.com:mail-smtps-password=<password>:mail-smtps-socketFactory-class=javax.net.ssl.SSLSocketFactory:mail-smtps-auth=true:mail-smtps-socketFactory-port=465:mail-smtps-port=465:mail-smtps-user=<gmail_user>@gmail.com:mail-smtps-starttls-enable=true:mail-smtps-socketFactory-fallback=false:mail.smtp.starttls.enable=true mail/GMAIL_SESSION

# で行コメントになります。コマンドには改行を含むことができないため、1行で書く必要があります。

--property の項目は、<key>=<value>:<key>=<value> の形式で記載するため、値中に : を含む場合は \: のようにエスケープし、= を含む場合は \\= のようにエスケープする必要があるため注意が必要です。

イメージビルド

上記準備ができれば、以下でイメージをビルドします。

> podman build ./ -t payara-appimage

> podman images

JDBCドライバと接続設定を含むイメージが作成できました。


PostgreSQL イメージ

postgres は公式イメージをそのまま使用します。 ので、ここではコンテナ起動用の事前準備を行います。

データベース用のボリュームを作成しておきます。

> podman volume create myapp_pgdata_volume

> podman volume ls

データベースへ初期データなどを投入する必要がある場合は、コンテナの /docker-entrypoint-initdb.d 以下に初期化スクリプトを配備します。 ここでは、新しいデータベースとユーザを作成する ./initdb/init-user-db.sh を例とします。

#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
  CREATE USER <user_name> WITH PASSWORD '<user_pass>';
  CREATE DATABASE "<database_name>" OWNER <user_name>;
  GRANT ALL PRIVILEGES ON DATABASE "<database_name>" TO <user_name>;
  -- ...
EOSQL

テーブル作成や初期データ投入のSQLを指定することができます。 データベース名などにハイフン - を含む場合は、"<database_name>" のようにダブルクオートで括る必要があります。


Pod の作成

payara と postgres を含めた Pod を作成します。

> podman pod create -p 5432:5432 -p 4848:4848 -p 8080:8080 --name myapp-pod

> podman pod ps

5432:5432 は postgres 接続、4848:4848 は payara の管理コンソール接続、8080:8080 はアプリケーション接続のポートになります。


Payara コンテナ

作成した Pod に payara を追加します。

先で作成したイメージ localhost/payara-appimage でコンテナを起動します。

> mkdir deployments

> podman run -d --name myapp-payara --pod myapp-pod -v ${pwd}/deployments:/opt/payara41/deployments localhost/payara-appimage

${pwd}/deployments:/opt/payara41/deployments でマウントしているので、./deployments/ にwar ファイルが配備されていれば自動でデプロイされます。


デプロイの動作について少し補足しておきます。

デプロイは、$POSTBOOT_COMMANDS(post-boot-commands.asadmin) に対して deploy コマンドか書き込まれることで行われます。 これは、generate_deploy_commands.sh で以下のように行われています。

if [ x$1 != x ]
  then
    DEPLOY_OPTS="$*"
fi

echo '# deployments after boot' >> $POSTBOOT_COMMANDS
for deployment in "${DEPLOY_DIR}"/*
  do
    echo "deploy --force --enabled=true $DEPLOY_OPTS $deployment" >> $POSTBOOT_COMMANDS
done

$DEPLOY_DIR にある対象を、post-boot-commands.asadmin に deploy コマンドとして追加しているだけなので、post-boot-commands.asadmin を自作する場合は、マウントした任意ディレクトリからデプロイするよう直接指定することもできます。

deploy --force --enabled=true /opt/myapps/myapp.war


Postgres コンテナ

作成した Pod に postgres を追加します。

> podman run -d --name myapp-postgres --pod myapp-pod -e POSTGRES_PASSWORD=POSTGRES_PASS -e POSTGRES_USER=POSTGRES_USER -e POSTGRES_DB=POSTGRES_DB -v myapp_pgdata_volume:/var/lib/postgresql/data -v ${pwd}/initdb:/docker-entrypoint-initdb.d postgres

Postgres のデータは、myapp_pgdata_volume ボリュームに保存されます。 データベース起動時に initdb 配下に配備したスクリプトが実行されます。


起動確認

https://localhost:4848/ にアクセスして管理コンソールにログインします。 Payara イメージでは、ユーザ/パスは admin/admin になっています。

JDBC設定などが正しく作成されていることを Ping により確認しておくと良いでしょう。

/deployments/ に war を配備すればオートデプロイされ、アプリケーションが利用可能になります。

> cp .myapp.war ./deployments/myapp.war

Kubernetes の YAML ファイルは以下のように作成できます。

> podman generate kube myapp-pod > myapp-pod.yaml

作成した pod の停止と削除は以下のように行うことができます。

> podman pod stop myapp-pod
> podman pod rm myapp-pod

DB のデータ削除する場合は volume 削除します。

podman volume rm myapp_pgdata_volume


K8s の YAML からのPod起動

次回からは、Kubernetes の YAML ファイルにより起動停止は以下のように行うことができます。

> podman machine start
> podman kube play myapp-pod.yml
> podman play kube --down myapp-pod.yml