Docker で動いている Keycloak の H2 データベースを Postgres に移行する
TL;DR
- Keycloak コンテナのエントリーポイントを一時的に
/bin/sh -c "while true; do sleep 10000; done"
に変える - コンテナ内のシェルで
kc.sh export
とkc.sh import
を実行する
本編
うっかり H2 データベースで本番運用してしまった Keycloak のデータベースを Postgres に切り替えたい。
そのためには kc.sh export
コマンドでレルムをエクスポートし、データベースを切り替えた上で kc.sh import
を実行する必要がある。しかし、これらのコマンドは Keycloak を停止しないと実行できないので、Docker で動かしている Keycloak でこの作業を行うには少し工夫が必要になる。
(同じような問題で困ってる人もいるっぽい)
参考までに、自分の環境では以下のような誤った docker-compose.yml で Keycloak を実行していた(ドメイン名と初期パスワードは実際は違う値)。
Postgres を使用するようにしていたはずが、設定する環境変数が間違っており、実際には H2 データベースが利用されていた[1]。
volumes:
postgres_data:
services:
postgres:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
restart: unless-stopped
keycloak:
image: quay.io/keycloak/keycloak:20.0
entrypoint: /opt/keycloak/bin/kc.sh start --auto-build
environment:
DB_VENDOR: POSTGRES
DB_ADDR: postgres
DB_DATABASE: keycloak
DB_USER: keycloak
DB_SCHEMA: public
DB_PASSWORD: password
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: changeme
KC_HOSTNAME: "kc.example.com"
KC_HOSTNAME_ADMIN: "kcadm.example.com"
KC_PROXY: "edge"
ports:
- 8080:8080
depends_on:
- postgres
restart: unless-stopped
-
しかも H2 データベースのディレクトリは永続化されていないので、
docker compose down
でデータが消える仕様になっていた… (とはいえ、docker ホストマシン自体のバックアップはあるので完全にデータを失うことはない) ↩︎
作業メモ
これは手順書ではなく自分が行った作業の記録なので、参考にする場合は十分に注意を払うこと。(できるだけ環境依存の手順を書かないようにはしていますが。)
エクスポート
コンテナを止めて、H2 データベースのデータをホストにコピーした。
# docker stop keycloak_keycloak_1
# docker cp keycloak_keycloak_1:/opt/keycloak/data/h2 /root/h2
# chmod 777 /root/h2
# chmod 666 /root/h2/*
docker-compose.yml を以下のように書き換えた:
15c15,19
< entrypoint: /opt/keycloak/bin/kc.sh start --auto-build
---
> volumes:
> - /root/h2:/opt/keycloak/data/h2
> # entrypoint: /opt/keycloak/bin/kc.sh start --auto-build
> # dummy entrypoint to prevent keycloak from starting
> entrypoint: /bin/sh -c "while true; do sleep 10000; done"
これで、H2 データベースの永続化ができた。さらに、エントリーポイントを sleep
コマンドで上書きすることで、コンテナの起動時に Keycloak が開始されるのを防ぐようにした。
コンテナを作り直した。
(host)# docker compose down
(host)# docker compose up -d
レルムをエクスポートした。
(host)# docker exec -it keycloak_keycloak_1 bash
(keycloak)# cd /opt/keycloak/
(keycloak)# bin/kc.sh export --file kc_export.json
(keycloak)# exit
(host)# docker cp keycloak_keycloak_1:/opt/keycloak/kc_export.json /root/kc_export.json
インポート
docker-compose.yml を以下のように書き換えた:
16c16
< - /root/h2:/opt/keycloak/data/h2
---
> - /root/kc_export.json:/opt/keycloak/kc_export.json:ro
21,26c21,24
< DB_VENDOR: POSTGRES
< DB_ADDR: postgres
< DB_DATABASE: keycloak
< DB_USER: keycloak
< DB_SCHEMA: public
< DB_PASSWORD: password
---
> KC_DB: postgres
> KC_DB_URL: jdbc:postgresql://postgres/keycloak
> KC_DB_USERNAME: keycloak
> KC_DB_PASSWORD: password
ボリュームを書き換えて、エクスポートしたレルムのファイル kc_export.json
をコンテナ内に読み込み専用でマウントした。また、データベースの指定を正しい環境変数に書き換え、データの格納先が Postgres になるようにした。
コンテナを作り直した。
(host)# docker compose down
(host)# docker compose up -d
レルムをインポートした。
(host)# docker exec -it keycloak_keycloak_1 bash
(keycloak)# cd /opt/keycloak/
(keycloak)# bin/kc.sh build # 環境変数で指定した設定を反映するのに必要
(keycloak)# bin/kc.sh import --file kc_export.json
(keycloak)# exit
動作確認
docker-compose.yml を以下のように書き換えた:
15,19c15
< volumes:
< - /root/kc_export.json:/opt/keycloak/kc_export.json:ro
< # entrypoint: /opt/keycloak/bin/kc.sh start --auto-build
< # dummy entrypoint to prevent keycloak from starting
< entrypoint: /bin/sh -c "while true; do sleep 10000; done"
---
> entrypoint: /opt/keycloak/bin/kc.sh start --auto-build
kc_export.json
のマウントはもう不要なので削除した。また、ダミーのエントリーポイントを削除し、元のエントリーポイントに戻した。これで通常通り Keycloak が起動するようになる。
コンテナを作り直した。
(host)# docker compose down
(host)# docker compose up -d
ブラウザで Keycloak の管理画面や Keycloak で認証するサービスにアクセスできることが確認できた。