探索Docker容器下MySQL的数据持久化

背景介绍

容器化技术为开发带来了巨大的便捷,Docker作为容器化技术的典型代表,广泛的应用在工程生产中。
同时,以Docker为基础的其他技术,也极大地丰富了Docker的功能,如Python编写的容器编排技术Docker Compose,谷歌开源的容器管理技术Kubernetes,都为传统的开发、部署、维护的工作打开了新世界的大门。

最近打算用docker-compose创建一个 网页客户端(web)+ 服务端接口(api)+ 任务队列(celery)的项目。
按照传统的部署方式,需要在宿主机上启动的进程有:数据库(MySQL/MongoDB)、缓存(Redis/RabbitMQ/..)、任务队列(celery)、后端API(Python/..)、HTTP服务器(Nginx/Apache)。缺点有一些:初次部署环境配置较多、多个进程维护成本高。

如果采用容器的方式部署,首先解决了本地开发与生产环境差异产生的影响;其次,采用Docker ComposeKubernetes更加符合模块化开发的风格,降低了耦合性,提高了可维护性。

最近在看Docker ComposeKubernetes,其中容器相互引用利用的是容器名,在创建容器时将指定的容器名写入hosts,这样就可以起到和localhost一样的效果。
但如果在宿主机上运行的进程,比如mysql-server或内部其他接口,是不能从容器内进行调用的,容器的端口映射只能将端口进行暴露,只能在宿主机内单向连通。

对此,我想到的解决有两个:一个是通过公网IP进行连接;另一个就是将这些服务进程运行在容器内。

第一个办法这无疑降低了性能,提高了网络延迟,不可取。第二个办法对于一般的服务可行,但是对于数据库需要考虑数据持久化,不能因为容器停止、重启等造成数据的丢失。

Docker容器下MySQL数据持久化

前提

mysql-server镜像要比mysql镜像小几百兆,更为精简;MySQL 8.0版本在用户认证机制上做了变动,在探索过程中没有找到较好的解决办法,只好选择 MySQL 5.7版本。

卷挂载

根据博客Docker MySQL Persistence,与mysql/mysql-server镜像文档的内容。

MySQL支持数据的持久化,只要将指定的宿主机目录挂在到MySQL默认数据存储路径 /var/lib/mysql中即可。

1
2
3
4
docker run -it --name mysqldb \
-v /path/to/local-mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
-d mysql/mysql-server:5.7

将此目录以相同方式挂载到其他容器中,即可以实现Docker容器下MySQL数据的持久化,但被挂载的目录只能被一个MySQL容器使用,不能多个MySQL容器同时挂载。

1
2
3
4
docker run -it --name mysqldb \
-v /path/to/local-mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
-d mysql/mysql-server:5.7

开启远程访问

在解决数据持久化之后,需要解决连接问题。

  • 首先是暴露端口,增加-p参数:
1
2
3
4
5
docker run -it --name mysqldb \
-v /path/to/local-mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
-p 3306:3306 \
-d mysql/mysql-server:5.7
  • 其次是远程访问,需要将指定用户的访问地址host设为访问IP或%,这样可以从宿主机,或其他容器连接。

如果使用的是root用户,则需设置MYSQL_ROOT_HOST环境变量:

1
2
3
4
5
6
docker run -it --name mysqldb \
-v /path/to/local-mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_ROOT_HOST=% \
-p 3306:3306 \
-d mysql/mysql-server:5.7

也可以创建新用户,此时需要额外的三个环境变量:用户名MYSQL_USER、用户密码MYSQL_PASSWORD、授权该用户的数据库名MYSQL_DATABASE,此时创建的用户的访问host%,即任意IP:

1
2
3
4
5
6
7
8
docker run -it --name mysqldb \
-v /path/to/local-mysql:/var/lib/mysql \
-e MYSQL_USER=new_username \
-e MYSQL_PASSWORD=new_user_password \
-e MYSQL_DATABASE=user_database \
-e MYSQL_ROOT_PASSWORD=password \
-p 3306:3306 \
-d mysql/mysql-server:5.7