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,並固定版本號
想一想#
RUN pip install和CMD ["python", "app.py"]分別在什麼時候執行?為什麼不能把啟動指令寫成RUN?- 為什麼
EXPOSE是「文件性質」?不加它,-p對映還有效嗎?(會,EXPOSE 只是聲明) - 對照你熟悉的語言,試著寫出它的最小 Dockerfile。