はじめに
前回の投稿、
[備忘録] [初心者] Docker Compose / Rails(公式doc.)について自分用補足#1 (Dockerfile, entrypoint.sh)
に続き、Docker + Raislの公式チュートリアルの内容を丁寧に追って理解を試みる取り組みのアウトプットです。
あくまで学習過程の私的なアウトプットなので、信頼性の高い情報は、各リンク先を参照していただければと思います。
本編
クィックスタート: Compose と Rails | Docker ドキュメント
上記のチュートリアルで扱われる、docker-compose.yml
の理解のためのメモです。
一部、深掘りのために、PostgreSQL
関連や、公式イメージのDockerfile
の内容も扱います。
docker-compose.yml
の概観理解に役立ったリンク例
- Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
- Docker Compose の概要 | Docker ドキュメント
- さわって理解するDocker入門 第4回 | オブジェクトの広場
- Compose file version3のリファレンス - Qiita
docker-compose.yml
version: '3'
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
version:
使用するDocker Composeのバージョン
services:
#サービス設定リファレンス | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
アプリケーションを構成する各サービスのコンテナを設定します。
今回扱うチュートリアルでは、2つのサービスdb
, web
によってサービス全体を構成しています。
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
db:
任意のサービスの名称として"db"が付けられています。
公式のサンプルでは、下位にimage
, volumes
, environment
の設定項目が続きます。
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
image:
image: postgres
#image | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
コンテナを起動させるイメージの設定とあります。
今回は、PostgreSQLのDocker公式イメージを用います。
デフォルトのコンテナOSは、Debian:stretch、オプションでAlpineも選択できるようです。
volumes:
volumes:
- ./tmp/db:/var/lib/postgresql/data
#volumes | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
マウントホストパスや名前つきボリュームを、サービスに対するサブオプションとして指定します。
まず、マウント
という言葉もピンときていなかったのですが、下記の質疑がとても分かりやすかったです。
filesystems - understanding "mount" as a concept in the OS - Unix & Linux Stack Exchange
What is a mount point in Linux/Unix? - The Linux Juggernaut
特に、耕地の管理とディスクドライブの管理とのアナロジーを示した例え話はとても面白いと感じました。
各パーティション内のデータにアクセスするための"門"を設けることがマウントであるということに納得しました。
また、ボリュームの概念が分かっていないので調べました。
ボリュームの利用 | Docker ドキュメント
ボリュームとは、Docker コンテナーにおいて生成され利用されるデータを、永続的に保持する目的で利用される仕組みです。
このように、システムを終了してもデータが消失しないような仕組みを設けることを永続化と呼ぶようです。(不揮発性メモリへの保存、回復可能にしておくなど)
永続性 - Wikipedia
What Is Persistent Data? - DZone Database
では、volumeに設定されている./tmp/db:/var/lib/postgresql/data
とはどういうディレクトリなのでしょうか。
ボリュームの利用 | Docker ドキュメントには、設定の書式として、[SOURCE:]TARGET[:MODE]
という書式が適用されることが説明されています。
この書式にあてはめると、下記表の対応となります。
書式 | 記述例 | 意味 |
---|---|---|
[SOURCE:] | ./tmp/db: | ホストのパスあるいはボリューム名 |
TARGET | /var/lib/postgresql/data | ボリュームがマウントされているコンテナのパス |
[:MODE] | none | 読み込み専用ro , 読み書き可能rw . デフォルトは後者 |
つまり、コンテナから見たとき、/var/lib/postgresql/data
の中身として、ホストOS上の./tmp/db
を見ている状態になります。
これはこういうものだと、割り切ってしまうのもひとつかもしれません。
ただ、もう少し自分の中で具体的根拠を伴った意味付けが欲しいと思いました。
/var/lib/postgresql/data
とは何か
このディレクトリについては、PostgreSQLのリファレンスに説明がありました。
データベースの物理的な格納 - PostgreSQL 8.0.4 文書
データベースクラスタで必要となる全てのデータは、クラスタのデータディレクトリ内に格納され、通常 PGDATA として参照されます。 (そのディレクトリを定義するために使用できる環境変数名です。) 通常の PGDATA の位置は /var/lib/pgsql/data です。
データベースクラスタはPostgreSQL独自の用語らしいです。
第18回 データベースクラスタ - OSS-DB道場
sql - What's a PostgreSQL "Cluster" and how do I create one? - Stack Overflow
PostgreSQLでは、1つのサーバインスタンス上に複数のデータベースを構成することができ、PostgreSQLで言う"クラスタ"とは、そうした1つ以上のデータベースの集合体を含む共有ディレクトリを管理する仕組みであると解釈しました。
そして、それらに関わるデータが格納される場所がPGDATA
の環境変数で参照され、その保存先が通常では/var/lib/pgsql/data
に指定してあると。
/var/lib/
という階層の意味 : ファイルシステム階層標準 (FHS)
他でもよく見る/var/lib
についても意味を把握しておこうと思いました。
LinuxやUnix系のOSのディレクトリの階層は、ファイルシステム階層標準によって定められていることを知りました。
Filesystem Hierarchy Standard - Wikipedia(JP)
Filesystem Hierarchy Standard(ファイルシステム・ヒエラルキー・スタンダード、FHS、ファイルシステム階層標準)は、Linuxを含むUNIX系オペレーティングシステムでの主なディレクトリとその内容を定めたものである。
2020-07現在の最新版はFHS 3.0で、下記リンクからHTMLやPDFなどの形式で閲覧することが出来ます。
/var
は、動的に変化する変数データファイルを格納するもので、、ネットワーク上で他のコンピュータと共有されないもの。
/var/lib
は、アプリケーションやシステムに関連する状態情報を保持。
FHSの解説では、アプリケーションは/var/lib
のサブディレクトリを使用しなければならない、とあるので、/var/lib/pgsql
はその規則に則ったPostgreSQL用のデータ格納先であることが伺えます。
PostgreSQLの公式イメージにおける/var/lib/postgresql/data
の扱い
PostgreSQLの公式DockerイメージのDockerfile
を見てみます。
下記の2行に/var/lib/postgresql/data
の記述を見つけました。(ディレクトリの生成も含めれば3行)
登場するDockerのENV
とVOLUME
の命令は、この親投稿では触れなかったものなので、調べてみます。
ENV PGDATA /var/lib/postgresql/data
#ENV | Dockerfile リファレンス | Docker ドキュメント
環境変数
<key>
に<value>
という値を設定します。
つまり環境変数PGDATA
に/var/lib/postgresql/data
を設定しています。
PostgreSQLの公式リファレンスでは、pgsql
というデフォルトのディレクトリ名が、Dockerの公式イメージでは postgresql
となっています。
VOLUME /var/lib/postgresql/data
#VOLUME | Dockerfile リファレンス | Docker ドキュメント
VOLUME 命令は指定された名前を使ってマウントポイントを生成します。 そして自ホストまたは他のコンテナーからマウントされたボリュームとして、そのマウントポイントを扱います。
荒い解釈ではありますが、/var/lib/postgresql/data
をめぐる流れとしては、下記のように整理できると思いました。
1. ホストOSのローカルに/var/lib/postgresql/data
を生成
(postgres/Dockerfile-debian.template#L21)
2. PostgreSQLがサービスのデータを参照するための環境変数PGDATA
に/var/lib/postgresql/data
を設定
(postgres/Dockerfile-debian.template#L181)
3. Composeの起動時にPostgreSQLのサービスが/var/lib/postgresql/data
をマウントできるようにマウントポイントを生成
(postgres/Dockerfile-debian.template#L184)
4. $ docker compose run ~
でコンテナを起動したらマウントポイントの/var/lib/postgresql/data
をマウントしてサービス側から使用できるようにする
(チュートリアルのdocker-compose.ymlのdb: volume:設定行)
environment:
environment:
POSTGRES_PASSWORD: password
#environment | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
環境変数を追加します。
web:
任意のサービスの名称として"db"が付けられています。
公式のサンプルでは、下位にbuild
, command
, volumes
, ports
, depends_on
の設定項目が続きます。
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
build:
build: .
#build | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
build の指定方法の 1 つは、ビルドコンテキストへのパスを表わす文字列を指定します
ビルドコンテキスト?
Docker Tips: All About the Build Context - Better Programming - Medium
The build context is the set of files located at the specified PATH or URL. Those files are sent to the Docker daemon during the build so it can use them in the filesystem of the image.
指定されたURLやPATHにあるファイル一式。これらのファイルはDockerのデーモンに送られビルド中にイメージのファイルシステムで使用できるようになる。
今回では、web
サービスのイメージでbuild
のPATHに.
を指定しているので、 /var
, /myapp
などの全ての階層とファイルがweb
サービスイメージのファイルシステムで使用できるようになっています。
command:
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
#command | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
コンテナ起動時にデフォルトで実行されるコマンド。
bash -c
bash(1): GNU Bourne-Again SHell - Linux man page
-c
は後に続く文字列をコマンドとして実行するので、bash -c "<command>"
はBashシェルでを実行する意味になります。
volumes:
volumes:
- .:/myapp
再掲:#volumes | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
ホストOS上のパスである.
を、コンテナ上の/myapp
へ専用のボリュームとしてマウントします。
ports:
ports:
- "3000:3000"
#ports | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
公開するポートをHOST:CONTAINER
で指定します。
depends_on:
depends_on:
- db
#depends_on | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
サービスの依存関係を指定します。複数ある場合は順番に起動。
ただ、依存サービスの「準備」状態を待たずに当サービスの起動を実行するため、ちゃんと依存関係にあるサービスの「準備」を待ちたいなら、別途コマンドにより待機させる工夫が必要です。
後書き
Docker + Raislの公式チュートリアルについては今回で一旦終了です。
DeepL頼みなことが多いですが、海外の記事やリファレンスを抵抗なく触れられるようになったことは、自身として少しは進歩しているのかなと感じます。
理解が荒い部分も多いので、このような調査とアウトプットを継続して、正しい理解に近づくように取り組んでいきます。
また、英語だと教育資料や初心者向けの教材なども簡単にヒットするので、様々な情報源から学びを得られるように独力で英文を読む能力も鍛えていきたいと思いました。
次は、CircleCIの設定ファイルについて学習します。