跳轉到

3.1 什麼是 Dockerfile?#

從使用別人的 Image 到打造自己的#

前兩章我們都在使用現成的 Image(nginx、redis、postgres)。但要部署你自己的程式,就需要把你寫的程式碼 + 依賴 + 執行環境打包成自己的 Image——這件事的食譜,就是 Dockerfile。

Dockerfile 是一個純文字檔(檔名就叫 Dockerfile),每行一條指令,描述「這個 Image 要怎麼一層一層建出來」。

一個最小的範例#

假設你有一個 Python 程式 app.py,用 Flask 提供一個 API。它的 Dockerfile 只需要六條指令:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["python", "app.py"]

每一條指令的意義:

指令 意義 口訣
FROM 以哪個基礎 Image 為起點 站在誰的肩膀上
WORKDIR 設定工作目錄(之後的指令都在這目錄下) 我在哪裡
COPY 把檔案從主機複製進 Image 帶什麼進來
RUN 建構時執行指令(裝依賴、編譯) 建構時做什麼
EXPOSE 聲明容器會監聽哪個埠(文件性質) 用什麼門
CMD 容器啟動時執行的指令(每個 Dockerfile 只有一個生效) 啟動時做什麼

RUN 與 CMD 的區別:最容易混淆的一點#

  • RUN:在 docker build 時執行,結果寫進 Image 層。用來裝依賴、編譯。
  • CMD:在 docker run 時執行,定義容器啟動的預設指令。用來跑你的程式。

記憶法:RUN 是蓋房子時做的(build),CMD 是住進去之後做的(run)。

常見語言的起點範本#

Node.js#

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Go(多階段建構的極簡版)#

FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o server .

FROM alpine
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]

Go 編譯成單一執行檔後不需要 Go 環境,所以用 alpine 當最終底層,Image 可以小到十幾 MB。

選擇基礎 Image 的原則#

  • 優先用 -slim 或 alpine 變體:體積小、安全漏洞少
  • 選你熟悉的版本標籤(python:3.12-slim 比 python:latest 可靠,避免某天 latest 悄悄升級壞掉)

本章小結#

  • Dockerfile 是打造自己 Image 的食譜,每行一條指令產生一層
  • 核心六指令:FROM、WORKDIR、COPY、RUN、EXPOSE、CMD
  • RUN 在 build 時執行,CMD 在 run 時執行——最重要的一個區別
  • 基礎 Image 優先選 -slim/alpine,並固定版本號

想一想#

  1. RUN pip install 和 CMD ["python", "app.py"] 分別在什麼時候執行?為什麼不能把啟動指令寫成 RUN?
  2. 為什麼 EXPOSE 是「文件性質」?不加它,-p 對映還有效嗎?(會,EXPOSE 只是聲明)
  3. 對照你熟悉的語言,試著寫出它的最小 Dockerfile。