網頁開發實戰
EP.13

Docker 入門:Image、Container、Compose
容器化技術一次搞懂

Image 是食譜,Container 是料理 — 從 Hello World 到 docker-compose 部署,
附面試必備概念

Joseph Chen

2025
14 min read
1.8k views

「『在我電腦可以跑』是工程師最讓人頭痛的一句話。Docker 解決的就是這個問題 — 把整個執行環境打包起來一起出貨,讓它在哪裡都能跑。」

— 容器化技術的核心價值:環境一致性(Environment Parity)。

為什麼需要 Docker?

你在本機開發的 Python 3.11 應用程式,部署到伺服器後發現對方是 Python 3.8,某個套件不支援,整個炸掉。這就是「環境不一致」問題。

💻

開發環境

macOS + Python 3.11 + 套件 A v2.0

🧪

測試環境

Ubuntu + Python 3.9 + 套件 A v1.8

🌍

生產環境

CentOS + Python 3.8 + 套件 A v1.5

Docker:把應用程式 + 所有相依套件 + 執行環境打包成一個 Image → 在任何機器上都一模一樣地跑。

VM vs Container:架構比較

Docker Container 和虛擬機(VM)都能提供隔離環境,但底層架構完全不同:

Virtual Machine

App A
App B
Guest OS × 2(各自完整)
Hypervisor(VMware / VirtualBox)
Host OS + 實體硬體
  • 每個 VM 含完整 OS,體積 GB 級
  • 啟動需 1–2 分鐘
  • 隔離性最強(不同 Kernel)

Docker Container

Container A
Container B
Docker Engine(共用 Host Kernel)
Host OS + 實體硬體
  • 共用 Host Kernel,體積 MB 級
  • 啟動只需秒級(甚至毫秒)
  • Process-level 隔離(namespace + cgroup)
比較項目VMContainer
體積GB 級(含完整 OS)MB 級(只含應用層)
啟動時間1–2 分鐘秒級甚至更快
隔離程度強(獨立 Kernel)中(共用 Kernel)
資源消耗
可攜性依賴 Hypervisor任何有 Docker 的機器都能跑
使用場景需要不同 OS、強隔離微服務、CI/CD、快速部署

三個核心概念:Dockerfile → Image → Container

Docker 的世界只有三個主角,搞懂他們的關係就懂了 80%:

建置與執行流程

Dockerfile

食譜(文字檔)

docker build

Image

快照(唯讀)

docker run

Container

執行中的實例

Dockerfile

食譜

一個純文字的指令檔,告訴 Docker「怎麼建這個 Image」。FROM 哪個 base image、要 RUN 哪些指令安裝套件、要 COPY 哪些檔案進去。

Image

快照(唯讀)

docker build 執行 Dockerfile 後產生的唯讀快照,由多個 layer 堆疊而成。可以 push 到 Docker Hub 分享給別人。

Container

執行中的實例

docker run 從 Image 啟動的執行實例,有自己的 process、network、filesystem。同一個 Image 可以同時啟動多個 Container。

常用指令速查表

指令作用常用參數
docker build -t <name> .從 Dockerfile 建 Image-t 指定名稱:tag,. = 當前目錄
docker run <image>從 Image 啟動 Container-d 背景執行,-p 8080:80 port 對應,-v 掛載 volume
docker ps列出執行中的 Container-a 顯示全部(含已停止)
docker stop <id>停止 Containerdocker stop $(docker ps -q) 停全部
docker rm <id>刪除 Container-f 強制刪除執行中的
docker images列出本機所有 Image
docker rmi <image>刪除 Image-f 強制刪除
docker exec -it <id> sh進入執行中的 Container-it = interactive + tty
docker logs <id>查看 Container 輸出日誌-f 追蹤即時輸出
docker pull <image>從 Registry 下載 Imagedocker pull node:18-alpine
docker push <image>推 Image 到 Registry需先 docker login

Dockerfile 基礎語法

Dockerfile 的每一行指令都會建立一個 layer。以下是最常用的關鍵字:

Dockerfile — Node.js 應用範例
# FROM:指定 base image(起點)
FROM node:18-alpine

# WORKDIR:設定容器內的工作目錄
WORKDIR /app

# COPY:把本機檔案複製進容器
# 先複製 package.json,利用 layer cache 加速 build
COPY package*.json ./

# RUN:在建置階段執行指令(安裝套件)
RUN npm ci --only=production

# 再複製其他原始碼(改動頻繁的放後面)
COPY . .

# EXPOSE:宣告容器對外的 port(只是文件,不真正開放)
EXPOSE 3000

# CMD:容器啟動時執行的預設指令(只有最後一個 CMD 生效)
CMD ["node", "server.js"]
指令說明
FROM指定 base image,每個 Dockerfile 都必須有。alpine 版本體積更小。
WORKDIR設定後續指令的工作目錄,不存在時自動建立。
COPY複製本機檔案/目錄到容器內。
ADD和 COPY 類似,但支援 URL 和自動解壓 tar,一般優先用 COPY。
RUN建置階段執行的 shell 指令,每個 RUN 建立一個 layer。
ENV設定環境變數,Container 執行時也會存在。
EXPOSE宣告 port(僅文件用途,需要 -p 才真正對應到主機)。
CMD容器啟動的預設指令,可被 docker run 後面的參數覆蓋。
ENTRYPOINT容器入口點,不易被覆蓋,常和 CMD 搭配使用。

docker-compose:多服務一起管理

實際專案往往有前端、後端、資料庫三個服務。docker-compose 讓你用一個 YAML 檔宣告所有服務,一行指令全部啟動。

docker-compose.yml — 前後端 + PostgreSQL
version: '3.8'

services:
  # ── 前端(Next.js)
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    environment:
      - NEXT_PUBLIC_API_URL=http://backend:8000
    depends_on:
      - backend

  # ── 後端(FastAPI / Node.js)
  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      - db

  # ── 資料庫(PostgreSQL)
  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
常用 compose 指令
docker compose up -d        # 背景啟動所有服務
docker compose down          # 停止並移除 Container
docker compose logs -f       # 追蹤所有服務的日誌
docker compose ps            # 查看所有服務狀態
docker compose build         # 重新 build 所有 Image

Volume vs Bind Mount:資料持久化

Container 本身是無狀態的,刪除後資料就消失。要讓資料持久化,需要掛載外部儲存:

Named Volume

dockerfile
# docker-compose.yml
volumes:
  - mydata:/app/data

# Docker 管理儲存位置
# ✅ 推薦用於:資料庫、持久化資料
  • 由 Docker 管理,可跨平台
  • 性能較佳
  • 用 docker volume ls 管理

Bind Mount

dockerfile
# docker-compose.yml
volumes:
  - ./src:/app/src

# 把本機目錄直接掛進去
# ✅ 推薦用於:開發時熱更新
  • 本機路徑直接對應
  • 開發時即時同步
  • 跨平台路徑問題需注意

面試常考題

以下是 Docker / DevOps 相關面試中最常出現的概念題,每題附標準答案要點。

Q1. Image 和 Container 的差異?

Image 是唯讀的靜態快照(食譜),由 Dockerfile build 產生,存在 registry 可以分享。Container 是 Image 的執行實例(料理),有自己的 process、network、可寫 filesystem layer。同一個 Image 可以同時 run 多個 Container,彼此獨立。

Q2. CMD 和 ENTRYPOINT 的差異?

CMD 是容器的預設指令,可以被 docker run 後面傳入的參數完全覆蓋。ENTRYPOINT 是固定的入口點,傳入的參數會附加在後面而不是替換。常見搭配:ENTRYPOINT ["python"] + CMD ["app.py"],這樣可以 docker run myapp other.py 來執行不同的腳本。

Q3. Docker layer 是什麼?為何要把 COPY package.json 放在 COPY . . 前?

Dockerfile 每一個指令(FROM/RUN/COPY)都建立一個 layer,Docker 會 cache 每層。如果某層輸入沒變,直接用快取跳過。package.json 改動頻率遠低於原始碼,把它先 COPY 並 RUN npm install,只要 package.json 沒變就直接使用 cache,大幅加速 CI/CD 的 build 時間。

Q4. Container 之間如何通訊?

使用 docker-compose 時,同一個 compose file 的 Container 預設在同一個 network,可以直接用 service name 當 hostname(例如後端連 db:5432)。若是手動啟動,需要 docker network create 建立自訂 network,再用 --network 參數指定。

Q5. docker-compose 和 Kubernetes 的差異?

docker-compose 適合本機開發和小型部署,管理單台機器上的多個 Container,設定簡單。Kubernetes(K8s)是生產級的容器編排系統,管理多台機器(cluster)、自動 scaling、rolling update、自我修復(Pod 掛了自動重啟)、服務發現、負載平衡。學習曲線差距很大。

Q6. 什麼是 multi-stage build?為什麼用它?

Multi-stage build 是在同一個 Dockerfile 裡用多個 FROM 分成不同階段。例如先用 node:18 build React app(含所有 devDependencies),再用 nginx:alpine 只複製 build 產物,最終 Image 不含任何 Node.js 環境。效果:把數百 MB 的 build 環境 Image 縮到幾十 MB 的精簡 Image,減少攻擊面積與部署時間。

這篇學到什麼

🎯Docker 解決「在我電腦可以跑」問題,把應用程式 + 執行環境打包成可攜的 Image。
🏗️Container 比 VM 輕量:共用 Host Kernel,體積 MB 級,秒級啟動。
📦Dockerfile → docker build → Image(唯讀快照)→ docker run → Container(執行實例)。
🔢Layer cache 加速 build:把不常改動的 COPY package.json 和 RUN npm install 放前面。
🎼docker-compose.yml 一個檔管理多服務,docker compose up -d 一行全啟動。
🔬Multi-stage build:build 環境和執行環境分開,最終 Image 只含必要的產物,體積最小化。

上一篇

EP.12 — Git

版本控制的底層邏輯

下一篇

Coming Soon...

敬請期待下一篇

Docker
Container
DevOps
Image
Compose
Dockerfile
EP.13