最近、 Docker
とDocker-compose
の使用について多くのことが書かれています。たとえば、まだ慣れていない場合は、Habréに関する最近の記事をお勧めします。 これは本当に便利ですが、特にansibleと組み合わせて使用します。 そして、私はどこでもそれを使用しています。 CI
開発から自動統合テストまで。 彼らはテストでの使用についても書いた 。 とても快適です。 ただし、ローカル開発の場合、「実稼働時のような」データ処理や「実稼働に近いボリュームでの」パフォーマンステストの場合、「実稼働時のような」データベースを含むイメージを手元に置きたいと思います。
したがって、すべての開発者が1つのチームでプロジェクトを開始できるように、プロジェクトの作業を開始する必要があります。次に例を示します。
./gradlew dockerRun
必要なすべての関連コンテナを使用して、アプリケーションがすぐに起動しますか? そして主なことは、そこに画像やデモデータをエクスポートまたはインポートする時間を無駄にすることなく、すぐに作業を開始できるほとんどの開発およびバグ修正ケース、標準ユーザー、ほとんどの作業サービスのデータがすでに含まれていることです!
素晴らしいボーナスとして、数ギガバイトのデータベースと、数秒以内に元の(または他のコミット)状態にロールバックする機能があるのは素晴らしいことではありませんか?
もちろん、データを含むそのようなイメージのDockerfile
作成と、このプロセスの落とし穴のいくつかについて説明します。
ここが焦点です。 私たちのアプリケーションでは、 Postgres
を積極的に使用しているので、ストーリーと例はコンテナに関するものですが、これは例にのみ適用され、プレゼンテーションの本質は他のリレーショナルまたはファッショナブルなNoSQL
データベースに適用されます。
何が欲しい?
最初に、問題をより詳細に定義しましょう。 アプリケーションで作業するすべての人が使用できるデータを含む画像を準備しています:
- 一部のデータには難読化が必要です(たとえば、メールボックスやユーザーの個人データ)-つまり、ダンプを復元するだけではなく、処理する必要があります
- ただし、アセンブリメカニズムをさらに変更することなく、 SQLのビルド用に提供されたスクリプトをロールアップするための一般的なメカニズムが必要です。 たとえば、これを使用して、サンプリング(データ量の削減)およびイメージのサイズの削減を行うことができます。
- 起動時にオプションを渡さずに、また複雑な正規表現で毎回設定を変更せずに、画像に追加の設定を便利に含めたい
- 起動方法に関する巨大なマニュアルを書かないように、いくつかの設定拡張をイメージに含めたい(起動時に起動するために必要なオプションを渡す)
- 大量のデータがあるため、最適化設定を有効にして生産性を向上させたい
- 一般に、多くの設定では、 ALTER SYSTEMコマンドを実行することにより、標準の拡張パスを通じてこれを行うことができます。 ただし、これは構成ファイルまたは起動オプションでのみ定義を必要としない設定のみです 。
- データは開発者と
CI
同じです
降りる
Dockerfile
説明しませんが、既にこれを理解していることを望みます。 アイデアを得たい人は、記事 、まあ、または公式ドキュメントを参照してください 。
公式のdocker postgresイメージにはすでにいくつかの拡張ポイントがあります。
-
POSTGRES_*
変数 - そして、起動時に実行されるshスクリプトまたは
sql
ファイルを置くことができるイメージ/docker-entrypoint-initdb.d
内のディレクトリ。 これは、追加のユーザーまたはデータベースの作成、権限の設定、拡張機能の初期化を行う場合に非常に便利です。
ただし、私たちの目的では、これだけでは十分ではありません。
- いくつかのデータを含めることはできません。最初にそれらを上書きします。
- まず、これによりデータベースのサイズが膨大になる可能性があります(一部のログまたは履歴を削除したい)
- 第二に、ユーザーは
entrypoint
オーバーライドすることで画像を開始し、見るべきではないプライベートデータを見ることができます
- さらに、--
--max_prepared_transactions=110
ように、起動時にコマンドラインでほとんどすべてのパラメーターを渡すことができますが、それらを簡単にイメージに入れて標準にすることはできません
- そのため、たとえば、テスト用のイメージを構築しており、迅速なロールバックを行っているため、信頼性よりもパフォーマンスを最適化するための積極的な設定を含める必要があります(
fsync
を完全に無効にするなど)
- そのため、たとえば、テスト用のイメージを構築しており、迅速なロールバックを行っているため、信頼性よりもパフォーマンスを最適化するための積極的な設定を含める必要があります(
おそらくすぐにファイルのプロトタイプを表示します(一部の重要でない部分のみを切り取って小さくします。たとえば、 Deb
や公式リポジトリにはないため、 RPM
からDebian
pg_hint_plan
れるpg_hint_plan
拡張を含めるには多くのスペースが必要です)。
FROM postgres:9.6 MAINTAINER Pavel Alexeev # Do NOT use /var/lib/postgresql/data/ because its declared as volume in base image and can't be undeclared but we want persist data in image ENV PGDATA /var/lib/pgsql/data/ ENV pgsql 'psql -U postgres -nxq -v ON_ERROR_STOP=on --dbname somedb' ENV DB_DUMP_URL 'ftp://user:password@ftp.somehost.com/desired_db_backup/somedb_dump-2017-02-21-16_55_01.sql.gz' COPY docker-entrypoint-initdb.d/* /docker-entrypoint-initdb.d/ COPY init.sql/* /init.sql/ # Later in RUN we hack config to include conf.d parts. COPY postgres.conf.d/* /etc/postgres/conf.d/ # Unfortunately Debian /bin/sh is dash shell instead of bash (https://wiki.ubuntu.com/DashAsBinSh) and some handy options like pipefaile is unavailable # Separate RUN to next will be in bash instead of dash. Change /bin/sh symlink as it is hardcoded https://github.com/docker/docker/issues/8100 RUN ln -sb /bin/bash /bin/sh RUN set -euo pipefail \ && echo '1) Install required packages' `# https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#apt-get` \ && apt-get update \ && apt-get install -y \ curl \ postgresql-plperl-9.6 \ && echo '3) Run postgres DB internally for init cluster:' `# Example how to run instance of service: http://stackoverflow.com/questions/25920029/setting-up-mysql-and-importing-dump-within-dockerfile`\ && bash -c '/docker-entrypoint.sh postgres --autovacuum=off &' \ && sleep 10 \ && echo '4.1) Configure postgres: use conf.d directory:' \ && sed -i "s@#include_dir = 'conf.d'@include_dir = '/etc/postgres/conf.d/'@" "$PGDATA/postgresql.conf" \ && echo '4.2) Configure postgres: Do NOT chown and chmod each time on start PGDATA directory (speedup on start especially on Windows):' \ && sed -i 's@chmod 700 "$PGDATA"@#chmod 700 "$PGDATA"@g;s@chown -R postgres "$PGDATA"@#chown -R postgres "$PGDATA"@g' /docker-entrypoint.sh \ && echo '4.3) RERun postgres DB for work in new configuration:'\ && gosu postgres pg_ctl -D "$PGDATA" -m fast -w stop \ && sleep 10 \ && bash -c '/docker-entrypoint.sh postgres --autovacuum=off --max_wal_size=3GB &' \ && sleep 10 \ && echo '5) Populate DB data: Restore DB backup:' \ && time curl "$DB_DUMP_URL" \ | gzip --decompress \ | grep -Pv '^((DROP|CREATE|ALTER) DATABASE|\\connect)' \ | $pgsql \ && echo '6) Execute build-time sql scripts:' \ && for f in /init.sql/*; do echo "Process [$f]"; $pgsql -f "$f"; rm -f "$f"; done \ && echo '7) Update DB to current migrations state:' \ && time java -jar target/db-updater-*.jar -f flyway.url=jdbc:postgresql://localhost:5432/somedb -f flyway.user=postgres -f flyway.password=postgres \ && echo '8) Vacuum full and analyze (no reindex need then):' \ && time vacuumdb -U postgres --full --all --analyze --freeze \ && echo '9) Stop postgres:' \ && gosu postgres pg_ctl -D "$PGDATA" -m fast -w stop \ && sleep 10 \ && echo '10) Cleanup pg_xlog required to do not include it in image!:' `# Command inspired by http://www.hivelogik.com/blog/?p=513` \ && gosu postgres pg_resetxlog -o $( LANG=C pg_controldata $PGDATA | grep -oP '(?<=NextOID:\s{10})\d+' ) -x $( LANG=C pg_controldata $PGDATA | grep -oP '(?<=NextXID:\s{10}0[/:])\d+' ) -f $PGDATA \ && echo '11(pair to 1)) Apt clean:' \ && apt-get autoremove -y \ curl \ && rm -rf /var/lib/apt/lists/*
ご覧のとおり、ファイルにコメントを直接追加しようとしました。多分それらは完全なものではないかもしれませんが、それでもいくつかの点について詳しく見ていきましょう。
注目に値する
-
ENV PGDATA /var/lib/pgsql/data/
をオーバーライドします。 これが重要なポイントです。 なぜなら ビルド中に入力されたデータをイメージに含めたい場合、 ボリュームとして定義された標準の場所に配置しないでください。 -
DB_DUMP_URL
変数DB_DUMP_URL
、後続の編集の便宜上、単に定義されています。 必要に応じて、ビルド中に外部から転送できます。 - 次に、ビルドプロセス中に
Postgres
直接起動しますbash -c '/docker-entrypoint.sh postgres --autovacuum=off &'
いくつかの簡単な設定を実行します。
-
sed
を使用して、メインのpostgres.conf
include_dir
sed
postgres.conf
include_dir
。 このような操作を設定で最小限に抑えるためにこれが必要です。そうしないと、メンテナンスが非常に困難になりますが、設定の拡張性に制限はありません。COPY postgres.conf.d/* /etc/postgres/conf.d/
ディレクティブCOPY postgres.conf.d/* /etc/postgres/conf.d/
を使用して、ビルドに固有の構成要素を配置することに注意してください。
- このメカニズムは 、基本的なイメージに含めるための問題としてコミュニティに提案されましたが、リクエストが閉じられている間に、すでに私がやったように質問を提起しましたが(誰かと記事を書く機会に役立つかもしれないことを示唆しています)再発見の希望を失いません。
- また、メインファイルから
chown
およびchmod
命令を削除(コメント)します。 データベースが初期化されると、ファイルには既にイメージ内の適切なユーザーと権限がありますが、経験上、WindowsのDockerバージョンでは、何らかの理由でこの操作に数十分かかる非常に長い時間がかかることが判明しました。 - また、最初に
Postgres
実行する必要があることに注意してください。 そうしないと、クラスターを初期化するためのディレクトリが空ではないというエラーが開始時に表示されます! - 次に、
Postgres
を再起動して、追加して読み取り用に設定した構成を再読み取りします。 厳密に言えば、この手順はまったく必要ありません。 ただし、デフォルトではshared_buffers = 128MB
ような非常に控えめなメモリ設定があり、重要なメモリ設定は何時間もドラッグし続けます。
-
- 次のステップでは、すべてが明確になっているはずです-ダンプを復元するだけです。 ただし、その背後にある
/init.sql/*
、イメージの作成中にこのディレクトリからすべてのSQL
スクリプト/init.sql/*
適用しSQL
(標準の拡張スクリプトとは異なります)。 ここで、データの難読化、サンプリング、クリーニング、テストユーザーの追加などを行います。
- すべてのスクリプトをこのように実行することで、次回ビルド手順に触れることなく、データを使用して何か他のことを行うファイルをこのディレクトリに追加するだけですみます!
- イメージを縮小し、さらに効率を上げるために、分析を使用して完全なバキュームを実行します 。
- これにより、 auto-vacuumを無効(
--autovacuum=off
)にしてPostgres
を実行し、インポートを高速化できることに注意してください。 - また、イメージを縮小する目的で、
pg_resetxlog
を使用してリセットし、蓄積されたWALを有効にしません。 そして、起動時に--max_wal_size=3GB
を使用して、ファイルサイズを増やし、再度ローテーションしないようにします。 - ベストプラクティスのガイドラインに従って、APTキャッシュのクリアが標準です。
- これにより、 auto-vacuumを無効(
完成したイメージは、タグを割り当ててリポジトリにプッシュするだけです。 ほとんどの場合、もちろん、何らかのパブリックデータサンプルで作業していない場合、これはプライベートリポジトリになります。
これにより、誰かがデータを使ったテスト画像の作成を準備するプロセスを少なくとも少し簡単にするのに役立てば非常に嬉しいです。