過去、Windows版のDockerで、PostgreSQLを動かして使用していました。
データの保存先にローカルボリュームをマウントしていたのですが。WSL対応機能の追加や、ファイルシステムの差異(ext4とNTFS)から、いつの間にか、データがうまく保存されなくなってしまいました。
近年、Podman Ver.4.3がリリースされて、Windowsのコマンドラインからポッドの起動やデータのバックアップができるようになりました。
過去にDockerで動かしていたコンテナを、Podmanにマイグレーションする手順を記録しておこうと思います。
目次
Dockerコンテナ側でデータベースをバックアップ
Dockerを使い始めた頃は、-vオプションでコンテナにローカルボリュームをマウントしないと、データが永続化されず。コンテナを終了すると、データが消えてしまいました。
この記事の頃だと思います。
私の環境ではdockerが動かないため、今の状況はわかりませんが、過去に次の手順でバックアップを進めました。
データディレクトリは直接ローカルマウントせずに
コンテナを移行するため、データベースをバックアップする必要があります。
先程申し上げたように、PostgreSQLのデータディレクトリ
/var/lib/postgresql
をローカルボリュームをマウントする方法は、ファイルシステムの差異から行いません。
理由は、ファイルやディレクトリの所有者情報や、各種権限(読み込み・書き込み等)が消失してしまうためです。
よって、データベースをダンプする方法で、バックアップしたいと思います。
Docker側のコンテナでデータベースの内容をダンプ
上述の記事の中ではコメント行になっていますが
# - ./pgadmin:/var/lib/pgadmin/storage
データベースのバックアップのため、pgadminコンテナに/pgadminフォルダをマウントしました。
消失に備えて、pgadminでデータベースをダンプし、/var/lib/pgadmin/storageに保存しました。
こちらのファイルは、データベースのディレクトリ構造そのものではないため、所有者や権限が消えても問題ありません。
更新日時は2019年6月ですか。3年半くらい寝かせてしまいましたが。こちらをPodmanで動かしたコンテナにリストア・・・できるのでしょうか?PostgreSQLのバージョンもずいぶん上がっていると思います。
Podmanでアプリケーション用のポッドを作成
こちらの記事と被りますが。
ポッドを作成し、PostgreSQLと管理用のadminerのコンテナを実行(run)したいと思います。
ロケールを日本語化するため、イメージを作成していますが。イメージの作成は大変でした。フリーズしたように見えて、20分ほど待っていると進む、という状態でした。※22.11.5現在
ちなみに、日本語化する必要がなければ、イメージの作成は不要です。普通に公式イメージの名前で、コンテナを起動すればOKかと思います。
日本語ロケールのPostgreSQLイメージ作成
ポッドの運用ディレクトリを作成し、その中に「Containerfile_pgsql.txt」を作成します。
rem ポッドの運用フォルダを作成
mkdir sv1
cd sv1
rem PostgreSQL用のcontainerfile作成
notepad Containerfile_pgsql.txt
次の内容になります。
FROM docker.io/postgres:latest
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
podman.exeコマンドでイメージをビルドします。名称はpostgres_jaにしてみました。
ビルドに20分くらいかかる場合がありました。フリーズしたの?と思いましたが、ずっと待っていたら進みました・・・
rem 日本語版PostgreSQLイメージ作成
podman pull docker.io/postgres:latest
podman image build -f Containerfile_pgsql.txt -t postgres_ja
ビルドが完了し、イメージが保存されました。
ポッドはアプリケーション名で作成
ポッドの名前ですが、これはアプリケーション名が良さそうです。
ここではsv1という名称にしました。(私がDocker時代に動かしていたアプリ名
公開ポート番号8080は、adminer用です。今後、コンテナを増やす時に公開ポート番号も増える形になります。
rem 公開ポート用オプションの覚書
rem --publish, -p=[[ip:][hostPort]:]containerPort[/protocol]
ポッドの中でコンテナを2つ実行します。PostgreSQLデータベース本体と、標準の管理ツールであるadminerの2つのコンテナです。
rem 作りたいアプリケーション名でポッド作成 コンテナはデータベースとadminer
podman pod create --name sv1-pod -p=8080:8080/tcp
rem 日本語ロケールのPostgreSQLコンテナ起動
podman run ^
--restart always ^
--pod sv1-pod ^
--name sv1-pgsql ^
-e POSTGRES_PASSWORD=Passw0rd' ^
-d postgres_ja
rem Adminerコンテナ起動
podman run ^
--restart always ^
--pod sv1-pod ^
--name sv1-adminer ^
-d docker.io/adminer:latest
Podmanでは匿名ボリュームでデータベースを永続化
画面写真内ではポッドの名称が違いますが。
今後、いろいろなコンテナを追加する段階で、何度かポッドを作り直す場合があると思います。
構築の段階では、名前はあまり問題ではなく、ポッドを作成するためのスクリプトまたはyamlファイルが大切になります。
また大切なデータは匿名ボリュームに入るようです。実際に確認してみました。
/var/lib/postgresql/dataディレクトリが、2b3f・・・で始まる名前の匿名ボリュームにマウントされています。※22.11.5 Podman.exe Ver.4.3で確認
つまり、ポッド内のPostgreSQLコンテナにリストアしたデータベース(テーブルやビューやストアドプロシージャ等)は、結果的にこのボリュームに格納される、と言えると思います。
ボリュームが存在する間は、データは消えません。コンテナの設定を調整するレベルでは大丈夫のようです。
コンテナやポッドを削除すると、ボリュームが消える場合がありますので、注意が必要です。その場合、バックアップしておいたデータベースを再度リストアする必要があります。
ボリュームが残る場合と、消える場合のパターンがいまいち理解できていないのですが・・・・(大丈夫か
PostgreSQLの管理ツールを使ったリストア
Adminer
PostgreSQLと一緒に起動したadminerを使って、データベースをリストアできないか調べてみましょう。
WebブラウザでadminerのURLにアクセスします。
http://localhost:8080/
ログインに必要な情報です。
- データベース種類:PostgreSQL
- サーバ:127.0.0.1
- ユーザ名:postgres
- パスワード: -e オプジョンで指定した値 ここではPassw0rd
Adminerのインポートメニューに移動しました。
「ファイルをアップロード」画面から、SQLまたは圧縮したSQL.gzファイルを使用してインポートができそうです。
しかし、<128MBという文字が見えます。おそらくアップロード可能なファイルサイズに制限があるようです。
今回、2.4GB程度のファイルをインポートしたいため、標準設定のAdminerのアップロード機能では難しいようです
「サーバーから実行」欄を見ると、adminer.sql[.gz」ファイルを実行、というボタンが見えます。
こちらは、Adminerのコンテナにアップロードしたsqlファイルを実行する機能かと思います。
Adminerコンテナのどこに、SQLファイルを置けば良いのでしょう?
ざっと見た感じ、/var/www/htmlがカレントディレクトリのようです。
adminer.sqlの置き場所を検証
試しに、/var/www/html/adminer.sqlファイルを作成してみました。
ファイルの内容は空ですが。
「ファイルを実行」ボタンを押したところ。
「実行するコマンドがありません」と表示されましたので、置き場所は合っていると思います。
つまり、Adminerの「サーバーから実行」機能を使用したい場合は、Adminerコンテナの/var/www/htmlディレクトリに、adminer.sqlまたはadminer.sql.gzファイルを置けば良い、ということになります。
podman cpコマンドで、コンテナにファイルをコピーしようと思ったのですが。
どうも期待した動作をしてくれませんでした。詳細は後述します。
Adminerのコンテナにローカルフォルダをマウント
やりたいことは、adminer.sqlファイルを、Adminerコンテナの/var/www/htmlディレクトリにコピーしたい、という事になります。
そのためには、Adminerコンテナをどう起動するか、が問題になります。
いちどAdminerコンテナを終了して。
ローカルフォルダを/backupディレクトリにマウントした形で、Adminerコンテナを起動する作戦にしてみたいと思います。
まずは、Windows上でadminer.sqlファイルを作成しておきます。
Adminerコンテナを起動する際、/backupディレクトリにWindows側のカレントディレクトリをマウントするオプションを追加しました。-v 行になります。
rem Adminerコンテナ削除
podman container stop sv1-adminer
podman container rm sv1-adminer
rem Adminerコンテナ起動
podman run -d ^
--restart always ^
--pod sv1-pod ^
--name sv1-adminer ^
-v .:/backup ^
docker.io/adminer:latest
コンテナ内の/backupディレクトリは、Windows側のsv1ディレクトリがマウントされているはずです。
確認しつつ、adminer.sqlファイルをコピーします。
rem /backupディレクトリ確認
podman exec sv1-adminer ls -al /backup
rem カレントディレクトリ確認
podman exec sv1-adminer ls
rem /backup/adminer.sqlをカレントディレクトリにコピー
podman exec sv1-adminer cp /backup/adminer.sql .
2.5Gバイトのadminer.sqlファイルが、Adminerコンテナの/var/www/htmlディレクトリにコピーされたようです。
Adminerコンテナ内のadminer.sqlをインポート
あとは、「サーバーから実行」の「ファイルを実行」ボタンをクリックして、adminer.sqlファイルをインポートする流れですが。
すんなりインポートできる場合もあれば。
PostgreSQLデータベース内の調整が必要になる場合もあるようです。
上図のエラー、adminロールが無いため、インポート前に作る必要があるかと思います。
まあ3年くらい動かせて無くて寝かせておりましたので。バージョン違いの影響かなと思います。
PgAdmin4コンテナは動作が不安定な状況※22.11.5現在
管理ツールのPgAdmin4コンテナの起動手順も記載しておきますが。
podman container stop sv1-adminer
podman container rm sv1-adminer
rem PgAdmin4コンテナ起動
podman run ^
--restart always ^
--pod sv1-pod ^
--name sv1-pgadmin ^
-e 'PGADMIN_DEFAULT_EMAIL=<ユーザ名を入力>' ^
-e 'PGADMIN_DEFAULT_PASSWORD=Passw0rd' ^
-v .:/backup ^
-d docker.io/dpage/pgadmin4
どうも私のおうち環境では安定動作しません。
PgAdminコンテナは、TCPポート番号80番と443番を使用しています。
試しておらず、推測で恐縮ですが。1024より小さいポート番号で動作することから、Podman Machineをルートフルモードで起動する必要があるかもしれません。
今のところ、ルートレス環境での構築を目指しているため、ここでは試しません。
docker.ioのイメージではなく、quay.ioのイメージのほうがPodmanに向いているのでしょうか?(憶測
こちらの記事のコマンドで、quay.ioにて公開されているpgadmin4を探すことが可能です。スターが何個あるか確認し、人気のイメージを探すことができます。
ちなみに、quayは「波止場」や「埠頭」という意味のようです。(余計なdockerトリビア
podman cpコマンドは動作せず?
podman cpコマンドで、コンテナにファイルをコピーしようと思ったのですが。
どうも期待した動作をしてくれません。
原因ですが、WSLとpodman machieとの間にある、ユーザ権限の問題のような感じがします。
関連情報はこのあたりです。
ステータスは「Open」になっており、解決していない模様です。
Machineをユーザ指定して動かせば良い、という情報もありますが、嵌りそうです。
podman cpコマンドの利用は保留して、別の方法を探しましょう。
データベースコンテナでコマンドを使うリストア手順
データベースコンテナで作業用ディレクトリをマウント
そういえば、バックアップしたSQLファイルは、pg_dumpコマンドで出力したことを思い出しました。
これは、データベースコンテで、pg_restoreコマンドでリストアする必要があります。
先程と同様に、データベースコンテナからsqlファイルにアクセスできるように、コンテナを-vオプション付きで作り直すスクリプトを記録しておきます。
rem ポッド削除
podman pod stop sv1-pod
podman pod rm sv1-pod
rem ポッド再作成
podman pod create --name sv1-pod -p=8080:8080/tcp
rem 日本語ロケールのPostgreSQLコンテナ起動 作業用ディレクトリ/backupをマウント
podman run ^
--restart always ^
--pod sv1-pod ^
--name sv1-pgsql ^
-e POSTGRES_PASSWORD=Passw0rd' ^
-v .:/backup ^
-d postgres_ja
rem Adminerコンテナ起動 作業用ディレクトリ/backupをマウント
podman run ^
--restart always ^
--pod sv1-pod ^
--name sv1-adminer ^
-v .:/backup ^
-d docker.io/adminer:latest
データベースコンテナでシェルを動かすコマンドは下記になります。
podman exec -it sv1-pgsql bash
こちらでpsql等の各種コマンドを使用して、データベースの設定やリストアを行う事が可能です。
コマンドやマウントした/backupディレクトリを使用して、昔Dockerで作ったコンテナの内容を、新しいポッド環境に再構築してゆこうと思います。
PostgreSQLデータベースコンテナ上でクエリを扱う覚書
完全に自分用コピペ用で恐縮ですが。(つまり詳細を省いてごめんなさいという意味
rem データベースコンテナでbash起動
podman exec -it sv1-pgsql bash
bash上でPostgreSQLのコマンドを使って何かしたい場合。
この記事のコンテナの起動方法では、ユーザ名はpostgresのようです。
# bash起動時のロケール
# LANG=ja_JP.UTF-8
# 和訳が不要なら、ロケールを変えておく
# LANG=C
# psqlコマンドで接続
psql -U postgres
クエリの入力モードにて。show databasesは違いました・・・PostgreSQLは\lでした。
こちらのクエリはPostgreSQL用になります。
SELECT文等のSQLクエリも使えます。この記事ではデータベース一覧等のコマンドをクエリの一部として扱っております。
-- データベース一覧はバックスラッシュと小文字エル
\l
-- 終了
\q
-- データベース作成
CREATE DATABASE sv1 ENCODING = 'UTF8' LC_COLLATE = 'ja_JP.UTF-8' LC_CTYPE = 'ja_JP.UTF-8';
-- データベース削除
DROP DATABASE sv1;
-- データベース切り替え
\c sv1
-- ロール一覧
\du
-- バージョン違いの影響?ロールも作って置きましょう
CREATE ROLE admin WITH CREATEDB CREATEROLE;
DROP ROLE admin;
日本語ロケールで起動すると、説明がわかりやすくなる一方、列名が和訳されて、SELECT文が作れなくなる罠が。
そうでしたデータベースをリストアしなきゃでした。
# pg_backupでバックアップした場合
pg_restore -U postgres -d sv1 -c -C < /backup/adminer.sql
# SQLファイルにダンプした場合
psql -U postgres -d sv1 < /backup/adminer.sql
adminロールがないエラーは、PostgreSQLのバージョンが変わった影響でしょうか。データベースをリカバリする前に、クエリを実行して作成する必要がありました。
ロール作成後、正常にリカバリすることができました。テーブル、ビュー、それとルーチンも復元できているように見えます。
これでPodmanのポッドで、PostgreSQLを使ったアプリを構築できそうです。
参考:データベースのボリュームバックアップ
最後に、リストアが完了し、運用を開始したsv1-pgsqlコンテナのボリュームをバックアップするコマンドを記録しておきます。
しかし実用ではありません。
rem sv1-pgsqlコンテナのボリュームバックアップ
podman container stop sv1-pgsql
podman run --rm --volumes-from sv1-pgsql -v .:/backup fedora tar zcvf /backup/pgsql.tar.gz /var/lib/postgresql/data
podman container start sv1-pgsql
参考:データベースコンテナのリストアコマンド
rem sv1-pgsqlコンテナのボリュームリストア
podman container stop sv1-pgsql
podman run --rm --volumes-from sv1-pgsql -v .:/backup fedora bash -c "cd / && tar zxvf /backup/pgsql.tar.gz"
podman container start sv1-pgsql
こちらはデータベースの稼働状態が格納されているため、バックアップ・リストアしても元のデータベースの状態が得られるとは限りません。
データベースのバックアップは、基本的にダンプを行う必要があると思います。
以上で、PodmanのPostgreSQLコンテナに、Docker時代に作成したPostgreSQLバックアップをインポートして、ポッド内で動かすことができました。
ポッドやコンテナの起動は簡単にできるのですが。
現状、WSLのPodman環境では、起動したコンテナに何か外からファイルを受け渡すのは難しいことがわかりました。
podman cpコマンドが動けば良いのですが、今はうまく動かない感じでした。
原因はWSLの実装上の問題のようです。根が深いため、すぐに何か対応できる状況では無さそうです。
代替案として、管理ツールであるAdminerコンテナやPostgreSQLのDBコンテナの/backupディレクトリに、Windowsのフォルダをマウントしてファイルをコピーすることができました。
追々、PostgreSQL以外の、昔Dockerで動かしていた別のコンテナもマイグレーションしたいと思います。
それでは本日も御機嫌よう!