【问题标题】:How to run knex migrations from Dockerfile or docker-compose如何从 Dockerfile 或 docker-compose 运行 knex 迁移
【发布时间】:2022-01-30 22:06:33
【问题描述】:

我有与 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
...

【问题讨论】:

  • 对于不同的技术堆栈,How do you perform Django database migrations when using Docker-Compose? 中有一些选项的讨论。一般来说,主要的选择是手动docker-compose run your-app knex migrate:latest,或者设置一个ENTRYPOINT 包装脚本在每次启动时自动执行。即使您使用不同的语言/迁移系统,该问题是否有足够的详细信息来帮助您?
  • 我同意你的看法。我可以创建这样的 ENTRYPOINT 脚本,我想这会起作用,但我想只使用 docker 和 docker-compose 工具来实现它。

标签: javascript node.js docker database-migration knex.js


【解决方案1】:

我可能以愚蠢的方式解决了这个问题,但它确实有效。所以,我所做的只是将它添加到我的 API 容器中:

restart: on-failure
command: bash -c "npm run knex && npm run start"

现在,它只是重新启动容器,直到连接到数据库并执行所有迁移。

【讨论】:

    【解决方案2】:

    如果您想水平扩展您的应用程序,链接命令或使用和入口点不是最佳选择。

    然后所有副本将同时进行迁移。它可能不会引起真正的问题,但它仍然不是完美的 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-05
      • 2020-04-27
      • 1970-01-01
      • 2021-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多