網頁開發實戰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...

敬請期待下一篇

DockerContainerDevOpsImageComposeDockerfileEP.13