DEV Community

JH5
JH5

Posted on • Originally published at Medium

你的Dockerfile看起來沒問題 ?

你的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
Enter fullscreen mode Exit fullscreen mode

或者你也可以用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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

安裝完畢後,要執行一次測試,基本上你只需要三樣東西:

  • 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
Enter fullscreen mode Exit fullscreen mode

次世代定序(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--'
Enter fullscreen mode Exit fullscreen mode

這個設定檔做了幾件重要的事:

  1. 版本鎖定:明確驗證了bwasamtools的版本號,如果未來有人更新了基礎Image導致工具版本飄移,測試就會立刻失敗,避免了用錯版本分析資料的慘劇。

  2. Runtime驗證:我們跑了gatk --help,這不僅確認gatk這個執行檔存在,還證明了它的Java環境和相關依賴是正常的。

  3. 關鍵檔案驗證:我們檢查了參考基因體的索引檔.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
Enter fullscreen mode Exit fullscreen mode

稍稍解釋一下設定檔案內容:

  1. 硬體環境依賴:我們直接在容器內跑Python程式碼來驗證torch.cuda.is_available(),這比單純檢查nvidia-smi指令更直接,確保PyTorch能真的抓到GPU,同時也檢查了NVIDIA_VISIBLE_DEVICES這個關鍵的環境變數。

  2. SBOM 安全pip freeze的檢查確保了所有Python套件的版本都被鎖定,這對於需要通過FDA或TFDA等法規認證的醫療器材軟體(SaMD)來說,是至關重要的一環。

  3. 服務可用性測試:最精彩的是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"'
Enter fullscreen mode Exit fullscreen mode

上面的範例間單的加上test 階段的範例,如過需要build stage可以自行根據你的task runner自行加上

  1. 自動化屏障:如果在test階段,CST發現任何不符合test_config.yaml中定義的規則(例如版本不對、檔案遺失),整個pipeline就會失敗。

  2. 品質保證:這確保了只有100%通過 CST 測試的Image,才會留在Registry中,對於後續的部署、或是給研究人員使用,都加上了更高的信任基礎。

簡單來說,Container Structure Test為我們提供了一個強大且靈活的框架,讓我們能夠將容器映像檔的品質標準,從「能跑就好」提升到「精確、可控、可驗證」。

從服務提供角度來看,速度很重要,但穩定與可靠永遠是第一位的,當智慧醫療的程式碼最終可能影響到一個人的健康決策時,便沒有犯錯的空間。

如果能將CST導入你的開發流程,就像是幫程式碼和模型買了一份保險,它不能保證你的演算法100%正確,但它能確保你交付到醫生或研究員手中的工具,是你預期中的那個最穩定的版本。

個人覺得,這不只是一個工具,這是一種開發思維的轉變,是從軟體工程走向精準醫療工程的關鍵的第一步。

# devops# docker

Top comments (0)