使用Docker部署PHP應用的設計方案

1. Docker

Docker的官方定義是:php

Docker allows you to package an application with all of its dependencies into a standardized unit for software development.html

-- https://www.docker.com/whatisdockermysql

毫無疑問的是,Docker解決了應用部署上一個巨大的問題:linux

客戶: 安裝好了,用不了。git

發佈者:個人機器上沒問題。
github

如何解決每一個應用的依賴在Docker出現以前是個頭疼的問題,如今僅僅經過一次配置,Dockerfile或者image做爲最終交付,就能在任何Linux上完美運行了。提及來很簡單的樣子,但在Docker配置過程當中,又存在不少值得思考的問題:應用各個組件如何安排?一個Container解決問題仍是細化Container?Container之間何如通訊?等等。。下面用一個最廣泛的WEB應用配置部署來講明這些問題。sql

NOTE:本文假定讀者對Docker中的一些概念有基本的認識,若是不甚瞭解,我推薦這篇文章:docker

https://linux.cn/article-6074-weibo.htmlshell

2. LNMP

典型的PHP應用配置方案是LAMP或者LNMP,本文以LNMP爲例。安全

設計方案以下圖(我已經實現並運行於 https://apporz.com):

應用由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這種設計的優缺點:

  1. 容器間的耦合性增大。能夠看到PHP-FPM容器和另外三個容器間有耦合關係,MySQL容器最獨立。

  2. 雖然耦合性比較大,但這種端口耦合,文件系統耦合關係能夠經過增長几個運行選項解決掉,後面有介紹。

  3. 因爲容器對整個架構的劃分,使得容器中的內容變得十分獨立和安全。例如,我但願在線上更新WWW中的代碼,只須要進入WWW容器作修改,不會影響到Nginx,PHP-FPM或者是MySQL。

  4. 各容器可靈活拆卸更換,好比我想把MySQL換成Mongodb,或者乾脆把業務代碼搬個家,不會影響到其餘容器(僅僅更改相關配置文件)

  5. 因爲各容器經由官方的鏡像建立,所以能夠隨時花最少的代價使用最新的官方鏡像嚐鮮。

  6. 佔用空間會比較大,一個簡單的應用要這麼作的話,四個鏡像會佔用大量的存儲空間。

2.1 容器間通訊問題

細化Container面臨着另外一個問題,就是如何進行容器間通訊。下面簡要描述一下上圖中的數據流程:

  1. 客戶端的http請求達到server的80端口,該端口被映射到Nginx Container的80端口,所以進入Nginx處理。Nginx會分析請求資源,斷定是靜態資源仍是php腳本,若是是靜態資源,則直接從WWW中取出發回客戶端;若是是腳本程序,則要告訴PHP-FPM到WWW獲取相應腳本,而後經過php-cgi處理。

  2. fast-cgi經過php執行腳本,必要時訪問MySQL存取數據。

這樣耦合關係就出來了:

  1. Nginx須要鏈接PHP-FPM開放的9000端口,須要訪問WWW中的文件系統。

  2. 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/

所以容器啓動的前後順序就出來了:

  1. MySQL Container

  2. WWW Container (因爲沒有任何服務運行,容器run後會當即exit,可使用 tail -f 等block命令使容器保持運行不退出)

  3. PHP-FPM Container

  4. 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兩天後的心得體會,紕漏在所不免,若有錯誤還請斧正。

相關文章
相關標籤/搜索