首先還是從一個PHP在Docker容器下的Hello World實例開始。我們準備這樣一個PHP文件`index.php`:
~~~
echo "PHP in Docker";
~~~
然后在同目錄下創建文本文件并命名為`Dockerfile`,內容為:
~~~
# 從官方PHP鏡像構建
FROM?????? php
# 將index.php復制到容器內的/var/www目錄下
ADD??????? index.php /var/www
# 對外暴露8080端口
EXPOSE???? 8080
# 設置容器默認工作目錄為/var/www
WORKDIR??? /var/www
# 容器運行后默認執行的指令
ENTRYPOINT ["php", "-S", "0.0.0.0:8080"]
~~~
構建這個容器:
~~~
docker build -t allovince/php-helloworld .
~~~
運行這個容器
~~~
docker run -d -p 8080:8080 allovince/php-helloworld
~~~
查看結果:
~~~
curl localhost:8080
PHP in Docker
~~~
這樣我們就創建了一個用于演示PHP程序的Docker容器,任何安裝過Docker的機器都可以運行這個容器獲得同樣的結果。而任何有上面的php文件和Dockerfile的人都可以構建出相同的容器,從而完全消除了不同環境,不同版本可能引起的各種問題。
想象一下程序進一步復雜,我們應該如何擴展呢,很直接的想法是繼續在容器內安裝其他用到的服務,并將所有服務運行起來,那么我們的Dockerfile很可能發展成這個樣子:
~~~
FROM?????? php
ADD??????? index.php /var/www
# 安裝更多服務
RUN?? ??????? apt-get install -y \
?? ??????? mysql-server \
?? ??????? nginx \
?? ??????? php5-fpm \
?? ??????? php5-mysql
?? ?????? ?
# 編寫一個啟動腳本啟動所有服務
ENTRYPOINT ["/opt/bin/php-nginx-mysql-start.sh"]
~~~
雖然我們通過Docker構建了一個開發環境,但覺不覺得有些似曾相識呢。沒錯,其實這種做法和制作一個虛擬機鏡像是差不多的,這種方式存在幾個問題:
- 如果需要驗證某個服務的不同版本,比如測試PHP5.3/5.4/5.5/5.6,就必須準備4個鏡像,但其實每個鏡像只有很小的差異。
- 如果開始新的項目,那么容器內安裝的服務會不斷膨脹,最終無法弄清楚哪個服務是屬于哪個項目的。