はじめに
この記事では以下で紹介した家計簿アプリ作りで用意したdocker-compose.ymlを詳細に見ていきます。
正直、参考にしたものをほとんどコピペして、一部自分で定義した部分もあるが、それもリファレンスをそのまま流用しただけで、ymlの中で何がどこを定義しているのか、自分の中で消化できていないテイタラクであったので、備忘録として自分の言葉で一つ一つ整理することにした次第です。
参考サイト
docker-compose.ymlの骨子はほとんど@niisan1banさんのものを流用させていただいた。
私なんぞより詳細に説明されているので、そちらも参照いただければ幸いです。
構成図
※@niisan1banさんの図を引用させていただいています。
私自身が改めて作るより遥かにわかりやすい図だったので、恐れながら使用させて頂きました。
docker-compose.yml
ファイルの中身です。次に各項目について説明をつけていきます。
version: '3'
services:
db:
# 起動するイメージを指定
image: mysql:8.0.32-debian
platform: linux/amd64
build:
context: .
dockerfile: ./Dockerfile
# 環境変数を設定
environment:
- MYSQL_ROOT_HOST=${DB_ROOT_HOST}
- MYSQL_DATABASE=${DB_NAME}
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- MYSQL_ROOT_PASSWORD=${DB_PASS}
- TZ=${TZ}
# ホスト側のポート:コンテナのポート
ports:
- '3306:3306'
# ボリュームバインド
volumes:
- ./db/conf:/etc/mysql/conf.d/:ro
- mysqldata:/var/lib/mysql
- ./db/logs:/var/log/mysql
#使用するネットワーク
networks:
- backend
api:
image: node:14.21.2-buster
build:
context: .
dockerfile: ./Dockerfile
environment:
- MYSQL_SERVER=db
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- MYSQL_DATABASE=${DB_NAME}
- TZ=${TZ}
- CHOKIDAR_USEPOLLING=true
#コンテナを起動させ続けるよう設定
tty: true
ports:
- '3000:3000'
# ソースコードを格納するフォルダをマウント
#(ホスト側の./apiをコンテナの/appにマウント)
volumes:
- ./api:/app
# 起動時のカレントフォルダを指定
working_dir: /app
# 起動後に実行するコマンドを指定
command: npm run dev
networks:
- backend
#依存関係(apiコンテナより先にdbコンテナが起動するように設定)
depends_on:
- db
vue:
image: node:14.21.2-buster
build:
context: .
dockerfile: ./Dockerfile
environment:
- CHOKIDAR_USEPOLLING=true
tty: true
ports:
- '8080:8080'
volumes:
- ./vue:/app
working_dir: /app
command: npm run serve
networks:
- backend
depends_on:
- api
networks:
backend:
volumes:
mysqldata:
version
docker-composeのバージョンは3.0にしています。特に気にしていなかったが、docker公式サイトを参照する限り、version3.xを指定していれば無難な模様。
version: '3'
dbコンテナ
image:
image: mysql:8.0.32-debian
docker officialのmysql:8.0.32-debian
のイメージを使用しています。
推奨のマイナーバージョンが現在(2023/8/5)は異なるようなので、推奨のイメージに差し替えてもよいかもです。
メジャーバージョンを変更すると正常に動作しなくなる可能性があるのでお勧めしません。
Dockerfile:
次の定義でcompose起動時にDockerfile
を別途読み込むような設定を追加しています。
build:
context: .
dockerfile: ./Dockerfile
- context: Dockerfileが格納されているパスを指定します。
- dockerfile: 対象のDockerfileを相対パスで指定します。
(参考サイト)
Dockerfileでは、DBで日本語が使える設定を定義しています。
これなしだと英語のデータしかDB登録できなかったので、使い物になりません。
FROM mysql:8.0.32-debian
# 日本語環境を追加
RUN apt-get update
RUN apt-get -y install locales-all
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
※Dockerfileを実際に適用させているのはdbコンテナに対してのみですが、お作法として、他のコンテナの定義でも記述だけしています。dbコンテナだけだと起動時エラーが出たので、各コンテナで横並びに設定を書いておくべきなのでしょう。
environment:
MySQLの環境変数を設定しています。これらの変数を設定していないとコンテナ内でMySQLを使用できないので必須となります。
environment:
- MYSQL_ROOT_HOST=${DB_ROOT_HOST}
- MYSQL_DATABASE=${DB_NAME}
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- MYSQL_ROOT_PASSWORD=${DB_PASS}
- TZ=${TZ}
設定値は、docker-compose.ymlと同階層に配置した.envファイル
に定義しています。
DB_ROOT_HOST=%
DB_NAME=oeconomica
DB_USER=username
DB_PASS=mypassword
TZ=Asia/Tokyo
ports:
# ホスト側のポート:コンテナのポート
ports:
- '3306:3306'
dbコンテナに接続するためのポート番号をここで指定しています。
MySQLで基本的に利用される3306番で定義していますが、ホスト側ですでに別サービスで同ポートを使用済みの場合は、別の分かりやすいポートに変更しても大丈夫です。
# ホスト側のポート:コンテナのポート
ports:
- '33060:3306'
volumes:
volumes:
- ./db/conf:/etc/mysql/conf.d/:ro
- mysqldata:/var/lib/mysql
- ./db/logs:/var/log/mysql
- ./db/conf:/etc/mysql/conf.d/:ro
ホスト上の./db/conf
ディレクトリをコンテナ内の/etc/mysql/conf.d
ディレクトリにreadonly形式でマウントする。こうすることで、my.cnfがコンテナに読み込まれるようになる。
※- ./db/logs:/var/log/mysql
も同じ仕組み
% cd ./db/conf;ls
my.cnf
root@ae9fecd6b75e:/var/lib/mysql# cd /etc/mysql/conf.d/
root@ae9fecd6b75e:/etc/mysql/conf.d# ls
my.cnf
- mysqldata:/var/lib/mysql
mysqldata
という名称のボリュームをコンテナ内の/var/lib/mysql
にマウントする。
ボリュームにはDBのデータが保存されるので、ボリュームが残っている限りはコンテナを一度消そうが、保存したセーブデータそのままに家計簿を使い続けられる。
ボリュームの状態はDocker Destopでこのように見えている。
volumeはdocker-compose.ymlの一番末尾でも記載され、これがないとvolumeが作成自体されない。
volumes:
mysqldata:
apiコンテナ
image:
image: node:14.21.2-buster
docker officialのnode:14.21.2-buster
のイメージを使用しています。
メジャーバージョンがかなり古めのものでした。私の作ったアプリケーションでは特に問題なく動作していますが、node.jsのコンテナを他のアプリを載せるために利用しようと検討している方は、最近のバージョンのものをお勧めします。
environment:
node.jsがデータベースに接続するための環境変数を定義します。
また、CHOKIDAR_USEPOLLING=true
を設定することでHot Reloadが有効になります。
どういうことかというと、これを設定していないと、apiコンテナ内のソースコードを変更しても、変更が反映されなくなり、反映させるために、わざわざ再起動させる手間が生じます。
CHOKIDAR_USEPOLLING=true
を設定すると、ソースコードの変更を検知して自動でアプリを再起動するライブラリ「nodemon」が動くようになるので、ソースコードの修正がリアルタイムで反映され、開発が効率化します。
environment:
- MYSQL_SERVER=db
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- MYSQL_DATABASE=${DB_NAME}
- TZ=${TZ}
- CHOKIDAR_USEPOLLING=true
tty:
この設定を入れないと、ポートの接続待ちや実行プロセスがない場合コンテナが起動してすぐに終了する事象が起きてしまいます。
#コンテナを起動させ続けるよう設定
tty: true
要するに何かしらの仕事を命令されていないと、「オレいる意味なくね?」とコンテナ側がサボって動いてくれない。なので、tty(入出力を受付する窓口)の仕事を用意することで、常に職場にいてもらうようにするって感じです。
working_dir:
デフォルトのカレントディレクトリを設定する項目。
基本、編集するのは、/app以下だけなので、あらかじめカレントディレクトリとして設定しておきます。
# 起動時のカレントフォルダを指定
working_dir: /app
command:
コンテナ起動時に実行させるコマンドを定義しています。
# 起動後に実行するコマンドを指定
command: npm run dev
npmはNode.jsをインストールしたときについてくるパッケージ管理ツールで、
npm run dev
は package.json ファイル内の scripts セクションに定義された dev スクリプトを実行するコマンドになります。
{
"name": "app",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "nodemon ./bin/www",
"start": "node ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"jade": "~1.11.0",
"morgan": "~1.9.1",
"mysql2": "^3.1.2",
"sequelize": "^6.29.0",
"sequelize-cli": "^6.6.0"
},
"devDependencies": {
"nodemon": "^2.0.20"
}
}
depends_on:
サービスの依存関係を定義しています。
ここでは、apiコンテナはdbがないとエラーになって動かないため、dbコンテナ起動後にapiコンテナの起動がはじまるように設定します。
#依存関係(apiコンテナより先にdbコンテナが起動するように設定)
depends_on:
- db
今回のdocker-composeでは最終的にdb→api→vue
の順番で起動するよう依存関係を調節しています。
vueコンテナ
dbコンテナ、apiコンテナの説明で概ね網羅しているので、改めての説明は割愛します。