上篇文章說明 使用 CircleCI 作為《我.影化身》雲端持續整合方案, 其中提到 CircleCI 對於 Docker 的支援是很完整的,本文進一步來看看如何在 CircleCI 上使用 Docker 在每次代碼提交時自動建構應用程式的映像。
為了讓產生的映像夠小 1 ,《我.影化身》 ⎘ 專案的 Docker 映像是以 eavatar/basebox
為基礎, 關於如何建構 eavatar/basebox
這個映像,請參考:建構一個與 Ubuntu 相容的小型 Docker 映像 。
讓 CircleCI 知道專案需要 Docker 支援
要讓 CircleCI 知道專案建置需要使用它提供的 Docker 服務,需要在 circle.yml 描述檔中加入:
machine:
services:
- docker
也只需要這樣,CircleCI 就知道在啟動專案建置工作時要同時啟用 Docker 支援,有了這樣的設定, 在我們的建構腳本中就可以使用 Docker 相關的命令。
專案所需的 Dockerfile
建構 Docker 映像需要一個 Dockerfile
來讓 Docker 工具知道如何建構專案所需的映像, 底下是本專案經過刪減後的 Dockerfile:
FROM eavatar/basebox #1
MAINTAINER sampot <[email protected]>
ADD dist/avame /avame #2
EXPOSE 5080 5443 #3
ENV AVA_POD /home/ava/.config/avame #4
USER ava #5
CMD ["/avame/avame"] #6
其中,
-
指定
eavatar/basebox
作為基礎映像這是山姆鍋自己使用的基礎映像,在這個映象中已經有預建一個特別用戶:
ava, 用來作為執行應用時的身份。
-
將打包好的應用檔案加入映像中的
/avame
路徑執行應用所需的程式碼與檔案都放在 dist/avame 這個相對路徑中。
-
設定應用使用的網路埠號(port numbers)
《我.影化身》有提供 Web 使用者介面以及 API,5080 給 HTTP, 5443
則是 HTTPS 協定使用。
-
設定 AVA_POD 環境變數
這個環境變數指定程式資料要放置的路徑。照道理應該要根據當下登入的使用者身份自動判別,
但在精簡環境中,會誤判成 \'/.config/avame\' 這個路徑,由於需要以一般使用者身份執行, 所以強制指定到可以讀寫的路徑去。
-
更換執行應用的使用者身份: 基於安全理由,即使在 Docker 容器中也不建議使用 root 身份執行應用程式。
-
指定映像啟動時預設執行的命令
/avame/avame
是應用的執行檔。
建構 Docker 映像
在 CircleCI 中使用 Docker 跟在本地開發相同,使用 docker
命令來執行。 為了可以輕易從映像檔中得知當初建構時的程式碼版本,山姆鍋使用下列指令:
docker build -t eavatar/avame:$CIRCLE_BUILD_NUM-$CIRCLE_SHA1 .
docker tag eavatar/avame:$CIRCLE_BUILD_NUM-$CIRCLE_SHA1 eavatar/avame:latest
這樣產生的映像檔名就會包含提交(commit)時的版本號碼,以及建構的序號。有了這個資訊, 之後不幸要重製問題時,才方便使用找出相同版本的程式碼。
上傳映像到 Docker Hub
為了之後的部署工作,需要將產生的映像上載到某個儲存所。幸好《我.影化身》是開源專案,可以使用 Docker Hub 這個免費的儲存所。要上載映像到 Docker Hub, 使用下列指令:
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
docker push eavatar/avame
其中,$DOCKER_EMAIL, $DOCKER_USER, $DOCKER_PASS 會以對應的環境變數取代, 代表登入 Docker Hub 所需的資料,這些環境變數需要在 CircleCI 的後台設定。
完整的 circle.yml 檔案
為了方便參考,下面是寫本文時專案完整的 circle.yml 檔:
machine:
services:
- docker
general:
artifacts:
- "dist/avame-0.1.0+${CIRCLE_BUILD_NUM}.tgz"
dependencies:
override:
- sudo mkdir -p /usr/local/lib
- sudo pip install -U pip
- sudo easy_install -U setuptools
- pip install -r requirements.txt
- pip install selenium
test:
override:
- sudo cp plat.libs/libsodium.so.13.1.0 /usr/local/lib/
- sudo ln -s /usr/local/lib/libsodium.so.13.1.0 /usr/local/lib/libsodium.so.13
- sudo ln -s /usr/local/lib/libsodium.so.13.1.0 /usr/local/lib/libsodium.so
- PYTHONPATH=".:./src" py.test -vvv --cov=src/ava tests/unit/
- PYTHONPATH=".:./src" py.test -vvv tests/integration/
- PYTHONPATH=".:./src" py.test -vvv tests/functional/
- PYTHONPATH=".:./src" pyinstaller pack/avame-tui.spec --clean -y
post:
- cd dist && tar zcvf avame-0.1.0+${CIRCLE_BUILD_NUM}.tgz avame/
deployment:
hub:
branch: master
commands:
- docker build -t eavatar/avame:$CIRCLE_BUILD_NUM-$CIRCLE_SHA1 .
- docker tag eavatar/avame:$CIRCLE_BUILD_NUM-$CIRCLE_SHA1 eavatar/avame:latest
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker push eavatar/avame
執行產生的應用映像檔
在一個已經安裝好 Docker 環境的主機,可以使用下列指令啟動《我.影化身》:
docker run -it --rm -p 5080:5080 eavatar/avame
在輸出的訊息中,找到 [INFO - Access Token: 9dfDU4GqZ1vgHGnL5wsXsC
, 其中
9dfDU4GqZ1vgHGnL5wsXsC
是登入使用者介面需要的密碼,每次都會更動。 也可以在啟動時,透過環境變數 AVA_ACCESS_TOKEN 來指定一個固定值。
docker run -it --rm -p 5080:5080 -e AVA_ACCESS_TOKEN=1234 eavatar/avame
假設 Docker 容器的 IP 位址是 192.168.99.101, 則可以使用瀏覽器開啟網址http://192.168.99.101:5080
來登入,畫面應該跟本文開頭的圖檔相似。
《我.影化身》還在開發階段,歡迎任何改進建議!
結語
既然做到隨著每次代碼的提交(commit),只要通過測試,一個新的 Docker 映像就會被發佈到 Docker Hub 上。 下一步,自然是利用產生的映像來自動部署到測試或生產環境。對了,《我.影化身》使用 JQuery Mobile + Backbone 這樣的框架組合做 Web UI,有機會再來分享。
Footnotes
-
這裏當然是山姆鍋自己的主觀認定。 ↩