為了盡可能縮小容器體積,一方面也避免 CLI 工具或程式庫淪為惡意程式或攻擊者的兇器,容器基底映像檔(Image)一般只會滿足運行程式所需的最最最低要求,不包含我們常用的 CLI 指令。

以運行 .NET 程式的基本容器映像檔 mcr.microsoft.com/dotnet/runtime 為例,就連 ps 跟 curl 都沒有。以上回寫的 Prometheus 智慧插座用電量監測器為例,用 docker exec -it hs300-exporter /bin/bash 測試可確試容器沒有 ps 與 curl CLI 可用。(延伸閱讀: Docker 排查偵錯常用 CLI 指令整理)

如果我們想在 Docker 安裝特定 CLI 工具方便偵錯,或是應用程式需要額外程式庫才能執行,要怎麼做?不難,修改上回的 Dockerfile,在建立 Docker 映像檔過程增加三個步驟即可:

  1. USER root 切換為 root 身分以便執行 apt-get
  2. 使用 apt-get 安裝所需軟體或程式庫,結束時 rm -rf /var/lib/apt/lists/* 清理暫存檔以節省容量
  3. USER app 切回非 root 身分

修改版 Dockerfile 如下:

# 使用 .NET 9 SDK 作為建置環境
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# 複製專案檔並還原相依套件 (利用快取機制,csproj 檔沒變動時,不需要重複還原)
COPY hs300-exporter.csproj .
RUN dotnet restore

# 專案只有一個 Program.cs 檔案
# 有很多檔案時,可使用 COPY . . 指令並配合 .dockerignore 檔案排除不要複製的檔案
COPY Program.cs .
# --no-restore 跳過前面已做過的 Package 還原步驟,加速建置
# /p:PublishSingleFile=false 不打包成單一檔,執行前不需解壓,啟動速度較快
# /p:PublishTrimmed=false 不進行程式碼修剪,加快建置減少出錯風險
RUN dotnet publish -c Release -o /app/publish \
    --no-restore \
    /p:PublishSingleFile=false \
    /p:PublishTrimmed=false

# 使用 .NET 9 Runtime 作為執行環境(較小的 Image)
FROM mcr.microsoft.com/dotnet/runtime:9.0
WORKDIR /app

# 切換到 root 使用者以便安裝套件
USER root

# 使用 apt-get 安裝需要套件 
# 裝 curl 通常會一併安裝 ca-certificates 以更新 CA 憑證信任資料
# --no-install-recommends 不要安裝推薦項目
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl ca-certificates procps && \
    rm -rf /var/lib/apt/lists/* # 清理暫存檔以減少映像檔大小

# 切換為非 root 使用者執行應用程式,提高安全性
USER app

# 複製建置輸出
COPY --from=build /app/publish .

# 宣告使用 Port (Metadata 性質,不影響編譯或執行)
EXPOSE 9999

# 執行應用程式
ENTRYPOINT ["dotnet", "hs300-exporter.dll"]

改用這個版本的映像檔建立容器,以 docker exec -it 登入測試,現在就有 ps 跟 curl 可用惹。

額外安裝套件,映像檔一定會變大,但大小差多少?下圖為 docker history 的檢查結果,上方為原始映像檔,下方為增加 apt-get 後的映像檔,多了三層,體積增加約 8MB:

【資安提醒】多裝這兩個工具,方便之餘也意味:一旦容器被入侵,攻擊者也會多兩個工具可利用。額外安裝套件前,請自行評估必要性及風險。

Shows how to add CLI tools (e.g., ps, curl) to a minimal .NET Docker image using Dockerfile, and highlights security risks.


Comments

Be the first to post a comment

Post a comment