跳轉至

建立 2025-08-18 更新 2026-09-28

Dockerfile 入門

Dockerfile 是一份純文字檔,一行一行寫下「怎麼做出一個 Image」:從哪個基礎環境開始、要複製哪些檔案、要安裝什麼、最後執行什麼指令。寫好之後,用 docker build 就能把自己的程式打包成 Image,再用 docker run 執行。本頁先帶你做出第一個 Image,再說明快取、多階段建置與常用指令。

動手做:打包一個 Python 網站

1. 準備程式

建立一個資料夾,放入以下三個檔案。

app.py:一個最簡單的 Flask 網站。

from flask import Flask

app = Flask(__name__)


@app.get("/")
def index():
    return "Hello Docker!\n"


@app.get("/health")
def health():
    return "OK\n"

requirements.txt:程式需要的套件。

flask==3.1.2

.dockerignore:列出不要放進 Image 的檔案,就像 .gitignore。

__pycache__/
*.pyc
.venv/
.env
.git/

2. 寫 Dockerfile

在同一個資料夾建立名為 Dockerfile 的檔案(沒有副檔名):

# 1. 基底映像檔:已經裝好 Python 3.12 的精簡版 Linux
FROM python:3.12-slim

# 2. 之後的指令都在 /app 資料夾裡執行
WORKDIR /app

# 3. 先複製套件清單並安裝(這一層可以被快取)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 4. 再複製程式碼(最常改的放最後)
COPY . .

# 5. 改用一般使用者執行,比 root 安全
RUN useradd --create-home appuser
USER appuser

# 6. 說明這個容器會用 8000 埠(只是註記,不會真的開放)
EXPOSE 8000

# 7. 容器啟動時要執行的指令
CMD ["flask", "--app", "app", "run", "--host", "0.0.0.0", "--port", "8000"]

3. 建置並執行

docker build -t hello-docker:1.0 .
docker run -d --rm --name hello -p 8000:8000 hello-docker:1.0
  • -t hello-docker:1.0:幫 Image 取名字和版本。
  • 最後的 .:代表「用目前這個資料夾的檔案來建置」。

打開 http://localhost:8000,看到 Hello Docker! 就成功了。用 docker exec hello whoami 可以確認程式是以 appuser 身分執行,而不是 root。看完用 docker stop hello 停止。

為什麼要 --host 0.0.0.0?

程式預設只接受「自己」的連線(127.0.0.1)。在容器裡,「自己」指的是容器本身,所以從你的電腦連不進去。改成 0.0.0.0 才會接受外部的連線。

為什麼要先複製 requirements.txt?

Dockerfile 的每個 RUN、COPY 都會產生一層(layer)。建置時,Docker 會檢查每一層「跟上次比有沒有變」,沒變就直接沿用上次的結果,這叫做快取(cache)。

但只要某一層變了,它後面的所有層都要重做。所以順序很重要:

  • 套件清單很少改,放前面 → 安裝套件那一層幾乎每次都能用快取。
  • 程式碼常常改,放後面 → 改程式時只需要重做最後幾層。

試著修改 app.py 再建置一次,會看到安裝套件的步驟顯示 CACHED,幾秒鐘就建置完成。如果把 COPY . . 放在 pip install 之前,每次改程式都要重新安裝所有套件。

多階段建置:讓 Image 變小

有些程式需要先「建置」才能執行,例如前端網站要先用 Node.js 打包。但打包工具在執行時用不到,放在 Image 裡只會讓它變大。

多階段建置(multi-stage build)可以在一個 Dockerfile 裡用兩個 FROM:第一階段負責建置,第二階段只拿建置好的結果。

以下範例假設專案裡有 public/ 網頁資料夾,以及一個 package.json,執行 npm run build 會把網頁輸出到 dist/ 資料夾:

# 第一階段:用 Node.js 建置網站
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json ./
RUN npm install
COPY public ./public
RUN npm run build

# 第二階段:只把建置結果交給 Nginx
FROM nginx:1.28-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

AS build 幫第一階段取名字,COPY --from=build 從第一階段複製檔案。最後的 Image 只有 Nginx 和網頁檔案,完全不含 Node.js。

常用指令一覽

指令 用途 範例
FROM 選擇基底映像檔,每個 Dockerfile 都從它開始 FROM python:3.12-slim
WORKDIR 設定工作資料夾,不存在會自動建立 WORKDIR /app
COPY 把檔案從電腦複製到 Image COPY . .
RUN 建置時執行指令,例如安裝套件 RUN pip install -r requirements.txt
ENV 設定環境變數,容器執行時也看得到 ENV TZ=Asia/Taipei
ARG 建置時才用的變數,用 --build-arg 傳入 ARG VERSION=1.0
USER 切換執行身分 USER appuser
EXPOSE 註記容器使用的連接埠(只是說明) EXPOSE 8000
CMD 容器啟動時的預設指令 CMD ["python", "app.py"]
ENTRYPOINT 容器固定要執行的程式 ENTRYPOINT ["gunicorn"]
HEALTHCHECK 定期檢查程式是否正常 見下方範例
ADD 類似 COPY,但會自動解壓縮 tar 檔 一般情況用 COPY 就好
LABEL 加上說明資訊,例如作者、版本 LABEL version="1.0"
VOLUME 標示這個資料夾存放資料 VOLUME /data

只有 RUN、COPY、ADD 會真的在 Image 裡增加檔案;其他指令只是修改設定。完整說明請看 Dockerfile Reference。

CMD 和 ENTRYPOINT 差在哪?

兩者都是設定「容器啟動時要執行什麼」,差別在能不能被取代:

  • CMD:預設指令。執行 docker run 映像檔 其他指令 時,後面的指令會取代 CMD。
  • ENTRYPOINT:固定要執行的程式。docker run 後面接的東西會變成它的參數。
ENTRYPOINT ["ping"]
CMD ["localhost"]

這個 Image 預設執行 ping localhost;執行 docker run 映像檔 google.com 則變成 ping google.com。

大部分情況只用 CMD 就夠了。記得使用 ["程式", "參數"] 這種方括號寫法,程式才能正確收到停止訊號,docker stop 時會比較快結束。

健康檢查

HEALTHCHECK 讓 Docker 定期確認程式是否正常,docker ps 會顯示 healthy 或 unhealthy。檢查用的指令必須在 Image 裡存在:python:3.12-slim 沒有 curl,可以改用 Python 來檢查:

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"

Image 名稱怎麼看?

完整的 Image 名稱格式是:

[倉庫位址/][帳號/]名稱[:標籤]
Image 名稱 意思
python:3.12-slim Docker Hub 官方的 python,標籤 3.12-slim
myuser/myapp:1.0 Docker Hub 上 myuser 帳號的 myapp,版本 1.0
ghcr.io/acme/api:prod GitHub Container Registry 上 acme 組織的 api

沒寫倉庫位址就是 Docker Hub;沒寫標籤就是 latest。

寫 Dockerfile 的好習慣

  1. 一定要有 .dockerignore,避免把 .git、.env(密碼)放進 Image。
  2. 基底映像檔寫清楚版本,例如 python:3.12-slim,不要只寫 python。
  3. 不常變的步驟放前面,程式碼放最後,善用快取。
  4. 用 USER 改成一般使用者執行。
  5. 不要把密碼、金鑰寫在 Dockerfile 裡,任何拿到 Image 的人都看得到。
  6. 需要建置步驟的程式,使用多階段建置。

參考資料

推薦影音

Writing a Dockerfile

簡述:Docker 官方短片,介紹 Dockerfile 的基本結構,對應本頁「動手做」。(Docker 官方)

Using the build cache

簡述:Docker 官方短片,說明快取什麼時候有效、什麼時候失效,對應本頁「為什麼要先複製 requirements.txt?」。(Docker 官方)

Multi-stage builds

簡述:Docker 官方短片,示範用多個 FROM 讓最後的 Image 更小,對應本頁「多階段建置」。(Docker 官方)

更多影片請見 影音教學。