[英]How to run knex migrations from Dockerfile or docker-compose
I have Dockerfile that works with API and MySQL database and it should do migrations:我有 Dockerfile 与 API 和 MySQL 数据库一起使用,它应该进行迁移:
FROM node
WORKDIR /api
COPY . .
RUN npm install
EXPOSE 3001
VOLUME [ "/api/node_modules" ]
CMD [ "npm", "start" ]
Also, there is a docker-compose file where I have database as a service:此外,还有一个 docker-compose 文件,其中我将数据库作为服务:
db:
image: mysql
container_name: database
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_PASSWORD: password
MYSQL_DATABASE: testdb
The problem is, I don't know how to run migrations.问题是,我不知道如何运行迁移。 Should I do it from docker-compose file or Dockerfile?我应该从 docker-compose 文件还是 Dockerfile 执行它?
I was trying to do something like this in Dockerfile, but it doesn't seem to be working:我试图在 Dockerfile 中做这样的事情,但它似乎不起作用:
...
CMD [ "knex", "migrate:latest" ]
...
Or:或者:
...
RUN knex migrate:latest
...
I solved this problem, probably in stupid way, but it works.我解决了这个问题,可能是以愚蠢的方式,但它有效。 So, what I did is just added this on my API container:所以,我所做的只是在我的 API 容器上添加了这个:
restart: on-failure
command: npm run knex
Now, it just restarts container until get connection to database and does all migrations.现在,它只是重新启动容器,直到连接到数据库并执行所有迁移。
Chaining the command or using and entrypoint is less optimal in case you want to horizontally scale your application.如果您想水平扩展应用程序,链接命令或使用和入口点不是最佳选择。
Then all replicas will do the migration, at the same time.然后所有副本将同时进行迁移。 It's likely to not cause real problems, but It's still not perfect IMO.它可能不会引起真正的问题,但它仍然不是完美的 IMO。
Instead, this should be handled separately, as a one shot command when actually required.相反,这应该单独处理,在实际需要时作为一次性命令。 For example, in Kubernetes in would be good to run a dedicated migration job along with your application release, if the database schema has actually changed.例如,在 Kubernetes 中,如果数据库架构实际上已更改,那么与您的应用程序版本一起运行专用迁移作业会很好。
With compose, there are no jobs, but you can achieve similar behaviour.使用 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
Now you row the migration only once and all 3 app replicas wait for the migration to complete before they start up.现在,您只需执行一次迁移,所有 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
In your case, you would use the same image you build from the Dockerfile for both migration and app service.在您的情况下,您将使用从 Dockerfile 构建的相同映像用于迁移和应用程序服务。 In the migration service you use knex migrate
and in the app service you use npm run start
.在迁移服务中使用knex migrate
,在应用服务中使用npm run start
。
If you need the migration to even wait for the DB, depends_on might not be sufficient, unless you build in a health check that reflects if the database is actually ready to accept a connection.如果您需要迁移甚至等待数据库,depends_on 可能还不够,除非您构建反映数据库是否实际准备好接受连接的运行状况检查。 If you have a health check, then you can use the condition service_healthy
.如果您有健康检查,那么您可以使用条件service_healthy
。
For example, you could dome something like this.例如,你可以像这样做圆顶。
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
You can health check logs by doing a container inspect.您可以通过执行容器检查来检查日志。
$ 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
If you don't want to use a health check, you can also use third party solutions like https://github.com/Eficode/wait-for .如果您不想使用健康检查,也可以使用第三方解决方案,例如https://github.com/Eficode/wait-for 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.