Container 應用
到目前為止,已經說明了 docker run
幾個常用的選項和參數,也做了一些簡單的範例。今天將以情境的方式,介紹如何應用 docker run
指令完成任務。
資料庫 client 端
使用 container 連線資料庫,如:
docker run --rm -it percona mysql -h10.10.10.10 -umiles -pchou |
曾遇過在連線資料庫的時候,遇到版本不相容的問題,所以有做過下面的測試:
# 換用其他 fork 的 client |
最終成功地完成測試了。如果要在本機安裝多個版本會是困難的,相較使用具隔離性的 Docker container 測試起來就非常容易。
Redis 也可以用一樣的方法:
docker run --rm -it redis redis-cli -h10.10.10.10 |
資料庫 server 端
開發階段在測試的時候,最怕遇到多人共用資料庫的情境,因為會互相傷害影響測試結果。最好的方法還是人人自備資料庫,自己的資料自己建。
如果對機器管理不熟悉,就算照著網路教學自己建好資料庫,但遇到問題或開不起來,也只能重灌治萬病,這樣做的風險也不低。
Docker 在這種情境下,會是個非常好用的工具。container 砍掉重練的效果就等於重灌,而且常見的 image 幾乎都找得到,一個 docker pull
指令就搞定了,連學習安裝過程和踩雷的時間都可以省下來。配合 -p
選項把 port 開放出去,那就跟在本機安裝 server 幾乎完全一樣,非常方便。
docker run --rm -it -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pass mysql |
指令借我用一下
小弟主要語言為 PHP,建置環境時,偶爾會需要用到 node.js。因為極少用到 node.js,所以不想額外安裝 nvm 等相關套件,但要用的當下又很麻煩,這有什麼方法能解決呢?
Docker 提供了滿滿的大平台,只要透過下面這個 docker run
指令,即可達成「不安裝工具還要能使用工具」的任性需求:
docker run --rm -it -v $PWD:/source -w /source node:14-alpine npm -v |
來分解並複習一下這些選項與參數的用途:
--rm
執行完後移除。當要使用功能的時候開 container,功能處理完後移除 container-it
通常需要跟 container 互動,因此會加這個選項-v $PWD:/source
把本機目錄綁定到 container,$PWD
為執行指令時的當下目錄,/source
則是 container 裡的絕對路徑-w /source
是進去 container 時,預設會在哪個路徑下執行指令node:14-alpine
image 名稱,這裡用了 Alpine 輕薄短小版npm -v
在 container 執行的指令,可以視需求換成其他指令
步驟有點複雜,有個方法是將它拆解成「進 container」與「container 裡執行指令」兩個步驟執行。在不清楚 container 發生什麼事的時候,拆解指令是個非常好用的方法;相反地,了解 container 運作過程的話,合併指令則是方便又直接,大家可視情況運用。
# 先查看目前檔案列表 |
上面這個範例可以看到,因為有做 bind mount,所以指令在 container 做的事情會同步回 host。簡單來說即:Host 沒有安裝指令也不打緊,用 Docker 啟動 container 幫忙執行後,再把結果傳回給 host。
接著拿上面產生的 packages.json
來做一個正式的範例:
# 確認內容 |
這個範例主要可以觀察到兩件事:
- 第一次執行
docker run
時,因為沒有packages-lock.json
,所以 npm 有產生這個檔案,ls -l
也有看到 - 第二次執行
docker run
時,已經有packages-lock.json
了,所以 npm 做的事跟第一次不一樣
上面這個 docker run
指令即可安裝 packages.json
所需套件。
工程師可以再懶一點
每次打落落長的指令也很逼人,有個簡單的解決方案--設定 alias。
# 確認無法使用 npm |
設定好後,打 npm
就等於打了長長一串 docker run
指令了。到這裡讀者也能感受,最後用起來的感覺會跟平常使用 npm
一模一樣,幾乎可以取代安裝工具。
類似的概念可以做到非常多工具上,下面是目前實驗過可行的。
# 使用 Composer |
最後要提醒一個重點:這個範例主要是想讓讀者知道 Docker 可以如何應用。實務上,跟安裝好工具的使用經驗還是有所差別的。
路徑差異
因工作目錄是設定 -w /source
,也許會因專案設定不同而導致工具執行出錯;另外,工具如果跟某個絕對路徑有相依,如 ~/.npm
,這也可能導致出錯。
Kernel 差異
Container Kernel 不同可能會導致無法預期的錯誤。
以 Mac + Docker Desktop for Mac 來說,實際執行 container 是使用 Linux kernel,因此若工具有產生 binary,通常會是 for Linux,這時回到 Mac 直接使用就會出錯。
另外,Container Kernel 不同,在做 bind mount 時會有效能問題,簡單來說就是會跑比較慢一點。
Docker 上跑就沒問題
若讀者有個好習慣是時常用 --rm
的話,那大部分的情況可以把這個標題大聲說出來:「Docker 上跑就沒問題」。
舉個例,laravel-bridge/scratch
套件需要在 PHP >= 7.1 版的環境裡執行單元測試,可以使用下面指令來測試套件在各個環境是否正常:
# 在 laravel-bridge/scratch 上跑測試 |
全部 pass,這樣就比較有信心跟其他開發者說,在 PHP 7.1 ~ 7.4 上都是沒問題的!
同樣地,我們也可以在 PHP 8.0 beta 上測試,來確保套件在即將發布的最新版上也是能正常運作的:
docker run -it --rm -v $PWD:/source -w /source php:8.0.0beta4-alpine vendor/bin/phpunit |
指令補充說明
docker run
-w|--workdir
指定預設執行的路徑
今日自我回顧
今天比較像是如何使用 Docker 的小技巧,有些情境都是不想裝或不會裝,所以才會直接拿別人包好的 image 來用;有些情境則是確認使用官方 image 執行可以正常,則不管在哪個用一樣的方法執行也要正常。
- 練習透過 Docker 建立資料庫,與連線資料庫
- 練習拆解指令和合併指令,這在下一輪十天說明 build image 會重複使用這個技巧
- 練習用 Docker 指令配合開發程式碼做測試