如何从 Dockerfile 或 docker-compose 运行 knex 迁移
How to run knex migrations from Dockerfile or docker-compose
我有与 API 和 MySQL 数据库一起使用的 Dockerfile,它应该进行迁移:
FROM node
WORKDIR /api
COPY . .
RUN npm install
EXPOSE 3001
VOLUME [ "/api/node_modules" ]
CMD [ "npm", "start" ]
此外,还有一个 docker-compose 文件,我将数据库作为服务:
db:
image: mysql
container_name: database
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_PASSWORD: password
MYSQL_DATABASE: testdb
问题是,我不知道如何 运行 迁移。我应该从 docker-compose 文件还是 Dockerfile 来完成?
我试图在 Dockerfile 中做类似的事情,但它似乎不起作用:
...
CMD [ "knex", "migrate:latest" ]
...
或:
...
RUN knex migrate:latest
...
我解决了这个问题,可能是以愚蠢的方式,但它有效。所以,我所做的只是将其添加到我的 API 容器中:
restart: on-failure
command: bash -c "npm run knex && npm run start"
现在,它只是重新启动容器,直到连接到数据库并执行所有迁移。
如果您想水平扩展应用程序,则链接命令或使用入口点不是最佳选择。
然后所有副本将同时进行迁移。它可能不会造成真正的问题,但它仍然不是完美的 IMO。
相反,这应该单独处理,在实际需要时作为一次性命令。例如,在 Kubernetes 中 运行 一个专门的迁移作业与你的应用程序发布一起会很好,如果数据库架构实际上已经改变。
使用 compose,没有作业,但您可以实现类似的行为。
services:
migration:
image: busybox
command: sh -c 'echo "running migration..."; sleep 20; echo "migration completed"'
app:
image: busybox
command: echo "app started"
depends_on:
migration:
condition: service_completed_successfully
deploy:
replicas: 3
现在您只需对迁移进行一次排行,所有 3 个应用程序副本在启动之前等待迁移完成。
$ docker compose up
Attaching to app_1, app_2, app_3, migration_1
migration_1 | running migration...
migration_1 | migration completed
migration_1 exited with code 0
app_2 | app started
app_3 | app started
app_1 | app started
在您的情况下,您将使用从 Dockerfile 构建的同一映像用于迁移和应用程序服务。在您使用 knex migrate
的迁移服务和您使用 npm run start
.
的应用服务中
如果您需要迁移甚至等待数据库,depends_on 可能还不够,除非您构建健康检查以反映数据库是否真的准备好接受连接。如果你有健康检查,那么你可以使用条件 service_healthy
.
例如,你可以做这样的事情。
services:
db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: "root"
MYSQL_DATABASE: "wordpress"
MYSQL_USER: "wordpressuser"
MYSQL_PASSWORD: "wordpresspassword"
healthcheck:
test: mysqladmin -u root --password=$$MYSQL_ROOT_PASSWORD ping
interval: 30s
timeout: 10s
retries: 10
migration:
image: busybox
command: sh -c 'echo "running migration..."; sleep 20; echo "migration completed"'
depends_on:
db:
condition: service_healthy
app:
image: busybox
command: echo "app started"
depends_on:
migration:
condition: service_completed_successfully
deploy:
replicas: 3
您可以通过容器检查来检查日志的健康状况。
$ docker inspect sample_db_1 --format \
'{{range .State.Health.Log}}{{.End}} | Exit Code: {{.ExitCode}} | {{.Output}}{{end}}'
2022-01-30 12:53:43.749365 +0000 UTC | Exit Code: 0 | mysqladmin: [Warning] Using a password on the command line interface can be insecure.
mysqld is alive
如果您不想使用健康检查,您也可以使用第三方解决方案,例如 https://github.com/Eficode/wait-for。
我有与 API 和 MySQL 数据库一起使用的 Dockerfile,它应该进行迁移:
FROM node
WORKDIR /api
COPY . .
RUN npm install
EXPOSE 3001
VOLUME [ "/api/node_modules" ]
CMD [ "npm", "start" ]
此外,还有一个 docker-compose 文件,我将数据库作为服务:
db:
image: mysql
container_name: database
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_PASSWORD: password
MYSQL_DATABASE: testdb
问题是,我不知道如何 运行 迁移。我应该从 docker-compose 文件还是 Dockerfile 来完成?
我试图在 Dockerfile 中做类似的事情,但它似乎不起作用:
...
CMD [ "knex", "migrate:latest" ]
...
或:
...
RUN knex migrate:latest
...
我解决了这个问题,可能是以愚蠢的方式,但它有效。所以,我所做的只是将其添加到我的 API 容器中:
restart: on-failure
command: bash -c "npm run knex && npm run start"
现在,它只是重新启动容器,直到连接到数据库并执行所有迁移。
如果您想水平扩展应用程序,则链接命令或使用入口点不是最佳选择。
然后所有副本将同时进行迁移。它可能不会造成真正的问题,但它仍然不是完美的 IMO。
相反,这应该单独处理,在实际需要时作为一次性命令。例如,在 Kubernetes 中 运行 一个专门的迁移作业与你的应用程序发布一起会很好,如果数据库架构实际上已经改变。
使用 compose,没有作业,但您可以实现类似的行为。
services:
migration:
image: busybox
command: sh -c 'echo "running migration..."; sleep 20; echo "migration completed"'
app:
image: busybox
command: echo "app started"
depends_on:
migration:
condition: service_completed_successfully
deploy:
replicas: 3
现在您只需对迁移进行一次排行,所有 3 个应用程序副本在启动之前等待迁移完成。
$ docker compose up
Attaching to app_1, app_2, app_3, migration_1
migration_1 | running migration...
migration_1 | migration completed
migration_1 exited with code 0
app_2 | app started
app_3 | app started
app_1 | app started
在您的情况下,您将使用从 Dockerfile 构建的同一映像用于迁移和应用程序服务。在您使用 knex migrate
的迁移服务和您使用 npm run start
.
如果您需要迁移甚至等待数据库,depends_on 可能还不够,除非您构建健康检查以反映数据库是否真的准备好接受连接。如果你有健康检查,那么你可以使用条件 service_healthy
.
例如,你可以做这样的事情。
services:
db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: "root"
MYSQL_DATABASE: "wordpress"
MYSQL_USER: "wordpressuser"
MYSQL_PASSWORD: "wordpresspassword"
healthcheck:
test: mysqladmin -u root --password=$$MYSQL_ROOT_PASSWORD ping
interval: 30s
timeout: 10s
retries: 10
migration:
image: busybox
command: sh -c 'echo "running migration..."; sleep 20; echo "migration completed"'
depends_on:
db:
condition: service_healthy
app:
image: busybox
command: echo "app started"
depends_on:
migration:
condition: service_completed_successfully
deploy:
replicas: 3
您可以通过容器检查来检查日志的健康状况。
$ docker inspect sample_db_1 --format \
'{{range .State.Health.Log}}{{.End}} | Exit Code: {{.ExitCode}} | {{.Output}}{{end}}'
2022-01-30 12:53:43.749365 +0000 UTC | Exit Code: 0 | mysqladmin: [Warning] Using a password on the command line interface can be insecure.
mysqld is alive
如果您不想使用健康检查,您也可以使用第三方解决方案,例如 https://github.com/Eficode/wait-for。