你的Dockerfile看起來沒問題 ?
你有遇到Dockerfile build 成功,但是deploy後還是不能用,build成功,只代表指令在建構當下沒出錯,不過這完全不保證:
你安裝的工具或套件版本真的是你想要的那個嗎?
必要的模型權重檔,真的被複製到正確的路徑了嗎?
容器的環境變數、對外開放的Port、預設使用者都設定正確了嗎?
某些指令的輸出,是否包含不該出現的警告或錯誤訊息?
我們習慣用Docker將複雜的分析環境、特定版本的工具(例如GATK 4.2.0.0、SAMtools 1.9)、Python依賴套件,甚至是AI模型全部打包成一個Image,一個Dockerfile寫完,docker build成功,就心滿意足地把Image推送到Container Registry了。
「在我電腦上可以跑,換到Server上就不行」?或是模型版本、依賴套件錯亂導致分析結果無法重現?當你的分析pipeline牽涉到幾十個工具,或是一個AI模型要落地到醫院的伺服器上時,結果攸關病人疾病關鍵字的HPO Term沒有正確的帶入或是帶錯?
分析失敗事小,給出錯誤的臨床建議事大,這應該就是Container Structure Test(CST)派上用場的地方,它讓我們能在Image Build 完後,自動化地對「內容」進行滴水不漏的驗證,例如Command Tests, File Existence Tests, File Content Tests, Metadata Test 等這幾個常見的面向。
安裝與設定 CST
在我們深入探討如何撰寫測試之前,先把工具準備好,CST的安裝非常簡單,它就是一個獨立的執行檔,沒有什麼複雜的依賴。
macOS 使用者
如果你用Mac,最快的方式是透過 Homebrew:
brew install container-structure-test
或者你也可以用curl手動下載:
curl -LO https://github.com/GoogleContainerTools/container-structure-test/releases/latest/download/container-structure-test-darwin-arm64 && chmod +x container-structure-test-darwin-arm64 && sudo mv container-structure-test-darwin-arm64 /usr/local/bin/container-structure-test
Linux 使用者
Linux環境下,同樣使用curl即可:
curl -LO https://github.com/GoogleContainerTools/container-structure-test/releases/latest/download/container-structure-test-linux-amd64 && chmod +x container-structure-test-linux-amd64 && sudo mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-test
安裝完畢後,要執行一次測試,基本上你只需要三樣東西:
CST執行檔:就是我們剛剛安裝的
container-structure-test。待測試的Container Image:這Image必須已經在你的本機或是遠端Registry中。
測試設定檔:一個
.yaml或.json檔,用來定義你要執行的所有測試。
準備好這些,就可以用一行指令啟動測試:
container-structure-test test --image gcr.io/your-project/your-image:latest --config your_test_config.yaml
次世代定序(NGS)分析範例
我們正在打包一個用於次世代定序(NGS)分析的標準流程,這個Image裡面應該要有BWA(序列比對)、SAMtools(處理BAM檔)和GATK(變異偵測)等這些常用的生資工具。
schemaVersion: "2.0.0"
commandTests:
- name: "Check BWA version"
command: "bwa"
expectedError: ["Version: 0.7.17-r1188"] # bwa version info is in stderr
- name: "Check SAMtools version"
command: "samtools"
args: ["--version"]
expectedOutput: ["samtools 1.9"]
- name: "Check GATK Execution"
command: "gatk"
args: ["--help"]
expectedOutput: ["Usage: gatk <command>"]
fileExistenceTests:
- name: 'Reference Genome Index'
path: '/genome/hg38.fa.fai'
shouldExist: true
permissions: '-rw-r--r--'
這個設定檔做了幾件重要的事:
版本鎖定:明確驗證了
bwa和samtools的版本號,如果未來有人更新了基礎Image導致工具版本飄移,測試就會立刻失敗,避免了用錯版本分析資料的慘劇。Runtime驗證:我們跑了
gatk --help,這不僅確認gatk這個執行檔存在,還證明了它的Java環境和相關依賴是正常的。關鍵檔案驗證:我們檢查了參考基因體的索引檔
.fai是否存在。沒有這個檔案,後續的比對流程根本跑不起來,同時,也可以確認是hg19/hg37/hg38等參考檔案。
上面的這個範例便可以了解,CST將分析流程中對這個容器環境的「所有假設」,全部白紙黑字地寫成可自動化驗證的測試。
AI影像模型服務容器的驗證
假設我們打包了一個用於肺結節偵測的PyTorch模型,準備部署到醫院的PACS系統旁邊並需要進行串接,大致上需要應該會需要確認GPU環境,模型的檔案與API服務健康程度,相關的yaml檔案大概會需要這樣的配置。
schemaVersion: "2.0.0"
metadataTest:
exposedPorts: ["5000"]
envVars:
- key: "NVIDIA_VISIBLE_DEVICES"
value: "all"
- key: "MODEL_PATH"
value: "/models/lung_nodule_v2.pt"
workdir: "/app"
commandTests:
- name: "Check CUDA availability"
command: "python"
args: ["-c", "import torch; print(torch.cuda.is_available())"]
expectedOutput: ["True"]
- name: "Check required python packages"
command: "pip"
args: ["freeze"]
expectedOutput:
- "torch==1.13.1"
- "torchvision==0.14.1"
- "monai==1.1.0"
- "uvicorn"
- name: "API Health Check (using setup)"
# A simple script to start the server in the background and then test it
setup:
- ["/bin/bash", "-c", "uvicorn main:app --host 0.0.0.0 --port 5000 & sleep 5"]
command: "curl"
args: ["-s", "http://localhost:5000/health"]
expectedOutput: ['{"status": "ok"}']
fileExistenceTests:
- name: 'PyTorch Model File'
path: '/models/lung_nodule_v2.pt'
shouldExist: true
稍稍解釋一下設定檔案內容:
硬體環境依賴:我們直接在容器內跑Python程式碼來驗證
torch.cuda.is_available(),這比單純檢查nvidia-smi指令更直接,確保PyTorch能真的抓到GPU,同時也檢查了NVIDIA_VISIBLE_DEVICES這個關鍵的環境變數。SBOM 安全:
pip freeze的檢查確保了所有Python套件的版本都被鎖定,這對於需要通過FDA或TFDA等法規認證的醫療器材軟體(SaMD)來說,是至關重要的一環。服務可用性測試:最精彩的是
API Health Check。我們利用setup指令在背景啟動API伺服器,sleep 5給它一點啟動時間,然後用curl去呼叫健康檢查的endpoint。
整合 GitLab CI/CD
在你的專案根目錄下,建立一個.gitlab-ci.yml檔案:
stages:
- test
variables:
# 定義Image的名稱與標籤,方便在不同stage中共用
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
# --- Test Stage ---
# 這個階段負責拉取剛建好的Image,並執行Container Structure Test
test-image-structure:
stage: test
# 直接使用官方的CST Image來執行測試
image: gcr.io/gcp-runtimes/container-structure-test:latest
services:
- docker:20.10-dind
script:
- echo "Testing image structure..."
# 登入GitLab Registry來拉取Image
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# 拉取剛剛build好的Image
- docker pull $IMAGE_TAG
# 執行測試!
- container-structure-test test --image $IMAGE_TAG --config tests/test_config.yaml
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
上面的範例間單的加上test 階段的範例,如過需要build stage可以自行根據你的task runner自行加上
自動化屏障:如果在
test階段,CST發現任何不符合test_config.yaml中定義的規則(例如版本不對、檔案遺失),整個pipeline就會失敗。品質保證:這確保了只有100%通過 CST 測試的Image,才會留在Registry中,對於後續的部署、或是給研究人員使用,都加上了更高的信任基礎。
簡單來說,Container Structure Test為我們提供了一個強大且靈活的框架,讓我們能夠將容器映像檔的品質標準,從「能跑就好」提升到「精確、可控、可驗證」。
從服務提供角度來看,速度很重要,但穩定與可靠永遠是第一位的,當智慧醫療的程式碼最終可能影響到一個人的健康決策時,便沒有犯錯的空間。
如果能將CST導入你的開發流程,就像是幫程式碼和模型買了一份保險,它不能保證你的演算法100%正確,但它能確保你交付到醫生或研究員手中的工具,是你預期中的那個最穩定的版本。
個人覺得,這不只是一個工具,這是一種開發思維的轉變,是從軟體工程走向精準醫療工程的關鍵的第一步。

Top comments (0)