Docker 學習的道路真的是學無止盡,以下筆者列出三十天裡沒有提到的東西,有興趣的讀者可以用關鍵字查詢。
最後,來個小測驗考考大家是不是對 Docker 更了解:
第一題的答案是 (A)
A 描述錯誤:docker run
可以基於 image 產生 container,所以第一句話是正確的;相對地,docker commit
可以藉由 container 產生 image,所以第二句話是錯誤的。
B 描述正確:docker run <IMAGE ID>
指令中, 為 SHA256 digest,同個 digest 的內容無法改變。而 container 內容則是可變的,比方說進入 Nginx container 新增 HTML 檔,即可立刻使用瀏覽器看到內容。
C 描述正確:Image 上 run 一個 container 時,可以使用 docker rmi -f <IMAGE ID>
強制把 image 移除。雖然無法再使用該 Digest 再次啟動 container,但實際上 image 內容依然是存在的,因為重新 pull image 會發現 Already exists
的關鍵字。實際測試指令如下:
$ docker run php:7.4 php -v
Unable to find image 'php:7.4' locally
7.4: Pulling from library/php
...
$ docker rmi -f php:7.4
Untagged: php:7.4
Untagged: php@sha256:...
Deleted: sha256:...
$ docker pull php:7.4
7.4: Pulling from library/php
xxxxxxxxxxxx: Already exists
xxxxxxxxxxxx: Already exists
...
了解 image 與 container 的關係後,才能進一步了解 Docker 是如何建置、如何加速建置、啟動 container 等。
第二題的答案是:(C)
此題目要考慮下列兩件事:
A 與 B 很明顯正確,container 因為少了 OS 層,當然啟動速度與記憶體使用量,都相較 VM 來的有優勢。
C 假設過去 VM 習慣使用 Ubuntu 或是任一種 OS,現在 container 是否必須要用相同的 OS 才能正常運行(VM 跟 Container 也可以交換反過來看)?答案當然是「非必要」的,如官方 Redis image 就提供了 Debian 和 Alpine 等選擇,即使作業系統不一樣,只要把程式或設定做好,系統一樣能正常運作。
Container 用起來跟 VM 很類似,但要記得它們本質是不同的。而不管 VM 或 container 都得經過調校才能發揮最大的優勢。
第三題的答案是:(C)
A 與 B 其實是差不多的,差別是 B 會把 container 砍掉。
C 很明顯是不能做的。進去安裝 Vim 或相關除錯工具明顯錯誤就不提了,如果是為了看 log,參考 12 Factor Logs,它應該能在其他地方查得到,而不是進 container 查;如果是進去調整參數等行為,則會不符合 12 Factor Build, release, run 嚴格分離的原則。
現在 container 都是交由 Kubernetes 等 container orchestration 系統負責這些維運任務,但開發者也有必要了解這類問題的處理方法,才有辦法寫出符合 container 架構的程式。
一次性的特色可以參考 Create ephemeral containers。
第四題的答案是:(A)
參考 Decouple applications,Docker 官方是這麼說的:
Limiting each container to one process is a good rule of thumb, but it is not a hard and fast rule.
上面五種 container,唯獨 Apache with PHP-FPM(FastCGI)container 是比較不符合的,因為它必須啟動做兩件不同任務的 process。可以注意到在 DockerHub 找到類似的 image 的 CMD,都必須要使用 Supervisor 或類似的工具來管理 process。
順帶一提,官方也沒有提供 Apache + PHP-FPM 或 Nginx + PHP-FPM 的 image,而是提供只有 PHP-FPM 的 image,或是 Apache + PHP-CGI 的 image。
這概念與 SOLID 裡 SRP 的優點一樣:只做一件事,架構不會複雜,除錯會更容易。
第四題的答案是:(E)
A 的問題:部署上線後居然可以跑單元測試?這代表測試程式碼和單元測試套件也一併被部署上線,這不符合 Don’t install unnecessary packages。
正確的做法:在建置 image 前或是 Use multi-stage builds 在一開始的階段做單元測試,最終僅部署做完單元測試後的程式碼。
相對地,部署上線後,可以做冒煙測試(smoke testing)。
B 的問題:VOLUME 官方不建議用來放程式,而是放額外要保存的資料,如 MySQL 的 Dockerfile 就有設定 VOLUME /var/lib/mysql
是存放資料庫檔案。
正確的做法:程式上線應該透過建置新的 image,跑新的 container 來取代舊的。
可以試著反過來思考,為何我們會覺得 Docker 上跑 MySQL / Redis / Apache 很快速方便?因為它們把程式都包在 image 裡了。
C 的問題:「把機敏資訊加入 image 裡」這句話的意思就是,只要有辦法下載 image 就能得到機敏資訊。當然可以限制下載 image 的權限,但還是有另一個問題是難以做到環境同步,因為線上環境跟測試環境會是不同的 image--因為機敏資訊設定通常是不一樣的。
正確的做法:使用 ENV
環境參數(參考 12 Factor Config),把機敏資訊存在環境。
Docker 真的是學無止盡,雖然筆者跟他相處了很久,但要寫的時候,還是得東查西查。
希望這次的鐵人賽能幫助到大家,感謝收看。