我正在构建一个使用nodeJS和后端以及mySQL作为后端的应用程序,目前,我启动应用程序(没有docker)的步骤是:
npm install
和npm start
在端口8080上启动NodeJS 现在我想把我的应用程序dokerize,我已经有了以下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
命令中。
我认为它与最终解决方案非常接近:)
答案 0 :(得分:1)
使用数据库服务的名称mysql
作为数据库主机。 Docker会将其解析为实际的IP。另外,为什么FROM mysql:5.7
中有Dockerfile
,我认为它没有任何用途。
<强>更新强>
好吧,似乎myapp
在db准备好之前运行db脚本。请参阅此处了解解决方案https://docs.docker.com/compose/startup-order/
答案 1 :(得分:1)
问题可能与时间有关。两个容器将同时启动,你的node-app几乎会立即尝试连接到mysql,而MySQL服务器仍在启动。
docker-compose没有任何类型的结构,所以你必须在你的node-app中构建一个第一个等待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