天天看點

基于 Docker 的 PHP 開發環境基于 Docker 的 PHP 開發環境

【編者的話】本文作者是geoffrey,他是一個php的web開發者,喜歡devops和docker。本文主要介紹了如何使用docker建構 php的開發環境,文中作者也探讨了建構基于docker的開發環境應該使用單容器還是多容器,各有什麼利弊。推薦php開發者閱讀。

基于 Docker 的 PHP 開發環境基于 Docker 的 PHP 開發環境

現在很多開發者都使用vagrant來管理他們的虛拟機開發環境,vagrant确實很酷, 不過也有不少缺點(最主要的是它占用太多的資源)。在容器技術、docker和更多類docker技術出現後,解決這個問題就變得簡單了。

<a target="_blank"></a>

由于boot2docker的工作方式,本文所述的方法在你的環境中可能無法正常運作。如果需要在非linux環境下共享檔案夾到docker容器,還需要注意更多額外的細節。後續我會寫篇文章專門來介紹實際遇到的問題。

首先,我們得知道什麼才是好的開發環境, 對于我而言,一個好的開發環境需要具備以下幾個特點:

可随意使用。我必須可以随意删除和建立新的環境。

快速啟動。我想要用它工作時候,它立馬就能用。

易于更新。在我們行業中,事物發展變化非常快,必須能讓我很容易将我的開發環境更新到新的軟體版本。

而docker都支援以上這些特點,甚至更多。你幾乎可以即時銷毀和重建容器,而更新環境隻需要重建你目前使用的鏡像即可。

目前web應用錯綜複雜,php開發環境需要很多的東西,為了保證環境的簡單性,需要做各種各樣的限制。

我們這次使用nginx、php5-fpm、mysql來運作synmfony項目。由于在容器中運作指令行會更複雜,是以這方面的内容我會放到下一篇部落格中再說。

另一個我們要讨論的重點是:我們要把開發環境部署在多容器還是單容器中。 兩種方式各有優點:

單容器易于分發、維護。因為它們是獨立的,所有的東西都運作在同一個容器中,這點就像是一個虛拟機。但這也意味着,當你要更新其中的某樣東西(比如php新版本)的時候, 需要重新建構整個容器。

多容器可以在添加元件時提供更好的子產品化。因為每個容器包含了堆棧的一部分:web、php、mysql等,這樣可以單獨擴充每個服務或者添加服務,并且不需要重建所有的東西。

因為我比較懶,加上我需要在我的筆記本上放點别的内容,是以,這裡我們隻介紹單個容器的方法。

不管怎麼樣,你可以讀一下。接下來如果還沒有composer指令的話,你可以建立一個屬于自己的composer 别名。

現在你可以初始化symfony工程了:

帥呆了!下面來點實在的工作。(省略了部落客自娛自樂的一堆balabla....原文:awesome. give yourself a high-five, get a cup of coffee or whatever is your liquid drug of choice, and get ready for the real work.)

建構一個運作标準symfony項目且自給自足的容器相當容易,隻需要安裝好常用的nginx、php5-fpm和mysql-server即可,然後把預先準備好的nginx的虛拟主機配置檔案扔進去,再複制一些配置檔案進去就完事了。

我們通過擴充 debian:wheezy 這個基礎鏡像開始,然後通過一系列的sed指令來配置nginx和php5-fpm。

這裡我們要做兩件事。 首先配置php5-fpm和nginx讓他們在前台運作以便supervisord可以追蹤到他們。

然後,配置php5-fpm以指定的使用者運作web-server,并處理好檔案權限。

接下來需要安裝一組配置檔案,首先是nginx的虛拟主機配置檔案vhost.conf:

因為我們不需要域名,是以把server_name設成了_(有點像perl的$_占位符變量), 并配置根目錄(document root)為/svr/web, 我們會把應用程式部署在/srv下,剩下的就是标準的mginx + php5-fpm配置.

因為一個容器每次隻能運作一個程式, 我們需要supervisord(或者任何别的程序管理器,不過我比較中意supervisord)。幸運的是, 這個程序管理器會産生我們需要的所有程序!下面是一小段supervisord的配置:

這裡我們需要做的是定義所有的服務, 加上一個特殊的program:init程序,它不是一個實際的服務,而是一個獨創的運作啟動腳本的方式。

這個啟動腳本的問題在于,它通常需要先啟動某些服務。比如,你可能要初始化一些資料庫表,但前提是你得先把mysql跑起來,一個可能的解決辦法 是,在啟動腳本中啟動mysql,然後初始化表,然後為了防止影響到supervisord的程序管理,需要停掉mysql,最後再啟動 supervisord。

這樣的腳本看起來類似下面這樣:

看起來醜爆了有木有,咱換種方式,讓supervisor來運作它并且永不重新開機。

實際的init.sh腳本如下:

腳本先等待mysql啟動,然後根據環境變量db_name建立db,預設為symfony, 然後在init環境變量中查找要運作的腳本,并嘗試運作它。本文的結尾有說明如何使用這些環境變量。

萬事俱備隻欠東風。我們還要建構symfony docker鏡像, 使用docker build指令:

現在,可以使用它來運作你的symfony工程了:

我們來看看這一連串的選項分别是幹嘛的:

-i 啟動互動(interactive)模式, 也就是說,stdio(标準輸入輸出)連接配接到了你目前的終端上。當你要接收日志或者給程序發送信号時,它很有用。

-t 為容器建立一個虛拟tty, 它跟-i是好基友,通常一起使用。

-p 告訴docker守護程序釋出所有指定的端口, 本例中為80端口。

-v $pwd:/srv 把目前目錄挂載到容器的/srv目錄。挂載一個目錄使得目錄内容對目标挂載點可用。

現在你還記得之前提到的db_name和init環境變量了吧,幹嘛用的呢:用于自定義你的環境。 基本上你可以通過 docker run的-e選項在容器中設定環境變量,啟動腳本會拿到環境變量,是以,如果你的db名為some_project_dev, 你就可以這麼運作容器:

init 環境變量就更強大了,它允許你啟動時運作指定的腳本。比如, 你有一個bin/setup腳本運作composer install指令并且設定資料庫schema:

用-e來運作它:

注意,-e選項可以在docer run中多次使用,看起來相當酷。另外,你的啟動腳本需要可執行權限(chmod +x)。

現在我們通過curl發送請求到容器,來檢查一下是否所有的東西都像預期一樣工作。首先,我們需要取到docker映射到容器的80端口的公共端口,用docker port指令:

docker ps -aql 1 是個好用的指令,可以友善的檢索到最後一個容器的id, 在我們的例子中,docker 把容器的80端口映射到了49153端口。我們 curl 一下看看。

當我們不從localhost(譯者注:容器的localhost)通路dev controller時,得到了symfony的預設錯誤消息,這再正常不過了, 因為我們不是從容器内部發送 curl 請求的, 是以,可以安全的從前端控制器web/app_dev.php中移除這些行。

這些行阻止了任何從localhost以外的地方通路dev controller。

基于 Docker 的 PHP 開發環境基于 Docker 的 PHP 開發環境

很容易吧! 現在我們可以快速的啟動、更新環境了,但還是有很多地方需要改進。

result.png

原文釋出時間:2014-01-05

本文來自雲栖合作夥伴“linux中國”