写在前面
Docker 是一个能够把开发的应用程序自动部署到容器的开源引擎。Docker 提供了一个简单、轻量的建模方式。掌握 Docker 以后,使用 Docker 安装我们学习或者开发时常用的 mysql / redis / elastic search / rabbitMQ 等等会变得十分便捷。在作者尝试用windows 7 电脑上的 Docker 容器部署 mysql 5.7 数据库过程中,遇到了使用 sqlyog 却连接不上 mysql 服务的问题。在第1小节中,我将演示一下如何使用 docker-compose 在 Docker 容器中启动一个 MySQL 服务。第 2 小节,记录的是我分析 Sqlyog 连接不上 Docker 容器中的 mysql 数据库的原因。第 3 小节,则是阐述解决问题的方式。如果你只关心这个问题是如何解决的,请直接跳至“问题解决”章节。
作者在定位问题的过程中,接触了 Docker 常用的指令,在本文中也稍稍做个记录。另外,再开始 MySQL 部署之前,请确保你已经安装设置好 Docker 环境了,可以参考这篇 Docker在WIN7上的配置
1.Docker 容器启动 MySQL
Docker Mysql 官方文档
Docker compose-file 官方文档
相比于复杂的 docker 命令,我更愿意选择使用docker-compose方式在 Docker 容器中启动 MySQL。
1.1 创建 yaml 文件
version: '3.1'
services:
test-mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123456
ports:
- "3306:3306"
volumes:
- "/d/VirtualSpace/mysql/my.cnf:/etc/mysql/conf.d/my.cnf"
- "/d/VirtualSpace/mysql/:/docker-entrypoint-initdb.d/"
version
version 代表的是 Compose File Format(构成文件格式)的版本,有 1,2,2.x,3.x 版本,目前常见的是 3.x 版本(传送门)
你可以通过 docker --version 命令查看一下你的 docker 是否支持对应的 Compile File Format 版本。
services
我认为,services 代表是服务进程,可以通过docker ps查看启动进程。
这个名字的组成结构是 <当前工作路径名>_<servicename>_<sequencenumber>,我的 docker-compose.yml 文件路径是 D:\VirtualSpace\mysql\docker-compose.yml;服务名称 servicename 是 test-mysql;序号 sequencenumber 是从 1 开始计数的。
想了解更多关于 servicename 的内容,可以查看 docker-compose service name和container name的关系
image
一般来说,比较推荐使用 Dockerfile 来构建镜像,截止到 2020 年 11 月,MySQL 支持的镜像标签有以下几种:
environment
启动 mysql 映像时,可以通过在 docker run 命令行上传递一个或多个环境变量来调整 MySQL 实例的配置。
MYSQL_ROOT_PASSWORD
该变量是必需变量,它指定将为 MySQL root 用户的密码。
ports
要么指定两个端口(HOST:CONTAINER),要么仅指定容器端口(选择临时主机端口)。
volumes
冒号左边是指定主机的文件系统路径,冒号右边是指定容器的文件系统路径。从基础主机文件系统系统路径,装入容器文件系统路径。
首次启动容器时,将创建一个具有指定名称的新数据库,并使用提供的配置变量对其进行初始化。 此外,它将执行在/docker-entrypoint-initdb.d中找到的扩展名为.sh,.sql和.sql.gz的文件。文件将按字母顺序执行。您可以通过将 SQL 转储安装到该目录中并为自定义图像提供贡献的数据来轻松填充 mysql 服务。 默认情况下,SQL 文件将导入到 MYSQL_DATABASE 变量指定的数据库中。
关于 windows 系统的特殊说明:
我使用的是 win7 系统,在安装 Docker 时,用到了 VirtualBox,Docker 其实是运行在 VirtualBox 中的
默认情况下,仅对C:\Users 目录下进行挂载,对应的 Linux 虚拟机路径是 /c/Users
因为我们在 docker-compose.yml 中有指定 /d/VirtualSpace/mysql/my.cnf 和 /d/VirtualSpace/mysql/,这其实是由你 Windows 主机上的 D:\VirtualSpace\mysql\my.cnf 和 D:\VirtualSpace\mysql 共享给虚拟机,然后再挂载到 Docker 容器。正因为共享给虚拟机了,所以虚拟机中也可以访问到我们的指定文件。
1.2 启动服务
docker-compose down
暂停所有的服务
docker-compose up
启动当前工作目录下的服务,docker-compose up -d 表示后台启动命令。
1.3 使用 SQLyog 尝试连接
然后在使用 SQLyog 连接时,主机地址选择 localhost,端口 3306:
出现错误 1045,这是表示访问密码错误:
出现这个错误的主要原因:我以前在本地安装过 mysql,所以这个其实是我 windows 主机安装的 mysql 服务,不是 docker 容器的 mysql 服务,为了避开这个问题,我选择修改了 docker-compose.yml 的 ports 属性
ports:
- "3311:3306"
然后重新启动服务。再次尝试,这次的 Host Address 仍然是 localhost,端口改为 3311
2003 错误主要原因,网上的常见说法都是没有启动 mysql 服务。如果是 windows 主机安装的 mysql 服务,只要启动一下 mysql 服务就好了。但是,我们此时是用 Docker 容器启动服务的。
2.问题分析
真的会是 Docker mysql 服务没有正常启动的原因吗?
docker ps
该命令可以查看 Docker 服务进程。
分析:我们看到 test-mysql 服务是正常启动的,而且端口也是正确的。
难道说端口映射不起作用?于是我百度了一下,找了好久,这篇文章(解决无法对docker容器进行端口映射的问题)终于解答了我的疑惑。
网上还有一种说法,说是没有给 root 账号授权。
docker exec
docker exec 命令允许您在 Docker 容器内运行命令。 以下命令行将在 mysql容器内为您提供 bash 外壳:
docker exec -it mysql_test-mysql_1
在 Bash 中登录 mysql 客户端
mysql -uroot -p123456
在 mysql 客户端查询用户权限
SELECT HOST,USER,PLUGIN FROM mysql.user;
这里默认是给 host 授权了的,所以至少我连不上不是因为 root 账号没有授权的缘故。
3.问题解决
之所以在 Windows 主机上出现端口映射“不起作用”的情况,是因为在Linux上,docker 守护进程(和您的容器)在 Linux 机器本身上运行,因此“localhost”也是容器在其上运行的主机,并且端口已映射到该主机。
相对地,在 Windows(和 OS X)上,docker 守护程序和您的容器无法在本地运行,因此只有 docker 客户端在 Windows 机器上运行,而守护程序(和您的容器)在运行Linux的 VirtualBox 虚拟机中运行。于是我们通过以下命令:
docker-machine ip default
找到这个Linux的ip地址,一般情况下这个地址是 192.168.99.100。
因此 Host Address 改为 192.168.99.100:
总结一下:
在 Windows(和 OS X)系统上,docker 守护程序和您的容器无法在本地运行,因此只有 docker 客户端在 Windows 机器上运行,而守护程序(和您的容器)在运行Linux的 VirtualBox 虚拟机中运行。
参考文献
Docker之docker volume 挂载到容器(Windows下,volume目录挂载在容器、四)(第十四篇)