windows环境下搭建mysql数据库docker容器
最近因项目需要,要在windows环境下搭建一个以容器镜像运行的mysql数据库,本以为是件简单的事情,结果遇到不少坑,所以在这里记录下来以和大家共享。
运行环境
操作系统:Windows 10家庭中文版
Windows Docker安装包:Docker Toolbox version 19.03.1
Docker compose文件:
version: "3"
services:
mysql:
container_name: mysql
hostname: mysql
image: mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- ./mysql_data:/var/lib/mysql
- ./my.cnf:/etc/my.cnf
expose:
- "3306"
networks:
- "c7nNetwork"
networks:
c7nNetwork:
driver: bridge
因为需要对mysql运行镜像容器做数据持久化处理并进行运行参数配置,所以在docker-compose.yaml文件中分别挂载了mysql_data目录和my.cnf配置文件。
my.cnf配置文件内容:
[mysqld]
lower_case_table_names=1
character_set_server=utf8
max_connections=500
我的文件目录位置及结构:
操作步骤
- 打开“Docker Quickstart Terminal”,如下图:
- 将运行目录切换到docker-compose.yaml文件所在目录下,如下图:
- 输入命令"docker-compose.exe up -d"启动容器,然后输入“docker-compose.exe ps”命令查看容器运行状态,如下图所示:
问题一
经过执行以上部署步骤后,mysql容器镜像运行状态貌似没有什么问题,可是仔细查看后发现了两个问题:
1.挂载的mysql_data目录下没有产生任何文件,但是容器内/var/lib/mysql目录下数据库相关文件成功生成了;
2.容器内etc目录下的my.cnf竟然不是一个文件,而是一个目录,如下图所示:
原因分析
从现象看,所有问题都出在存储volume的挂载处理上,根本没有达到预期挂载效果。docker-compose在挂载错误的情况下没有给出明显的提示而做了默认处理,甚至把本来要挂载的文件在错误的情况下当做目录进行了处理。
问题原因分析思路:
1.首先可以排除文件夹和文件不存在的原因,docker-compose.yaml文件的同级目录下肯定存在对应的文件夹和文件;
2.如果排除了文件夹和文件不存在的原因,那只有一种可能,就是docker-compose程序在执行挂载命令时无法找到这两个对象,那为什么会找不到呢?经过深入分析,觉得还是docker-compose程序运行环境导致,我们执行docker-compose程序时是在一个Windows的终端上,所以给了我们一个错觉,以为是在Windows本地运行,但其实不是,docker-compose程序真正执行环境是在一个VirtualBox的虚拟机里,双击“Oracle VM VirtualBox”图标,如下图所示:
在这个虚拟机里肯定没有这两个文件夹和文件对象,这就可以解释为什么docker-compose程序没有找到对应的文件夹和文件。
解决办法
找到问题原因后解决就简单了,只要想办法将对应的文件夹和文件先共享进入虚拟机,然后再执行docker-compose命令进行挂载应该就可以了。经过调查,发现虚拟机存在一个默认的共享文件夹路径,位置在本地的C:\Users,如下图所示:
考虑到C:\Users目录在Windows 10环境下权限控制较为严格,不太适合进行工程开发,所以决定再增加一个挂载目录用于项目开发,本人在D盘根目录下创建了一个share文件夹,然后共享到虚拟机,如下图所示:
注意:增加新的共享目录需要先将虚拟机关闭。
将D:\WinDocker目录下的mysql文件夹整体移动D:\share文件夹下,然后重新执行docker-compose程序。在执行过后发现问题依旧,进入虚拟机查看,能够看到对应的文件夹和文件对象信息,如下图所示:
莫非是docker-compose程序无法解析./这种写法,尝试修改试试看,如下图所示:
version: "3"
services:
mysql:
container_name: mysql
hostname: mysql
image: mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- /share/mysql/mysql_data:/var/lib/mysql
- /share/mysql/my.cnf:/etc/my.cnf
expose:
- "3306"
networks:
- "c7nNetwork"
networks:
c7nNetwork:
driver: bridge
然后重新执行“docker-compose.exe up -d”命令。
问题二
新的问题出现了,查看mysql运行状态,发现容器状态竟然是退出,如下图所示:
容器运行日志如下图所示:
## 原因分析
通过查看mysql_data文件夹的内容,可以证明问题一的文件夹和文件挂载问题已经解决了,通过分析日志文件,可以看到两个问题:
1.容器内/etc/my.cnf文件由于权限过大而被mysqld进程因World-Writable(全局可写)的安全因素而被放弃加载;
2.出现了aio write文件写入错误,说明虚拟机不支持这种文件读写模式。
解决办法
1.修改/etc/my.cnf文件权限为644,经过测试,如果直接在容器里修改此文件权限不起作用,原因大概可能和Windows挂载有关,所以解决思路是首先完成挂载,然后在启动脚本里拷贝出一份再修改权限,因为mysql镜像启动默认会执行docker-entrypoint.sh脚本,所以首先需要将这个脚本从一个正常镜像中拷贝出来,修改后再挂载回去,具体如下:
version: "3"
services:
mysql:
container_name: mysql
hostname: mysql
image: mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- /share/mysql/mysql_data:/var/lib/mysql
- /share/mysql/my.cnf:/etc/my.cnf
- /share/mysql/docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh
expose:
- "3306"
networks:
- "c7nNetwork"
networks:
c7nNetwork:
driver: bridge
修改docker-entrypoint.sh文件,在文件开头增加内容,具体如下所示:
#!/bin/bash
cp /etc/my.cnf /etc/mysql/conf.d/mysql_db.cnf
chmod 644 /etc/mysql/conf.d/mysql_db.cnf
2.在my.cnf配置文件中增加一行参数:innodb_use_native_aio=0,具体如下所示:
[mysqld]
lower_case_table_names=1
character_set_server=utf8
max_connections=500
innodb_use_native_aio=0
修改完成后将前次执行时mysql_data目录下已经生成的文件全部删除,然后再次执行"docker-compose.exe up -d"命令,这次mysql数据库终于可以正常启动了。