多環境多語言下保持生產環境獨立的軟體開發方式:在容器內開發 / Programming in Container
這篇文章會分享我如何利用容器
(Container
) 來依據產品或專案,分門別類的管理並隔離各種程式語言開發環境及其版本。
為了解決各種疑難雜症,我很常需要在各式各樣的開發環境來回切換,諸如 Python
、Go
、PHP
、Node
、Java
等,若再加上版本號,如 Python 2 / 3、Node 8 / 12、Java 1.8 / 11,則組合方式更為多元且複雜。這不僅容易弄亂生產環境,有時還會彼此發生衝突。
過去我會採用系統預載的版本,例如 Ubuntu
18.04 預設為 Python 2.7,然後再加上 Version Control 工具 (如 pyenv
) 來新增 Python 3 環境,再用 virtualenv
來隔離模組。但到了容器化
(Containerization
)時代,我們可以有更整潔的解決辦法。
1. 產品與專案目錄結構
容器化技術工具我選擇 Docker
,每個目錄會依據各產品或專案來區隔。
並建立各自獨立的容器。
2. 容器化環境的搭建
這是 docker/python-3.8-cli/Dockerfile 的範例,
FROM python:3.8-slim
COPY app/ /app
WORKDIR /app
RUN apt-get update -y && apt-get dist-upgrade -yq
RUN apt-get install -yq \
git-core \
vim-tiny
RUN pip install -r requirements.txt
ENTRYPOINT ["python3.8"]
其中 requirements.txt 的內容範例為,你可以依需求調整,
Flask>=1.1.1,<1.2
flask-restplus>=0.13,<0.14
Flask-SSLify>=0.1.5,<0.2
Flask-Admin>=1.5.3,<1.6
gunicorn>=19,<20
接著建構 Docker image,就可以在 docker images
看到 python-3.8-cli。
$ cd docker/python-3.8-cli
$ docker build -t python-3.8-cli .
3. 一行指令運行特定環境
當需要 Python 3.8 的環境時,之後只需一行指令即可在本機沒有 Python 3.8 環境下運行程式碼。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python-3.8-cli latest c21974826f58 3 hours ago 851MB
// 利用 python-3.8-cli 容器環境,執行本機 docker/python-3.8-cli/hello.py 的程式
$ cd docker/python-3.8-cli
$ docker run -it --rm -v $(PWD)/hello.py:/hello.py python-3.8-cli /hello.py
若專案為目錄結構,而非上述的單一檔案,也可以將整個本機目錄對應至容器環境執行。
// 利用 python-3.8-cli 容器環境,執行本機 docker/python-3.8-cli/app/app.py
$ cd docker/python-3.8-cli
$ docker run -it --rm -v $(PWD)/app:/app python-3.8-cli /app/app.py
4. 當需要運行較複雜的環境時,可以選擇啟動容器
當需要更複雜的開發環境時,可以選擇把工作區域掛載至容器內,接著在本機使用熟悉的 IDE 進行開發,異動/修改的程式碼也會同步至容器。
假設有個新專案 myproject python-3.8-cli 的開發環境,我可以基於此 Docker image 運行一個 instance。
// 專案目錄
$ cd project/myproject
$ docker run -d --name myproject -h myproject -v $(PWD)/app:/app:rw -t python-3.8-cli
// 繼續使用本機 IDE 編輯本機的程式碼
$ code $(PWD)/app
5. 開啟額外指示,讓容器存取硬體資源
若你的容器開發環境需要本機硬體資源時,例如攝影機,則需要開啟額外指示。此範例是我利用 Python + OpenCV + Camera 開發某個視覺化處理的產品,需要存取攝影機並將畫面投射至本機。
$ cd project/mypython
$ docker run -d --name python-3.8-opencv -h python-3.8-opencv -v $(PWD)/app:/app:rw -t python-3.8-cli \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=${DISPLAY} \
--device /dev/video0:/dev/video0
// 繼續使用本機 IDE 編輯本機的程式碼
$ code $(PWD)/app
然而因為需要投射畫面,所以容器要安裝 X Window 相關所需的函式庫。
$ docker exec -it python-3.8-opencv bash
docker$ apt install libsm6 libxext6 libxrender-dev
$ exit
當程式碼編修完成,可以在本機 Host 直接運行,
// 允許其他 X 視窗的繪圖指令能連進本機
$ xhost +
// 本機運行 Instance 內的程式碼
// 因為 Dockerfile 有 WORKDIR 的關係,所以 Video.py 對應的是 Instance 裡的 WORKDIR/Video.py 路徑
$ docker exec python-3.8-opencv Video.py
接著就可以看到鏡頭拍攝的畫面,還有我試圖繪製的 Skeleton。