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

jopen 9年前發布 | 15K 次閱讀 Docker

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

</blockquote>

毫無疑問的是,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為例。

設計方案如下圖(我已經實現并運行成功的案例):

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

應用由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容器最獨立。

    </li>

  2. 雖然耦合性比較大,但這種端口耦合,文件系統耦合關系可以通過增加幾個運行選項解決掉,后面有介紹。

    </li>

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

    </li>

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

    </li>

  5. 由于各容器經由官方的鏡像創建,因此可以隨時花最少的代價使用最新的官方鏡像嘗鮮。

    </li>

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

    </li> </ol>

    2.1 容器間通信問題

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

    1. 客戶端的http請求達到server的80端口,該端口被映射到Nginx Container的80端口,因此進入Nginx處理。Nginx會分析請求資源,判定是靜態資源還是php腳本,如果是靜態資源,則直接從WWW中取出發回客戶端;如果是腳本程序,則要告訴PHP-FPM到WWW獲取相應腳本,然后通過php-cgi處理。

      </li>

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

      </li> </ol>

      這樣耦合關系就出來了:

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

        </li>

      2. PHP-FPM也需要訪問WWW中的文件系統,還要訪問MySQL的3306端口。

        </li> </ol>

        2.2 解決問題

        可以看出有兩類耦合關系:端口和文件系統。

        對于端口耦合,docker是通過--link選項解決的;對于文件系統耦合,docker是通過--volumes-from選項解決的。

        解決第一個耦合關系:

        $ sudo docker run -p 80:80 -p 443:443  # 主機端口映射到容器
        --volume-from WWW_CONTAINER_NAME  # 把WWW容器VOLUME過的文件夾掛載到將啟動的容器上
        --link PHP_FPM_CONTAINER_NAME:fpmservice  # 冒號前是正在運行的FPM容器名稱,后面是別名,別名會作為hostname在將啟動的容器內可見
        -d  # detach
        NGINX_IMAGE  # 鏡像名

        解決第二個耦合關系:

        $ sudo docker run --volume-from WWW_CONTAINER_NAME
        --link MYSQL_CONTAINER_NAME:mysql
        -d
        PHP_FPM_IMAGE

        參考文檔:https://docs.docker.com/reference/run/

        因此容器啟動的先后順序就出來了:

        1. MySQL Container

          </li>

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

          </li>

        3. PHP-FPM Container

          </li>

        4. Nginx Container

          </li> </ol>

          其中1和2可以對換。

          3. 總結

          利用Docker部署Web應用可以帶來很多便利,在宏觀上實現應用組件化,為實現分布式系統奠定了基礎。

          可以看到實際上在Docker容器間共享數據是很方便的,搞清楚各容器的依賴關系就不難解決。

          來自:http://my.oschina.net/ybusad/blog/499013

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!