最後一哩路:把專案打包成 Docker 映像檔,讓它在任何機器上都能 一致地執行;再用 Docker Compose 把「MySQL + API」包成一鍵啟動的整組服務。

為什麼需要 Docker?

「在我電腦上明明可以跑!」——傳統部署的萬年名句。 問題出在環境差異:JDK 版本、系統函式庫、環境變數、資料庫版本…… Docker 的解法是把應用程式與它需要的整個執行環境打包在一起:

lP8.6cm 名詞 & 意義
映像檔 Image & 唯讀的打包成品:程式+執行環境+設定(像「安裝光碟」)
容器 Container & 映像檔執行起來的實體(像「開機後的電腦」),可同時跑多個
Registry & 存放映像檔的倉庫(Docker Hub 就是官方公共倉庫)
Dockerfile & 描述「如何建置映像檔」的腳本

映像檔在你電腦上能跑,在同事電腦、測試機、雲端上就都能跑—— 因為執行環境已經「凍結」在映像檔裡了。 這也是為什麼 Spring Boot(內嵌 Tomcat、單一 JAR)與 Docker 是天作之合。

Dockerfile:逐行解說

專案根目錄的 採用多階段建置(Multi-stage Build):

多階段建置的流程與效益:

Dockerfile 的每個指令會產生一「層」快取,只要該步驟的輸入沒變就直接重用。 相依套件很少變、原始碼天天變——所以先只複製 下載套件(可快取), 再複製 編譯。這樣日常改程式重建映像檔時, 不用重新下載幾百 MB 的相依套件,建置時間從幾分鐘縮到幾十秒。

排除不需要送進建置環境的檔案(類似 ):

建置映像檔:docker build

# 在 bookstore-api/ 目錄下執行(注意最後的「.」=建置上下文為目前目錄)
#   -t 名稱:標籤   幫映像檔取名字與版本標籤
docker build -t bookstore-api:1.0.0 .

# 查看建好的映像檔
docker images
# REPOSITORY      TAG      IMAGE ID       CREATED         SIZE
# bookstore-api   1.0.0    3f5a1b2c4d6e   10 seconds ago  ~300MB

第一次建置需要下載基底映像檔與 Maven 套件,會花數分鐘; 之後拜 Layer 快取所賜會快非常多。

執行容器:docker run

# 執行容器:
#   -d          在背景執行(detached)
#   -p 8080:8080 連接埠對映「本機:容器」
#   -e KEY=VAL  設定環境變數(覆寫 application.yml 的預設值)
#   --name      幫容器取名字,方便後續操作
docker run -d --name bookstore-api \
  -p 8080:8080 \
  -e DB_HOST=host.docker.internal \
  -e DB_PASSWORD=root1234 \
  bookstore-api:1.0.0

# 追蹤日誌(-f 持續輸出,Ctrl+C 離開)
docker logs -f bookstore-api

容器有自己獨立的網路空間——在容器裡連 , 連到的是「容器自己」,不是你電腦上的 MySQL。 所以上面把 設為 (Docker Desktop 提供的特殊主機名稱,指向宿主機)。 下一節的 Docker Compose 會用更優雅的方式解決這個問題。

Docker Compose:一鍵啟動整組服務

手動管理「先啟動 MySQL、等它就緒、再啟動 API、還要設定網路」太繁瑣。 Docker Compose 把整組服務宣告在一個 YAML 檔裡:

三個關鍵設計:

  • 服務名稱=主機名稱:Compose 自動建立虛擬網路, 直接用 連資料庫 (所以環境變數設 )。

  • healthcheck + depends_on:MySQL 容器「啟動」不代表 「初始化完成」(可能差幾十秒)。健康檢查確認 MySQL 真的能服務後, 才啟動 app,避免連線失敗。

  • 具名資料卷 mysql-data:資料庫檔案存在 Docker 管理的卷中, 容器刪掉重建,資料依然保留。

啟動與驗證:

# 建置映像檔並在背景啟動所有服務
docker compose up -d --build

# 查看服務狀態(等 mysql 顯示 healthy、app 顯示 running)
docker compose ps

# 追蹤 API 日誌,看到 "Started BookstoreApiApplication" 就緒
docker compose logs -f app

# 測試 API(此時整組服務都跑在 Docker 裡!)
curl http://localhost:8080/api/books

# 全部停止並移除容器(資料卷保留,資料不會消失)
docker compose down

# 連資料卷一起刪除(資料庫歸零,重新開始)
docker compose down -v

常用指令速查

lP7.2cm 指令 & 用途
() & 列出執行中(含已停止)的容器
& 列出本機映像檔
& 追蹤容器日誌
& 進入容器內的終端機
& 停止/啟動容器
& 刪除容器
& 刪除映像檔
& 建置並啟動整組服務
& 停止並移除整組服務
& 清理沒用到的容器/映像檔/快取

完整驗證:從零到整組服務上線

最終驗收——確認任何一台裝了 Docker 的電腦都能跑起整套系統:

  1. ,等待建置完成。

  2. 確認 與 都在執行。

  3. 開啟 Postman,跑一次第 6 章的 Collection Runner——全部 PASS。

  4. 收工;下次 資料依然都在。

你已經完成了一個具備認證授權、連接真實資料庫、 可容器化部署、附完整測試集合的後端專案—— 這正是業界後端工程師日常工作的縮影。 附錄提供常見問題排除與延伸學習方向,祝學習順利!