前言
本篇隨筆是繼 “Docker Engine” 與 “Compose & Swarm” 之后的一個實例補充,初衷是記錄測試環境中的一次 MySQL 事故,就當做 “Docker 系列” 的一個小收尾吧。其實在生產環境中不推薦使用 Docker 部署 MySQL 和 Redis,那可是 The First Domino,倒一個掛一片呀,不過在本地和測試環境中就隨意了。
1. 部署准備
一般部署這些 db_service 容器都應該配套其管理工具(我不否認可以通過命令行完成所有的操作,而且功能更多,權限更大,但是非 DBA 的童鞋還是乖乖使用 UI 吧,耍酷浪費太多時間也不值當🤣),因此,這里我選擇的鏡像組合是 mysql、adminer 與 redis、erikdubbelboer/phpredisadmin。
Ps:這節太短了,就插一些題外話吧。現在爽 Docker 的同時其實也在為過去的自己默哀,想當年初入編程的時候還沒普及雲服務器和各種打包好的雲服務方案,當然也沒有 Docker,想做點什么實驗和測試都得在本機。本本性能不行還得一天到晚折騰各種安裝環境,就拿 db_service 來說吧,當時選擇的是 SQL Server,流行的版本是 05、08 和 08 r2 等,客戶要求啥版本的都有。那開發的時候得在本地裝呀,要命的是這家伙根本無法徹底卸載,版本之間還有兼容問題,啥錯誤都遇到過,解決不了最后的終極方案就是重裝系統,然后呢... 還得再裝呀... 這一下子就是半天到一天的時間。使用虛擬機吧,打開幾個 IDE 再啟動幾個虛擬機,不要說那時候了,就是現在的主流機也扛不動呀,編程體驗幾乎為零。這里算是憶苦思甜了,想想那時候,現在簡直太幸福了。
2. 配置
adminer 與 phpredisadmin 都可以在集群內訪問需要代理的服務,如果是在服務器上也不用額外暴露 3306 和 6379 端口,以下是我的 docker-compose 配置:
MySQL
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
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
3. MySQL 異常事故記錄
開門見山先說結果吧,最后確認是導致異常的原因是使用 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:
- MySQL data and log files placed on NFS volumes becoming locked and unavailable for use. Locking issues may occur in cases where multiple instances of MySQL access the same data directory or where MySQL is shut down improperly, due to a power outage, for example. NFS version 4 addresses underlying locking issues with the introduction of advisory and lease-based locking. However, sharing a data directory among MySQL instances is not recommended.
- Data inconsistencies introduced due to messages received out of order or lost network traffic. To avoid this issue, use TCP with hard and intr mount options.
- Maximum file size limitations. NFS Version 2 clients can only access the lowest 2GB of a file (signed 32 bit offset). NFS Version 3 clients support larger files (up to 64 bit offsets). The maximum supported file size also depends on the local file system of the NFS server.
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 自動化配置”。
結語
編程的樂趣非程序員不能體會,一行行代碼造就了這繽紛多彩的世界,而且其最大的魅力在於我們的產品復用幾乎是無成本的。也正因如此,無論我現今生活質量如何,我都能始終懷揣帶有一些夢幻色彩的理想,並為之奮斗。而程序員的悲哀也非他人能輕易理解,你可能認為你在處理一個偉大的問題,到頭來,可能僅僅是一個符號在作祟。本篇隨筆抒情的廢話比較多,感謝閱讀 😃
我的公眾號《有刻》,我們共同成長!