Docker 完整教學 2026:什麼是容器?從安裝、Dockerfile、Compose 多階段構建到安全部署一次學會

Docker 是打包與執行應用程式的開源容器平台:把程式碼、執行環境與相依套件打包成可攜帶的 image,在任何有 Docker 的機器上以 container 隔離執行,解決「在我電腦上可以跑」的經典噩夢。這篇 2026 年完整教學從容器與 VM 的差異講起,帶你安裝 Docker Engine、寫出符合最佳實踐的 Dockerfile(多階段構建、HEALTHCHECK、非 root 使用者)、用 docker compose 一次啟動多服務,最後補上資源限制與 rootless 等安全設定,適合自架族與後端開發者從零學到實戰。

  • Dennis
  • 9 分鐘閱讀
Docker 完整教學 2026:什麼是容器?從安裝、Dockerfile、Compose 多階段構建到安全部署一次學會

Docker 是一個開源的容器化平台:把「程式碼 + 執行環境 + 相依套件」打包成一個可攜帶的 image,再以彼此隔離的 container 在任何有 Docker 的機器上執行——從此告別「在我電腦上可以跑」的噩夢,部署、擴充、移除都變成一行指令的事。

如果你在 most.tw 看過本部落格的自架系列文章,會發現幾乎每篇的安裝步驟都長這樣:docker run ...docker compose up -dCaddyn8nVaultwarden……這些服務之所以能「十分鐘裝好」,靠的都是 Docker。這篇就從零開始,把 Docker 的原理與實戰一次講清楚——看完你就能自己寫 Dockerfile、用 Compose 管理多服務,甚至幫自己的專案做出乾淨又可攜的部署流程。

什麼是容器?跟虛擬機器差在哪?

容器(Container)的概念一句話:把應用程式連同它需要的所有檔案、函式庫、設定,關進一個獨立的「箱子」裡執行。箱子內看到的檔案系統、網路、程序都與外界隔離,但箱子共享主機的作業系統核心(kernel)——這正是它跟虛擬機器(VM)最根本的差異:

flowchart TB
    subgraph VM[虛擬機器架構]
        direction TB
        H1[Hypervisor<br/>虛擬化軟體層]
        G1[Guest OS 完整作業系統<br/>例如 Ubuntu 22.04]
        A1[App 應用程式]
        H1 --- G1 --- A1
    end
    subgraph Docker[容器架構]
        direction TB
        H2[主機作業系統核心<br/>Host Kernel]
        C1[Container A<br/>只有應用程式與函式庫]
        C2[Container B<br/>只有應用程式與函式庫]
        H2 --- C1
        H2 --- C2
    end
比較虛擬機器(VM)容器(Docker)
隔離層級硬體層(各自有完整 OS)作業系統層(共享 kernel)
啟動時間數十秒~數分鐘毫秒~秒級
磁碟佔用數 GB 起跳數 MB~數百 MB
資源開銷高(每台 VM 都要跑整套 OS)低(只跑應用程式)
適用情境需要不同核心/完整 OS 的環境微服務、CI/CD、自架服務

因為共享 kernel,Linux 容器只能在 Linux 主機上跑原生執行;macOS/Windows 上的 Docker Desktop 則是靠一層輕量虛擬機器(Linux VM)來跑容器。2026 年的 Docker Engine 已推進到 29.x 系列(官方文件最新到 29.7),arm64amd64 的多平台鏡像支援也早就成為標準配備——樹莓派、Jetson 這類 ARM 裝置跟 x86 伺服器用同一份 image 就能跑。

安裝 Docker(Ubuntu / Debian 為例)

Linux 上安裝的是 Docker Engine——它是完全開源(Apache 2.0)、對個人與企業永遠免費的。需要付費訂閱的只有 Docker Desktop 這類圖形工具(大型企業:超過 250 名員工或年營收超過 1000 萬美元才需要買授權)。Ubuntu 建議用官方 apt 來源安裝:

# 加入官方 GPG key 與 repository
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

最後一行把 BuildKit(buildx)與 Compose v2 外掛一起裝好——現代 Docker 已經不再需要另外安裝 Python 版的 docker-compose。不想每次都用 sudo 的話,把使用者加入 docker 群組:

sudo usermod -aG docker $USER
# 重新登入後生效,用 docker run hello-world 驗證
docker run hello-world

四個核心概念:image、container、volume、network

概念白話解釋常用指令
Image(映像檔)打包好的「安裝光碟」:唯讀的檔案系統快照,包含程式與環境docker pulldocker builddocker images
Container(容器)Image 執行起來的「實例」:可讀寫、可啟動停止,刪掉就沒了docker rundocker psdocker rm
Volume(磁碟卷)掛在容器上的持久化儲存,容器刪了資料還在docker volume create-v
Network(網路)容器間溝通的虛擬網路;沒指定時容器彼此隔離docker network create--network

跑起來試試看:

# 前台跑一個 nginx,本機 8080 對應容器 80
docker run -d --name web -p 8080:80 nginx:alpine

# 看執行中的容器
docker ps

# 進到容器內部
docker exec -it web sh

# 看 log、停止、刪除
docker logs web
docker stop web && docker rm web

⚠️ 容器是無狀態的:刪掉 container,裡面寫的一切(包括資料庫檔案)都會消失。所以任何要留的資料都得放 volume——這是最多人踩的坑。

寫第一個 Dockerfile:從爛寫法到最佳實踐

Dockerfile 就是「怎麼從零把 image 蓋出來」的說明書。先看一個常見的 Python(FastAPI)範例:

# ---- 第一階段:build(編譯、裝相依套件)----
FROM python:3.12-slim AS builder
WORKDIR /app
# ① 先複製依賴清單再裝依賴:善用層快取,改程式碼不會讓依賴重裝
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# ---- 第二階段:runtime(只留執行所需,鏡像更小更安全)----
FROM python:3.12-slim
WORKDIR /app
# ② 非 root 執行:避免容器被攻破時直接拿到 root
RUN useradd --create-home appuser
COPY --from=builder /install /usr/local
COPY --chown=appuser:appuser app.py .
USER appuser
# ③ 健康檢查:讓 Docker 知道服務「真的活著」而不是程序還在
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
EXPOSE 8000
CMD ["uvicorn", "app.py:app", "--host", "0.0.0.0", "--port", "8000"]

這個寫法示範了 2026 年的四條黃金守則:

  1. 層快取友善:把「很少變動的」放前面(先 COPY requirements.txt 再裝依賴),「常常變動的」放後面(COPY . .)。Docker 每個指令會產生一層,層有快取——沒變的層直接沿用,改一行程式碼不必重裝整套依賴。
  2. 多階段構建(Multi-stage Build):第一個 FROM 負責編譯與裝套件,第二個 FROM 只帶走成果。編譯工具、暫存檔全部留在第一階段,最終 image 乾淨又小。這是 2026 年鏡像瘦身的標準答案——第三方實測中,Go 靜態編譯搭配 Distroless 基礎鏡像可以壓到 12.8MB、.NET 9 AOT 約 14.2MB、Rust(Axum)約 21.4MB,而沒做多階段的版本動輒 100MB 以上。
  3. 非 root 執行USER appuser 讓容器內程序以一般使用者身份跑,即使被攻破,攻擊者也拿不到宿主機 root。
  4. HEALTHCHECK:讓 Docker 與 Compose 能判斷服務是否「真正可用」,而不只是程序存在。

另外兩招進階密技:

  • 建置期機密:絕對不要把 API key 寫成 ARGENV——它們會留在 image 歷史裡,任何人 docker history 都讀得到。要用 BuildKit 的機密掛載,密鑰只在那一個 RUN 指令執行期間短暫存在:
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci --production   # 建置後密鑰即消失,不留任何 layer
  • 語言選型注意:Node.js/Python 這類大量呼叫底層 C 函式庫的語言,用 Debian-slim 或 Distroless 比 Alpine 穩——Alpine 的 musl libc 偶爾會跟編譯好的二進位檔打架;Go 這種純靜態編譯語言才適合放心用 Alpine。

Docker Compose:一次管好一群服務

單一容器用 docker run 就好,但真實專案幾乎都是「Web + 資料庫 + 快取 + 反向代理」的組合。Compose 讓你把整組服務用一份 YAML 描述,一條指令全部啟動。2026 年的用法重點:指令是 docker compose(空格,不是舊的 docker-compose 連字號);檔名用 compose.yaml不要再寫 version: "3.8"——這個欄位早已廢棄,直接從 services: 開始。

下面這個範例示範 2026 年的標準架構:PostgreSQL 資料庫鎖進 internal: true 的內網(無法主動連外、杜絕資料外洩),Web 服務同時接內外網當橋樑,Caddy 只在公網邊界開 80/443:

# compose.yaml
services:
  db:
    image: postgres:17-alpine
    # 具名 volume:資料庫資料真正落盤的地方
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD:?請設定 DB_PASSWORD}
    # 健康檢查:pg_isready 就緒後才啟動 web
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "app"]
      interval: 10s
      timeout: 5s
      retries: 5
    # 安全:丟掉所有 capabilities、檔案系統唯讀、禁止提權
    cap_drop: [ALL]
    read_only: true
    tmpfs: [/tmp:size=64m]
    networks:
      - backend

  web:
    build: .
    environment:
      DATABASE_URL: postgresql://app:${DB_PASSWORD}@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    # 開發時即時同步程式碼
    # 搭配 docker compose watch 使用(sync / restart / rebuild 三種動作)
    develop:
      watch:
        - path: ./app
          action: sync
          target: /app
    networks:
      - backend
      - frontend

  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data   # TLS 憑證持久化
    networks:
      - frontend

networks:
  frontend:
  backend:
    internal: true        # 🔒 這個網路的容器無法連外網

volumes:
  pgdata:
  caddy_data:

啟動方式:

docker compose up -d        # 背景啟動整組
docker compose ps           # 看狀態
docker compose logs -f web  # 追蹤某服務 log
docker compose up -d --build   # 程式碼變更後重建
docker compose down         # 停止並移除(volume 保留)

幾個關鍵設計直接對應實戰需求:

  • 具名 volume(Named Volume)pgdatacaddy_data 由 Docker 管理,適合放「刪了容器也要留」的資料(資料庫、憑證);開發時要即時反映程式碼修改,才用 bind mount(./app:/app 這種路徑對應)。
  • internal: true 網路:資料庫這類不該上網的服務鎖在內網,就算被打穿也無法把資料外送——2026 年自架文章(例如 n8n 教學Caddy 教學)推薦的標準隔離架構。
  • 健康檢查驅動啟動順序depends_on + service_healthy 取代舊式 depends_on 空等,資料庫真正 ready 才拉 web。
  • 環境變數:密碼用 ${VAR}.env 檔讀取,別寫死在 YAML 裡。

2026 年容器安全檢查清單

項目做法為什麼
非 rootDockerfile 結尾 USER appuser逃逸後拿不到 root
丟棄權限cap_drop: [ALL]移除容器繼承的 Linux capabilities
唯讀檔案系統read_only: true + tmpfs攻擊者無法寫入惡意檔案
禁止提權security_opt: [no-new-privileges:true]阻斷 setuid 提權路徑
資源上限deploy.resources.limits--memory / --cpus單一容器吃爆整台主機的防線
保持更新定期 apt upgrade Docker Engine容器逃逸漏洞(如 2026 年的 AF_ALG 相關 CVE)靠新版 seccomp 預設檔攔截
Rootless桌面/開發機可跑 rootless 模式daemon 本身沒 root 權限,逃逸也只能拿到一般使用者

docker run 加上資源限制的對應寫法:docker run --memory=512m --cpus=0.5 myapp。容器不是免死金牌——它隔離的是「程式」,不是「惡意程式」,所以安全設定要做全套(業界稱為 Defense in Depth)。

常用指令速查表

想做的事指令
列出所有 image/containerdocker images / docker ps -a
刪除沒在用的東西(清理大師)docker system prune -a
看鏡像分層歷史docker history <image>
進容器除錯docker exec -it <container> sh
複製檔案進出容器docker cp
本機 build 多平台(ARM+x86)docker buildx build --platform linux/amd64,linux/arm64 -t 帳號/專案 . --push
自動產生 Dockerfiledocker init(支援 Go/Python/Node/Rust/Java 等)

想更深入的話,可以把 Docker 接進自動化流程:搭配 GitHub Actions 完整教學 做 CI/CD、用 Tailscale 把自架服務收進內網、或學 Supabase 完整教學 看整套服務怎麼用 Compose 跑起來。

延伸閱讀

資料來源

📬 訂閱 most.tw 電子報

每週精選 AI 工具教學與技術乾貨,直接送到你的信箱。免費、隨時可退訂。

💬 有問題想討論?加 LINE 聯絡我

歡迎透過 LINE 官方帳號直接留言,我會盡快回覆你的問題。

加入 LINE 好友