用 mysql 和 nodeJS 构建一个 docker

Posted

技术标签:

【中文标题】用 mysql 和 nodeJS 构建一个 docker【英文标题】:building a docker with mysql and nodeJS 【发布时间】:2018-11-07 14:12:07 【问题描述】:

我正在构建一个使用 nodeJS 和后端以及 mysql 作为后端的应用程序,目前,我启动应用程序(没有 docker)的步骤是:

    安装 NodeJS 安装 MYSQL 在端口 3306 上启动 mysqld 手动创建一个专用于 NodeJS 后端的 MYSQL 用户。这 用户应该只有我想要的架构的基本特权。 运行 sequelize 命令以使用 4) 中生成的用户 npm installnpm start 在端口 8080 上启动 NodeJS

现在我想对我的应用程序进行 docker 化,并且我已经有了以下 Dockerfile:

#node version: carbon
#app version: 1.0.0

FROM node:8.11.2

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 8080

我在 ./docker_db 文件夹中放置了一个 init.sql 文件,它执行以下操作:

CREATE USER 'app_user'@'%' IDENTIFIED BY 'password';

CREATE SCHEMA `myapp` DEFAULT CHARACTER SET utf8;

GRANT INSERT, CREATE, ALTER, UPDATE, SELECT, REFERENCES on myapp.*
TO 'app_user'@'%' IDENTIFIED BY 'password'
WITH GRANT OPTION;

以及以下 docker-compose.yaml:

version: '3.6'

services:
    mysql1:
        image: mysql/mysql-server:5.7
        environment:
            MYSQL_ROOT_PASSWORD: password
        ports:
            - "127.0.0.1:3306:3306"
        volumes:
            -   type: bind
                source: ./docker_db
                target: /docker-entrypoint-initdb.d
        expose:
            - "3306"
        networks:
            - app-network
    myapp:
        build:
            context: .
            dockerfile: Dockerfile
        command: npm start
        depends_on:
            - mysql1
        ports:
            - "127.0.0.1:8080:8080"
        expose:
            - "8080"
        links:
            - mysql1
        networks:
            - app-network
        command: ["./wait-for-db.sh"]

networks:
    app-network:
        driver: bridge

我的 ./wait-for-db.sh 在哪里执行以下操作:

#!/bin/bash
until mysql -h mysql1 -u app_user -p password -e 'select 1'; do 
        echo "still waiting for mysql"; sleep 1; done

exec node ./db/scripts/generateSequelizeCLIConfig.js
exec node_modules/sequelize-cli/bin/sequelize db:migrate
exec node_modules/sequelize-cli/bin/sequelize db:seed:all
exec npm start

(顺便说一句,我确实想将 3306 暴露给主机,以便我可以使用工作台连接到已成功连接的 mysql 服务器。)

在我的 sequelize 配置文件中我确实有:

"username": "app_user",
"password": "password",
"database": "myapp",
"host": "mysql1",
"port": "3306"

通过上面的设置,我执行了docker-compose up,然后得到以下几行:

mysql1_1  | [Entrypoint] MySQL Docker Image 5.7.22-1.1.5
mysql1_1  | [Entrypoint] Initializing database
myapp_1     | standard_init_linux.go:190: exec user process caused "no such file or directory"
myapp_myapp_1 exited with code 1
mysql1_1  | [Entrypoint] Database initialized
mysql1_1  | Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
mysql1_1  | Warning: Unable to load '/usr/share/zoneinfo/leapseconds' as time zone. Skipping it.
mysql1_1  | Warning: Unable to load '/usr/share/zoneinfo/tzdata.zi' as time zone. Skipping it.
mysql1_1  | Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
mysql1_1  | Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
mysql1_1  |
mysql1_1  | [Entrypoint] running /docker-entrypoint-initdb.d/init.sql
mysql1_1  |
mysql1_1  |
mysql1_1  | [Entrypoint] Server shut down
mysql1_1  |
mysql1_1  | [Entrypoint] MySQL init process done. Ready for start up.
mysql1_1  |
mysql1_1  | [Entrypoint] Starting MySQL 5.7.22-1.1.5

我现在面临的问题是:

1) 脚本的执行挂在Starting MySQL 5.7.22-1.1.5 的最后一行,不会去任何地方。

2) 在输出中,第 3 行和第 4 行显示有关 exec 用户进程导致“没有这样的文件或目录”的错误。我不认为这是由 wait-for-db.sh 中的命令引起的,因为如果我删除了 until 命令之后的行,问题仍然存在。事实上,我怀疑命令执行是否会到达这些行,感觉它仍在until 命令内。

我认为它确实接近最终解决方案 :)

【问题讨论】:

【参考方案1】:

使用您的数据库服务的名称,即mysql,作为您的数据库主机。 Docker 会将其解析为实际 IP。还有,为什么你的Dockerfile 中有FROM mysql:5.7,我认为它没有任何用处。

更新

好吧,好像myapp 在数据库准备好之前运行了数据库脚本。解决方案见这里https://docs.docker.com/compose/startup-order/

【讨论】:

我已根据您建议的更改和其他来源更新了问题,但类似的问题仍然存在。请指教。谢谢!【参考方案2】:

问题可能与时间有关。两个容器将同时启动,并且您的节点应用程序将几乎立即尝试连接到 mysql,而 MySQL 服务器仍在启动。

docker-compose 没有任何类型的结构,因此您必须在节点应用程序中构建一个入口点,首先等待 mysql 响应。

因此,在您的情况下,入口点将类似于

#!/bin/bash
until mysql -h mysql1 -uapp_user -ppassword -e'select 1'; do echo "still waiting for mysql"; sleep 1; done
exec npm start

【讨论】:

我们如何在节点服务中运行 mysql 命令,因为那里不可用。 写入节点?显然,您的节点应用程序也是一个 mysql 客户端。或者在构建映像时安装客户端。或者只是让它睡一会儿。这并不完美,但如果你不介意等待一些额外的时间,你可以睡 30 秒,并且可能确定它开始了。 @AndreasWederbrand 我已根据您的建议进行了更新 - 解决方案出现了新问题。 您只能拥有一个exec。它会将控制权移交给该脚本。其他的可以在您的等待数据库中正常运行。而且,您是否在 node-app 容器中安装了 mysql 客户端?

以上是关于用 mysql 和 nodeJS 构建一个 docker的主要内容,如果未能解决你的问题,请参考以下文章

用MongoDB和AWS云容器构建一个NodeJS APP-部分1

NodeJS + Mysql 与 Docker Compose 2

使用 NodeJS 将启动和停止时间发布到 mysql(sequelize)

jenkins 构建nodejs-pipeline流水风格的任务

Nodejs系列一 gulp初探

用Nodejs+Express搭建web,nodejs路由和Ajax传数据并返回状态,nodejs+mysql通过ajax获取数据并写入数据库