本篇随笔是继 “Docker Engine” 与 “Compose & Swarm” 之后的一个实例补充,初衷是记录测试环境中的一次 MySQL 事故,就当做 “Docker 系列” 的一个小收尾吧。其实在生产环境中不推荐使用 Docker 部署 MySQL 和 Redis,那可是 The First Domino,倒一个挂一片呀,不过在本地和测试环境中就随意了。
一般部署这些 db_service 容器都应该配套其管理工具(我不否认可以通过命令行完成所有的操作,而且功能更多,权限更大,但是非 DBA 的童鞋还是乖乖使用 UI 吧,耍酷浪费太多时间也不值当?),因此,这里我选择的镜像组合是 mysql、adminer 与 redis、erikdubbelboer/phpredisadmin。
Ps:这节太短了,就插一些题外话吧。现在爽 Docker 的同时其实也在为过去的自己默哀,想当年初入编程的时候还没普及云服务器和各种打包好的云服务方案,当然也没有 Docker,想做点什么实验和测试都得在本机。本本性能不行还得一天到晚折腾各种安装环境,就拿 db_service 来说吧,当时选择的是 SQL Server,流行的版本是 05、08 和 08 r2 等,客户要求啥版本的都有。那开发的时候得在本地装呀,要命的是这家伙根本无法彻底卸载,版本之间还有兼容问题,啥错误都遇到过,解决不了最后的终极方案就是重装系统,然后呢... 还得再装呀... 这一下子就是半天到一天的时间。使用虚拟机吧,打开几个 IDE 再启动几个虚拟机,不要说那时候了,就是现在的主流机也扛不动呀,编程体验几乎为零。这里算是忆苦思甜了,想想那时候,现在简直太幸福了。
adminer 与 phpredisadmin 都可以在集群内访问需要代理的服务,如果是在服务器上也不用额外暴露 3306 和 6379 端口,以下是我的 docker-compose 配置:
mysql:
image: mysql
networks:
- proxy
- youclk
volumes:
- /mnt/nas/db/mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: db_password
deploy:
restart_policy:
condition: any
max_attempts: 3
update_config:
delay: 5s
order: start-first
resources:
limits:
cpus: '0.50'
memory: 1g
mysql_admin:
image: adminer
networks:
- proxy
- youclk
depends_on:
- mysql
deploy:
labels:
- com.df.notify=true
- com.df.port=8080
- com.df.serviceDomain=mysql.youclk.com
restart_policy:
condition: any
max_attempts: 3
update_config:
delay: 5s
order: start-first
resources:
limits:
cpus: '0.50'
memory: 1g
启动后 UI 展示如下:
redis:
image: redis
networks:
- proxy
- youclk
deploy:
restart_policy:
condition: any
max_attempts: 3
update_config:
delay: 5s
order: start-first
resources:
limits:
cpus: '0.50'
memory: 1g
redis_admin:
image: erikdubbelboer/phpredisadmin
networks:
- proxy
- youclk
environment:
- REDIS_1_HOST=redis
- REDIS_1_NAME=redis
depends_on:
- redis
deploy:
labels:
- com.df.notify=true
- com.df.port=80
- com.df.serviceDomain=redis.youclk.com
restart_policy:
condition: any
max_attempts: 3
update_config:
delay: 5s
order: start-first
resources:
limits:
cpus: '0.50'
memory: 1g
启动后 UI 展示如下:
如果看过我之前的两篇博文或者对 Compose 有一定了解的话,以上参数一目了然,此处不做过多赘述。
但如果是部署在本地的话,各种 db_service 工具或者是集群外的其他服务也可能需要连接 db,所以得暴露其各自的端口,我倾向于再编写一个 docker-compose.local.yml ,用于放置本地配置,如下:
version: '3.5'
services:
mysql:
ports:
- 3306:3306
volumes:
- /Users/Jermey/Documents/data/db/mysql:/var/lib/mysql
mysql_admin:
deploy:
labels:
- com.df.notify=true
- com.df.port=8080
- com.df.serviceDomain=local-mysql.youclk.com
redis:
ports:
- 6379:6379
redis_admin:
deploy:
labels:
- com.df.notify=true
- com.df.port=80
- com.df.serviceDomain=local-redis.youclk.com
然后再编写一个启动脚本,根据当前的系统环境判断是否合并多个配置文件(我的写法比较粗暴,若有更优雅的方案欢迎留言交流):
if [ -z "`uname -a | grep 'Linux'`" ];then
docker-compose -f ../src/docker-compose.yml \
-f ../src/docker-compose.local.yml \
config > docker-stack.yml
docker stack deploy -c docker-stack.yml --with-registry-auth db
else
docker stack deploy -c ../src/docker-compose.yml --with-registry-auth db
fi
开门见山先说结果吧,最后确认是导致异常的原因是使用 NFS 存储 MySQL 的数据。起初服务一直能非常稳定在我本地的集群中运行,但在测试服务器上却时不时突然挂掉且无法重启,开始的时候一头雾水,本地和测试环境的配置文件完全一致呀,而且都是 Docker Swarm 集群,不应该有任何系统因素相关的干扰。而且它不是启动过后立马会挂,而是运行一段时间之后,期间我发了疯地去排除一个个可能导致 MySQL 宕机的其他服务,而因 NFS 能够正常挂载却被我最先排除(期间的心塞程度有 BUG 经历的工友应当能理解)。
直到我在 MySQL 官网看到了这则申明:
Caution is advised when considering using NFS with MySQL. Potential issues, which vary by operating system and NFS version, include:
Using NFS within a professional SAN environment or other storage system tends to offer greater reliability than using NFS outside of such an environment. However, NFS within a SAN environment may be slower than directly attached or bus-attached non-rotational storage.
If you choose to use NFS, NFS Version 4 or later is recommended, as is testing your NFS setup thoroughly before deploying into a production environment.
官方文档非常直白地警告 NFS 有风险,使用需谨慎。这下总算松了一口气,终于知道问题源头了,反正是测试环境,随便指定 MySQL 挂载集群中一个节点的目录就行。但不死心的我又尝试了下先将 NFS 挂载到主机,然后由 MySQL 容器再去挂载已经挂载了 NFS 的主机目录,现在是已经正常运行好几天了没有再宕机。
Ps:可以将挂载的命令写入初始配置脚本,新服务器到手之后只需执行一行代码就可以愉快地玩耍了,有兴趣可以看我这篇随笔:“Ubuntu 自动化配置”。