以 Laravel 為例,來 build image 吧!
Laravel 是目前 PHP 很流行的框架,今天以看到 Laravel 的預設歡迎頁為目標,建置 Laravel image。
初始化 Laravel
首先一開始,要先把 Laravel 主程式先準備好。參考 Installing Laravel 文件,安裝 PHP 7.3 與 Composer,然後執行下面指令即可把 Laravel 程式安裝至 blog
目錄。
composer create-project --prefer-dist laravel/laravel blog |
接著進 blog 目錄啟動 server:
cd blog |
完成後,看到 Laravel 的預設歡迎頁,程式碼就準備完成了。
事前準備
先定義 Docker 要下什麼指令,會達到跟官方執行 php artisan serve
一樣的結果:
docker run --rm -it -p 8000:8000 laravel |
轉換成 docker-compose.yml
如下:
version: "3.8" |
其中 -p 8000:8000
是配合預設開 8000 port;image 取名為 laravel
。
撰寫 Dockerfile
的過程中,會不斷重複啟動與移除 container 測試,可以用下面 Makefile
來簡化指令,示範和說明也比較清楚一點:
#!/usr/bin/make -f |
Dockerfile 的第一手
寫 Dockerfile
跟 TDD 一樣有三循環如下:
- 新增 Dockerfile 指令
- 執行
docker build
並驗證是否正確 - 最佳化 Dockerfile
撰寫 Dockerfile
的第一手,是先寫一個可以驗證成功的 Dockerfile
,後續就可以走上面的三循環。
昨天範例有提到 FROM
也是一個步驟。只要 image 在 DockerHub 能下載得到,Dockerfile
就能 build 成功,我們可以寫一個只有 FROM
的 Dockerfile
。Laravel 官網的 Server Requirements 要求 PHP >= 7.3,因此我們使用 php:7.3
image:
FROM php:7.3 |
接著執行 make build
與 make shell
試看看:
make build |
建置完成,並在 commit 上 tag laravel
,同時進去 shell 確認 PHP 版本正確。
註:目前
laravel
tag 與php:7.3
tag 在同個 commit 上。
設定路徑與原始碼
預設的路徑是根目錄 /
,是個一不小心就會刪錯檔案的位置,可以換到一個比較安全的目錄,比方說 /source
:
WORKDIR /source |
WORKDIR
可以設定預設工作目錄。它同時是docker build
過程與docker run
的工作目錄,跟-w
選項的意義相同。
接著把 Laravel 原始碼複製進 container 裡,這裡使用 COPY
指令:
COPY . . |
COPY
是把本機的檔案複製到 container 裡,使用方法為COPY [hostPath] [containerPath]
要注意這裡有個雷,單一檔案複製沒有問題,但目錄複製就得小心。它的行為跟 Linux 常見的 cp
不大一樣。
cp -r somedir /some/path |
以 cp
指令來說,上面指令執行完會多一個目錄 /some/path/somedir
。
COPY somedir /container/path |
以 COPY
指令來說,上面兩個指令是等價的。原本預期會多一個 /container/path/somedir
目錄,實際上是 somedir
目錄裡所有東西全複製到 /container/path
下。
解決方法是改成下面這個指令:
COPY somedir /container/path/somedir |
設定啟動 server 指令
Docker Compose 裡有提到一個設定是 command
,它定義了 container 啟動預設會執行的指令。Dockerfile
也有一樣用法的指令--CMD
。而啟動 server 指令一開始 Laravel 建好的時候已經知道了,php artisan serve
。
套用在 CMD
指令上的用法會有兩種如下:
# exec 模式,官方推薦 |
未來會再解釋這兩個模式的差異,先用官方推薦來試試。
實際執行的時候會發現不能正常連到 server?原因很簡單,在說明 Port forwarding 的時候,曾用了下面這張圖:
當時提到每個 container 有屬於自己的 port,因為每個 container 都是獨立的個體,包括 host 也是一個獨立的個體。
再回頭看 Laravel 啟動 server 的資訊,它綁定了 127.0.0.1:8000
在 container 上。
Starting Laravel development server: http://127.0.0.1:8000 |
不能連線的原因其實非常單純,host 與 container 要視為兩台不一樣的機器,因為 container 僅綁定本機--也就是只有進 container 使用 curl http://127.0.0.1:8000
可以連線,而 host 連 container 會被視為外部連線,因此會連線失敗。
解決方法很單純,把綁定 IP 調整即可,下例是以 0.0.0.0
全部開放為例:
CMD ["php", "artisan", "serve", "--host", "0.0.0.0"] |
建置服務成功!測試也完成了,恭喜大家成功用 Dockerfile
建置 Laravel image 成功!
今日自我回顧
今天 Dockerfile
最後長相如下:
FROM php:7.3 |
目前這個內容有很多缺陷,接下來會開始做 Dockerfile
最佳化,會一步步讓讀者知道更多 image 與 container 相關的技巧。
- 了解 build image 的流程
- 演練實際程式 build image