记录一下在项目中遇到的Docker报错信息
MySQL数据库和Prisma相关
docker-compose.yml文件
mysql:
container_name: mysql_container # 容器名称
image: mysql:8.0.32 # 使用官方镜像
ports:
- 3306:3306 # 本机端口:容器端口
restart: on-failure # 在失败时重启
environment:
- MYSQL_ROOT_PASSWORD=888888 # root用户密码
- MYSQL_DATABASE=mysql_database # 初始化时创建的数据库
volumes:
- ./deploy/mysql/db:/var/lib/mysql # 本地路径:容器内路径 -> 用来存放数据库表文件
- ./deploy/mysql/conf/my.cnf:/etc/my.cnf # 存放自定义的配置文件
# 我们在启动MySQL容器时自动创建我们需要的数据库和表
# mysql官方镜像中提供了容器启动时自动docker-entrypoint-initdb.d下的脚本的功能
- ./deploy/mysql/init:/docker-entrypoint-initdb.d/ # 存放初始化的脚本
server:
# 容器名称
container_name: server_container
# 构建目录
build:
context: .
dockerfile: prod.Dockerfile
# 重启规则
restart: on-failure # 设置自动重启,这一步必须设置,主要是存在mysql还没有启动完成就启动了node服务
# 暴露端口
expose:
- 3000
ports:
- 3000:3000
# 构建依赖
depends_on:
- mysql
env_file:
- .env
# 环境变量
environment:
- RUN_TIME_ENV=local
.env文件
DATABASE_URL="mysql://root:888888@localhost:3306/mysql_database"
报错信息
无法连接到本地3306端口的MySQL服务
PrismaClientInitializationError: Can't reach database server at `localhost`:`3306`
原因
在进行本地开发的时候,使用Prisma作为ORM工具,Prisma需要在本地创建一个.env文件并在文件中指明需要连接的数据库信息(文件内容就是上面的.env);
这样的写法在本地开发时没有问题,因为就算你在本地用容器单独跑了一个MySQL的服务,那也是在本地环境暴露3306端口,所以对于不是在容器中的项目来说,自然可以连接;
但是现在当我们把项目和MySQL服务放在同一个容器内时,对于项目中的Prisma来说,就找不到localhost这个地址了;
解决办法
在docker-compose中,如果多个服务是通过同一个docker-compose启动的话,就可以通过yml文件中配置的几个服务的名称进行通信,所以我们需要在本地项目中
- 新建一个
.env.prod文件用于Docker构建
# env.prod
DATABASE_URL="mysql://root:888888@mysql:3306/mysql_database"
- 然后修改
docker-compose.yml
# ...
env_file:
- .env # 改成 .env.prod
# ...
即可。
Prisma连接MySQL服务之后提示数据库不存在
PrismaClientInitializationError: Database `mysql_database` does not exist on the database server at `mysql:3306`.
原因
出现这个问题的原因一般有两个
- 没有在
MySQL初始化的时候指定需要自动创建的数据库 - 数据库的自动创建操作尚未完成
解决办法
- 针对第一种情况,我们需要在
docker-compose.yml文件的mysql部分添加
environment:
- MYSQL_DATABASE=mysql_database # 初始化时创建的数据库
- 针对第二种情况,只需要等待数据库创建完成即可,创建完成后
Prisma就不会再有这个错误提示了。
包管理工具相关(npm & pnpm)
报错信息
提示文件冲突
error: failed to solve: cannot replace to directory /var/lib/docker/overlay2/*/*/folder_a with file
原因
出现这个问题,有一个可能的原因是在本地项目中使用的包管理工具与在Dockerfile构建中使用的包管理工具不同。例如我的项目中就有这个问题,本地使用的是pnpm,而在Dockerfile中只拷贝了package*.json,并且使用npm ci进行依赖安装。所以当本地的依赖发生更新之后,Dockerfile中拿到的依然是旧的依赖文件,所以就会出现问题。
解决办法
- 删除本地的
node_modules和package.lock.json; - 使用
Dockerfile中指定的包管理工具(对我来说就是npm)安装本地依赖,从而生成新的package.lock.json; - 即可。