注意)この記事について
この記事は、私自身が作成したWebアプリについて自身で振り返り、理解を深めるためのものです。基本的には個人的な備忘録として執筆したものですので、ご了承ください。
作成したwebアプリ
備忘録 Docker#2
docker-compose.yml
version: '3'
services:
db:
container_name: postgresql_db
image: postgres:16
restart: always
environment:
TZ: Asia/Tokyo
POSTGRES_PASSWORD: password
volumes:
- postgresql_data:/var/lib/postgresql
ports:
- 5432:5432
healthcheck:
test: ["CMD-SHELL", "pg_isready -d myapp_development -U postgres"]
interval: 10s
timeout: 5s
retries: 5
web:
container_name: rails_app
build:
context: .
dockerfile: Dockerfile.prod
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
tty: true
stdin_open: true
volumes:
- .:/myapp
- bundle_data:/usr/local/bundle:cached
- node_modules:/myapp/node_modules
environment:
TZ: Asia/Tokyo
SELENIUM_DRIVER_URL: http://chrome:4444/wd/hub
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
chrome:
image: seleniarm/standalone-chromium:latest
ports:
- 4444:4444
redis:
image: "redis:7.0-alpine"
volumes:
- redis_volume:/data
command: redis-server --appendonly yes
ports:
- 6379:6379
volumes:
redis_volume:
bundle_data:
postgresql_data:
node_modules:
###解説
version: '3'
- Composeファイルのバージョンを指定している。バージョンによって使用できるオプションが異なる。
- なお、
docker-compose.yml
ファイルの拡張子はyml
,yaml
のどちらも利用できる。
services
・作成するサービスを定義する。サービスとはコンテナの集まりのこと。
・ここではdb
,web
,chrome
,redis
という4つのサービスを定義する。
services トップレベル要素
db:
container_name: postgresql_db
image: postgres:16
restart: always
environment:
TZ: Asia/Tokyo
POSTGRES_PASSWORD: password
volumes:
- postgresql_data:/var/lib/postgresql
ports:
- 5432:5432
healthcheck:
test: ["CMD-SHELL", "pg_isready -d myapp_development -U postgres"]
interval: 10s
timeout: 5s
retries: 5
db
- データベースの定義をする。
container_name: postgresql_db
- デフォルトで生成される名前ではなく、任意のコンテナ名を指定する。
- Composeファイルでcontainer_nameを指定している場合、Compose実装は、コンテナ1つよりも多くにサービスをスケールさせてはいけない。container_name は一意でなければならないため、2つのコンテナで同じ名前を使えない。スケールが必要な場合はcontainer_nameは指定しない。
スケール
- 正規表現に従った命名にしなければならない。
- 名前を指定すると
docker ps
コマンドなどでコンテナを確認する場合にわかりやすい。
image
- Docker公式のイメージを指定する。
restart: always
- コンテナが終了した際の動作を指定する。
-
always
により、コンテナを削除するまで、常に再起動する。
- なお、手動でコンテナを停止した場合は自動で再起動はしないらしい。
Always restart the container if it stops. If it's manually stopped, it's restarted only when Docker daemon restarts or the container itself is manually restarted.
environment:
TZ: Asia/Tokyo
RAILS_ENV: production
POSTGRES_PASSWORD: <%= Rails.application.credentials.dig(:db, :password) %>
environment
- コンテナ内での環境変数を定義する。
TZ: Asia/Tokyo
- タイムゾーンを指定する。ここではアジア/東京を指定する。
- TZを設定しない場合、基本的にはUTCとなる。(ベースイメージによって異なるらしい)
POSTGRES_PASSWORD
- PostgreSQLインスタンスのパスワードを定義する。
- postgresをdbとして使用する場合、パスワードの設定が最低限必要になる。なお、本番環境では
credentials
等を利用して機密にすること。
The PostgreSQL image uses several environment variables which are easy to miss. The only variable required is POSTGRES_PASSWORD, the rest are optional.
volumes
- ボリュームについては後述する。
port
- 起動したコンテナのポートとホストのポートにポートフォワーディングする。
ポートフォワーディング
- スケールして複数のコンテナを立てる場合、ホスト側の同じポートを指定するとエラーになるため、コンテナ側のポートのみ指定する。
healthcheck
- このサービスが正常かどうかを確認する。
- 後述するが、依存する側のサービスに
depends_on
で依存先のサービスの状態を指定することで、サービスの起動順序を指定できる。依存先のサービスが正常に起動できていない場合、以下のエラーが発生する。
dependency failed to start: container dbコンテナ名 is unhealthy
web:
container_name: rails_app
build:
context: .
dockerfile: Dockerfile.prod
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
tty: true
stdin_open: true
volumes:
- .:/myapp
- bundle_data:/usr/local/bundle:cached
- node_modules:/myapp/node_modules
environment:
TZ: Asia/Tokyo
RAILS_ENV: production
SELENIUM_DRIVER_URL: http://chrome:4444/wd/hub # Capybaraによるテストのための設定
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
build
-
docker compose build
実行時の設定。 -
context: .
でbuildするディレクトリをdocker-compose.yml
と同じカレントディレクトリに指定する。以下のdockerfileのディレクトリは、ここで設定したディレクトリをルートディレクトリとする。 -
dockerfile: Dockerfile.prod
で、buildに使用するDockerfileをDockerfile.prod
に指定する。
tty: true
- 仮想端末を用意してコンテナを持続させるための設定。
studin_open
- サービスコンテナに標準入力を割り当てて実行するよう設定する。
volumes
- ボリュームを設定することで、コンテナを削除後もデータを保存できる。(永続化)
- コンテナ内部にファイル等のデータを保存しても、コンテナを破棄するとデータごと消えてしまう。なので、データを永続化したい場合には、コンテナの外に保存する必要がある。その場所のことをボリュームと呼ぶ。
-
docker compose up
を初めて実行した際にボリュームが作成され、続く実行でも同じボリュームが再利用される。
データ永続化の手法について
ボリュームマウント
- 名前付きボリュームと無名ボリュームがある。
- 無名ボリュームはコンテナ作成と同時に自動生成されるが、名前がないので判別が困難で、再利用性は低い。
# docker-compose.ymlでの記述例
services:
web:
volumes:
- node_modules:/myapp/node_modules # 外で定義したボリューム名:コンテナの絶対Path
volumes:
node_modules: # ボリューム名を定義
バインドマウント
- ホストマシン上のファイルやディレクトリがコンテナ内にマウントされる。
- コンテナ側で予めファイルやディレクトリを準備する必要がないため、コンテナ削除後もローカルにデータがあれば、同様に使用できる。
- ローカルでのファイルの変更がコンテナに反映される。
# docker-compose.ymlでの記述例
services:
web:
volumes:
- .:/myapp # ホスト側の(docker-compose.ymlからの)相対Path:コンテナの絶対Path
depends_on
・db(サービス名)
とcondition: service_healthy
を指定することで、db
というサービスが正常(healty)に起動した場合のみ、このサービスを起動する。これによりサービスの起動順序を指定できる。