起因
Docker算是現在非常火的一個項目,但筆者對其一直不怎么感冒,畢竟沒啥使用場景。只是最近,筆者需要在自己的mac電腦上面安裝項目的開發環境,發現需要安裝MySQL,LedisDB,xcodis,Redis,Zookeeper等一堆東西,而同樣的流程仍然要在Windows的機器上面再來一遍,陡然覺得必須得有一個更好的方式來管理整個項目的開發環境了。自然,筆者將目光放到了Docker上面。
根據官方自己的介紹,Docker其實是一個為開發和運維人員提供構建,分發以及運行分布式應用的開源平臺(野心真的不小,難怪CoreOS要新弄一個Rocket來跟他競爭的)。
Docker主要包括Docker Engine,一個輕量級的運行和包管理工具,Docker Hub,一個用來共享和自動化工作流的云服務。實際在使用Docker的工程中,我們通常都是會在Docker Hub上面找到一個base image,編寫Dockerfile,構建我們自己的image。所以很多時候,學習使用Docker,我們僅需要了解Docker Engine的東西就可以了。
至于為啥選用Docker,原因還是很明確的,輕量簡單,相比于使用VM,Docker實在是太輕量了,筆者在自己的mac air上面同時可以運行多個Docker container進行開發工作,而這個對VM來說是不敢想象的。
后面,筆者將結合自己的經驗,來說說如何構建一個MySQL Docker,以及當中踩過的坑。
MySQL Docker
筆者一直從事MySQL相關工作的開發,對于MySQL的依賴很深,但每次安裝MySQL其實是讓筆者非常頭疼的一件事情,不同平臺安裝方式不一樣,加上一堆設置,很容易就把人搞暈了。所以自然,我的Docker第一次嘗試就放到了MySQL上面。
對于mac用戶,首先需要安裝boot2docker這個工具才能使用Docker,這個工具是挺方便的,但也有點坑,后續會說明。
筆者前面說了,通常使用Docker的方式是在Hub上面找一個base image,雖然Hub上面有很多MySQL的image,但筆者因為開發go-mysql,需要在MySQL啟動的時候傳入特定的參數,所以決定自行編寫Dockerfile來構建。
首先,筆者使用的base image為ubuntu:14.04,Dockerfile文件很簡單,如下:
FROM ubuntu:14.04
# 安裝MySQL 5.6,因為筆者需要使用GTID
RUN apt-get update \
&& apt-get install -y mysql-server-5.6
# 清空apt-get的cache以及MySQL datadir
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /var/lib/mysql
# 使用精簡配置,主要是為了省內存,筆者機器至少要跑6個MySQL
ADD my.cnf /etc/mysql/my.cnf
# 這里主要是給mysql_install_db腳本使用
ADD my-default.cnf /usr/share/mysql/my-default.cnf
# 增加啟動腳本
ADD start.sh /start.sh
RUN chmod +x /start.sh
# 將MySQL datadir設置成可外部掛載
VOLUME ["/var/lib/mysql"]
# 導出3306端口
EXPOSE 3306
# 啟動執行start.sh腳本
CMD ["/start.sh"]
我們需要注意,對于MySQL這種需要存儲數據的服務來說,一定需要給datadir設置VOLUMN,這樣你才能存儲數據。筆者當初就忘記設置VOLUMN,結果啟動6個MySQL Docker container之后,突然發現這幾個MySQL使用的是同一份數據。
如果有VOLUMN, 我們可以在docker run
的時候指定對應的外部掛載點,如果沒有指定,Docker會在自己的vm目錄下面生成一個唯一的掛載點,我們可以通過docker inspect
命令詳細了解每個container的情況。
對于start.sh
,比較簡單:
- 判斷MySQL datadir下面有沒有數據,如果沒有,調用
mysql_install_db
初始化。 - 允許任意ip都能使用root賬號訪問,
mysql -uroot -e "GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '' WITH GRANT OPTION;"
,否則我們在外部無法連接MySQL。 - 啟動mysql
構建:
docker build -t siddontang/mysql .
構建好了MySQL Docker image,我們就能使用docker run
來運行了:
docker run -d -p 3306:3306 --name=mysql siddontang/mysql:latest
這里,我們基于siddontang/mysql這個image創建了一個名叫mysql的container并運行,它會調用start.sh
腳本來啟動MySQL。
而我們通過docker stop mysql
就可以停止mysql container了。
如果筆者需要運行多個MySQL,僅僅需要多新建幾個container并運行就可以了,當然得指定對應的端口。可以看到,這種方式非常的簡單,雖然使用mysqld_multi
也能達到同樣的效果,但是如果我需要新增一個MySQL實例,mysqld_mutli
還需要去更改配置文件,以及在對應的MySQL里面設置允許mysqld_multi stop
的權限,其實算是比較麻煩的。而這些,在Docker里面,一個docker run
就搞定了。
完整的構建代碼在這里,mysql-docker,你也可以pull筆者提交到Hub的image siddontang/mysql
來直接使用docker pull siddontang/mysql:latest
。
Boot2Docker Pitfall
從前面可以看到,Docker的使用是非常方便的,但筆者在使用的時候仍然碰到了一點坑,這里記錄一下。
IP
最開始碰到的就是ip問題,筆者在run的時候做了端口映射,但是外部使用MySQL客戶端死活連接不上,而這個只在筆者mac上面出現,linux上面正常,后來發現是boot2docker的問題,我們需要使用boot2docker ip
返回的ip來訪問container,在筆者的機器上面,這個ip為192.168.59.103。
Volumn
仍然是boot2docker的問題,筆者在docker run
的時候,使用-v
來將外部的目錄綁定到datadir這個VOLUMN上面,這個在linux上面是成功的,可是在mac上面,筆者發現mysql_install_db
死活沒有權限寫入磁盤。后來才知道,boot2docker只允許對自己VM下面的路徑進行綁定。鑒于在mac下面僅僅是調試,數據不許持久化保存,這個問題也懶得管了。反正只要不刪除掉container,數據還是會在的。
Flatten Image
在使用Dockerfile構建自己的image的時候,對于Dockerfile里面的每一步,Docker都會生成一個layer來對應,也就是每一步都是一次提交,到最后你會發現,生成的image非常的龐大,而當你push這個image到Hub上面的時候,你的所有layer都會提交上去,加之我們國家的網速水平,會讓人崩潰的。
所以我們需要精簡生成的image大小,也就是flatten,這個Docker官方還沒有支持,但至少我們還是有辦法的:
-
docker export
anddocker import
,通過對特定container的export和import操作,我們可以生成一個無歷史的新container,詳見這里。 - docker-squash,很方便的一個工具,筆者就使用這個進行image的flatten處理。
后記
總的來說,Docker還是很容易上手的,只要我們熟悉了它的命令,Dockerfile的編寫以及相應的運行機制,就能很方便的用Docker來進行團隊的持續集成開發。而在生產環境中使用Docker,筆者還沒有相關的經驗,沒準后續私有云會采用Docker進行部署。
后續,對于多個Container的交互,以及服務發現,擴容等,筆者也還需要好好研究,CoreOS沒準是一個方向,或者研究下rocket :-)