1. Docker
Docker的官方定義是:
Docker allows you to package an application with all of its dependencies into a standardized unit for software development.
-- https://www.docker.com/whatisdocker
毫無疑問的是,Docker解決了應用部署上一個巨大的問題:
客戶: 安裝好了,用不了。
釋出者:我的機器上沒問題。
如何解決每個應用的依賴在Docker出現之前是個頭疼的問題,現在僅僅通過一次配置,Dockerfile或者image作為最終傳遞,就能在任何Linux上完美運作了。說起來很簡單的樣子,但在Docker配置過程中,又存在很多值得思考的問題:應用各個元件如何安排?一個Container解決問題還是細化Container?Container之間何如通信?等等。。下面用一個最普遍的WEB應用配置部署來說明這些問題。
NOTE:本文假定讀者對Docker中的一些概念有基本的認識,如果不甚了解,我推薦這篇文章:
https://linux.cn/article-6074-weibo.html
2. LNMP
典型的PHP應用配置方案是LAMP或者LNMP,本文以LNMP為例。
設計方案如下圖(我已經實作并運作于 https://apporz.com):
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLwQTOwgTNfRXYMR0XyQTNyAjMvwVMwkDMvwVNxAjMvwVZjFGcz9CXzRWYvxGc19CX0VmbuEmbph2Yz9mLjlGdhR3cvw1LcpDc0RHaiojIsJye.png)
應用由4個元件組成,分别是Nginx,PHP-FPM(PHP),MySQL以及WWW,4個元件運作在由各自鏡像建立出來的獨立的容器中。其中WWW Container隻是一個存儲業務代碼和靜态資源的容器,可以認為是"死"的。
事實上LNMP架構采用上面的設計方式應該是最容易想到的,也是最清晰的,每個元件有相對的獨立性。其中除了WWW容器,其他3個容器都可以直接通過官方鏡像建構出來。
然而網上很多同學并不是這樣做的,不會分的這麼細,通常是把Nginx和WWW放到一個容器内,或者幹脆全部放到一個容器中。可以學習一下大家的Dockerfile:
https://github.com/search?utf8=✓&q=docker-lnmp
細化Container這種設計的優缺點:
- 容器間的耦合性增大。可以看到PHP-FPM容器和另外三個容器間有耦合關系,MySQL容器最獨立。
- 雖然耦合性比較大,但這種端口耦合,檔案系統耦合關系可以通過增加幾個運作選項解決掉,後面有介紹。
- 由于容器對整個架構的劃分,使得容器中的内容變得十分獨立和安全。例如,我希望線上上更新WWW中的代碼,隻需要進入WWW容器做修改,不會影響到Nginx,PHP-FPM或者是MySQL。
- 各容器可靈活拆卸更換,比如我想把MySQL換成Mongodb,或者幹脆把業務代碼搬個家,不會影響到其他容器(僅僅更改相關配置檔案)
- 由于各容器經由官方的鏡像建立,是以可以随時花最少的代價使用最新的官方鏡像嘗鮮。
- 占用空間會比較大,一個簡單的應用要這麼做的話,四個鏡像會占用大量的存儲空間。
2.1 容器間通信問題
細化Container面臨着另一個問題,就是如何進行容器間通信。下面簡要描述一下上圖中的資料流程:
- 用戶端的http請求達到server的80端口,該端口被映射到Nginx Container的80端口,是以進入Nginx處理。Nginx會分析請求資源,判定是靜态資源還是php腳本,如果是靜态資源,則直接從WWW中取出發回用戶端;如果是腳本程式,則要告訴PHP-FPM到WWW擷取相應腳本,然後通過php-cgi處理。
- fast-cgi通過php執行腳本,必要時通路MySQL存取資料。
這樣耦合關系就出來了:
- Nginx需要連接配接PHP-FPM開放的9000端口,需要通路WWW中的檔案系統。
- PHP-FPM也需要通路WWW中的檔案系統,還要通路MySQL的3306端口。
2.2 解決問題
可以看出有兩類耦合關系:端口和檔案系統。
對于端口耦合,docker是通過--link選項解決的;對于檔案系統耦合,docker是通過--volumes-from選項解決的。
解決第一個耦合關系:
$ sudo docker run -p 80:80 -p 443:443 # 主機端口映射到容器
--volumes-from WWW_CONTAINER_NAME # 把WWW容器VOLUME過的檔案夾挂載到将啟動的容器上
--link PHP_FPM_CONTAINER_NAME:fpmservice # 冒号前是正在運作的FPM容器名稱,後面是别名,别名會作為hostname在将啟動的容器内可見
-d # detach
NGINX_IMAGE # 鏡像名
解決第二個耦合關系:
$ sudo docker run --volumes-from WWW_CONTAINER_NAME
--link MYSQL_CONTAINER_NAME:mysql
-d
PHP_FPM_IMAGE
參考文檔:https://docs.docker.com/reference/run/
是以容器啟動的先後順序就出來了:
- MySQL Container
- WWW Container (由于沒有任何服務運作,容器run後會立即exit,可以使用 tail -f 等block指令使容器保持運作不退出)
- PHP-FPM Container
- Nginx Container
其中1和2可以對換。
3. Dockerfile
Dockerfiles 請參見:
https://github.com/micooz/dockerfile
http://git.oschina.net/micooz/dockerfile
4. 總結
利用Docker部署Web應用可以帶來很多便利,在宏觀上實作應用元件化,為實作分布式系統奠定了基礎。
可以看到實際上在Docker容器間共享資料是很友善的,搞清楚各容器的依賴關系就不難解決。
P.s. 本文是我學習docker兩天後的心得體會,纰漏在所難免,如有錯誤還請斧正。
版權聲明:本文為CSDN部落客「weixin_34166472」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_34166472/article/details/91871085