🐳
[docker-compose] DB continer(service) へ migration を行う
要件
-
docker-compose
で DB container 起動時に、同時に migration を行いたい - 既に起動している DB container へ 任意のタイミングで migration したい
- できれば migration bin をlocalにインストールして行うのではなく、docker を使用したい
実行環境
- MacOS Big Sur v11.6
- Apple M1
Tools
Database | Migration tool |
---|---|
MySQL | golang migrate |
結論
file system
以下のようなディレクトリ構成を前提としています。
本稿は、migration
が主題であってseed
は本質ではないので割愛します。
また、migration
の内容(DDL)自体も何でもいいので、sqlファイルの中身も割愛します。
.
├── db
│ ├── conf.d
│ │ └── my.cnf
│ ├── migrations
│ │ │── Dockerfile
│ │ │── entrypoint.sh
│ │ └── migrations
│ │ └── 0001_init.up.sql
│ │ └── 0001_init.down.sql
│ │ └── 0002_xxxx.up.sql
│ │ └── 0002_xxxx.down.sql
│ └── seeds
│ │── xxxx.sql
│ │── ...
└── docker-compose.yml
docker-compose
docker-compose.yml
version: "3"
services:
db:
image: mysql:5.6
platform: linux/amd64
environment:
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: password
ports:
- "3306:3306"
volumes:
- db_volume:/var/lib/mysql:cached
- ./db/conf.d:/etc/mysql/conf.d
migrate:
build: ./db/migrations
depends_on:
- db
command: ["up"]
environment:
WAIT_HOSTS: db:3306
MIGRATIONS_DIR: /migrations
MYSQL_HOST: db
MYSQL_PORT: 3306
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: password
volumes:
- ./db/migrations/migrations:/migrations
volumes:
db_volume:
driver: local
migrate Dockerfile
migrate/Dockerfile
FROM migrate/migrate
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
RUN chmod +x /wait
COPY entrypoint.sh /usr/local/bin
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT [ "entrypoint.sh" ]
migrate entrypoint.sh
migrate/entrypoint.sh
#!/bin/sh
/wait
/migrate \
-path $MIGRATIONS_DIR \
-database "mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/${MYSQL_DATABASE}" \
$@
Point1: db service を待機
docker-compose up
で全serviceを起動する場合、migration container は db
(mysqld) の起動が完了し、tcp接続ができるようになるまで待機する必要があります。
docker-compose service 間の依存は dependes_on
で宣言的に定義できるものの、あくまで container の起動順序が制御されるだけであって、依存先の container が ready になるまで依存元の container の起動を待機する訳ではありません。
なので、 docker-compose-wait を利用し、特定の service が ready 状態になるまで待機するようにします。
migrate/Dockerfile
~
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
RUN chmod +x /wait
~
Point2: Docker entrypoint
golang migrate の official docker image では、 ENTRYPOINT
が定義されているので、上記の docker-compose-wait
を利用するべく ENTRYPOINT
を上書く必要があります。
ENTRYPOINT /wait && migrate
ただし、上記のように定義すると、走るプロセスは /bin/sh
となり、CMD
を migrate
の引数として渡すことができません。
docker inspect 89ab8ebc951e (container id/name)
[
{
"Id": "89ab8ebc951e3ee27a655960762227895d528173dcd7ba3dafc65c391ce5abee",
"Created": "2021-12-29T09:57:56.691705503Z",
"Path": "/bin/sh",
"Args": [
"-c",
"/wait \u0026\u0026 migrate",
"up"
],
...
なので、ENTRYPOINT
を shell script file とし、CMD
をその引数として実行するようにします。
COPY entrypoint.sh /usr/local/bin
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT [ "entrypoint.sh" ]
migrate/entrypoint.sh
#!/bin/sh
/wait
/migrate \
-path $MIGRATIONS_DIR \
-database "mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/${MYSQL_DATABASE}" \
$@
結果↓
docker inspect 127b9306a3da
[
{
"Id": "58b4b845757725c2623dc8df99d04f41c8e3aff9626f0ee26f1ac74bc7be77f8",
"Created": "2021-12-29T10:16:34.032928673Z",
"Path": "entrypoint.sh",
"Args": [
"up"
],
...
これで、docker-compose run
の引数で migration を行うことができるようになりました。
How to use
DB service 起動時に migration まで行う
docker-compose up
起動中の DB service に対し、追加で migration を行う
e.g.
docker-compose run migrate down 1
migration は行わないで DB の起動だけしたい
docker-compose up db
Discussion