本文說明 Docker 是什麼為何使用,以及如何在本專案(Spring Boot + PostgreSQL + Gradle)中 建置映像執行容器,並逐項解釋相關指令與檔案。專案根目錄已提供:

檔案 用途
Dockerfile 多階段建置:編譯 JAR → 輕量 JRE 映像
docker-compose.yml 同時啟動 PostgreSQL 與應用程式
.dockerignore 建置脈絡排除不必要檔案,加速建置

1. Docker 是什麼?

Docker 是一套 容器化(containerization) 平台。它把應用程式及其依賴(執行環境、函式庫、設定方式)打包成 映像(image),再從映像啟動 容器(container)

1.1 映像(Image)

  • 唯讀的「範本」,類似 虛擬機範本,但更輕量。
  • 層(layer) 堆疊而成;相同層可被多個映像共用,節省空間。
  • 常見來源:自己用 Dockerfile 建置,或從 Docker Hub 拉取官方映像(例如 postgreseclipse-temurin)。

1.2 容器(Container)

  • 映像 執行後 的實例,有獨立的檔案系統視圖、網路、程序空間。
  • 虛擬機 不同:容器共用宿主機的 Linux 核心(在 macOS/Windows 上由 Docker Desktop 提供 Linux VM),啟動快、資源開銷小。

1.3 Dockerfile

  • 文字腳本,描述「如何從基底映像一步步建立出自訂映像」。
  • 每一行指令通常產生一個 新層;指令順序影響 建置快取(不變的前段可重用)。

1.4 Docker Compose

  • YAML 定義 多個服務(例如:資料庫 + Web 應用),一鍵啟停、設定網路與依賴順序。
  • 本專案的 docker-compose.yml 會啟動 PostgreSQLBaasid 應用,並讓應用透過 服務名稱 postgres 連線資料庫。

1.5 為什麼要用 Docker 包裝本專案?

  • 環境一致:開發、CI、正式機都用同一套映像,減少「我機器可以跑」問題。
  • 依賴清楚:Java 21、JRE、JAR 都包在映像或 Compose 裡。
  • 資料庫一鍵起:Compose 內含 PostgreSQL,並掛載 sql/init.sql 做首次初始化。

2. 專案內 Docker 相關檔案說明

2.1 Dockerfile(多階段建置)

本專案採 多階段建置(multi-stage build)

  1. 第一階段(build:使用 JDK 21eclipse-temurin:21-jdk-jammy),執行 ./gradlew bootJar 產生可執行 JAR。
  2. 第二階段(最終映像):只保留 JRE 21eclipse-temurin:21-jre-jammy)與編譯好的 JAR,體積較小、攻擊面較小。

重點指令對照:

Dockerfile 指令 說明
FROM ... AS build 命名此建置階段為 build,後續可 COPY --from=build
WORKDIR /app 之後 RUNCOPY 的預設目錄設為 /app
COPY gradlew ... 將 Gradle Wrapper 與專案原始碼複製進映像(需與本機 gradlew 一致)。
RUN chmod +x gradlew && ./gradlew bootJar ... 赋予執行權並建置;-x test 略過測試以縮短映像建置時間(可依需求移除)。
FROM eclipse-temurin:21-jre-jammy 新的最終階段,不含 JDK 編譯器。
COPY --from=build /app/build/libs/*.jar app.jar 只從建置階段取出 JAR,檔名在 Gradle 依 build.gradleversion 可能為 baasid-1.0.0.jar,用萬用字元避免寫死。
EXPOSE 8080 文件用途,宣告容器內應用監聽 8080;不會自動對外開埠,對外對映在 docker run -p 或 Compose ports 設定。
ENTRYPOINT ["java", "-jar", "/app/app.jar"] 容器啟動時執行的固定命令;Spring Boot 可執行 JAR 內含主類別與依賴。

2.2 docker-compose.yml

區塊 說明
services.postgres 使用官方 postgres:16-alpine;環境變數建立資料庫 baasid、帳密與本機 application.yml 預設一致。
volumes: ./sql/init.sql -> /docker-entrypoint-initdb.d/ PostgreSQL 映像會在 資料目錄空白時 自動執行此目錄下的 .sql,建立表與種子資料。
healthcheck pg_isready 確認資料庫可接受連線,避免應用在 DB 未就緒時啟動失敗。
services.app build: . 表示用目前目錄的 Dockerfile 建置映像。
environment.SPRING_DATASOURCE_URL 覆寫 Spring Boot 的 spring.datasource.url主機名必須是 postgres(Compose 內建 DNS 服務名),不可寫 localhost(在容器內 localhost 是容器自己)。
depends_on.condition: service_healthy 等 PostgreSQL 健康檢查通過後才啟動 app(需 Compose v2 與支援 condition 的版本)。

2.3 .dockerignore

  • 類似 .gitignore不要build/.gradle/.git/ 等複製進建置脈絡,可減少傳輸量並避免覆蓋映像內編譯結果。

3. 前置需求

  • 已安裝 Docker EngineDocker Compose(Docker Desktop 通常兩者皆含)。
  • 在專案根目錄(與 Dockerfiledocker-compose.yml 同層)執行下列指令。

終端機中可確認版本:

docker version
docker compose version

指令說明:

指令 說明
docker version 顯示 Client/Server API 版本;確認 Docker 守護行程(daemon)有在運行。
docker compose version 顯示 Compose 外掛版本(Compose V2 語法為 docker compose,舊版獨立程式為 docker-compose)。

若你的環境仍使用舊指令,請將本文的 docker compose 改成 docker-compose(連字號)。


4. 方式一:Docker Compose(建議)

一次啟動 PostgreSQL + Baasid,並自動初始化資料庫腳本。

4.1 建置並以背景執行

docker compose up --build -d

各參數說明:

參數 說明
docker compose 讀取目前目錄的 docker-compose.yml,管理其中定義的服務。
up 建立網路、建立並啟動容器;映像不存在則先建置。
--build 啟動前先 重新建置 映像(程式碼變更後建議加上,確保 JAR 為最新)。
-d detached,在背景執行,終端機不會卡住顯示 log。

4.2 查看執行狀態與日誌

docker compose ps
docker compose logs -f app
指令 說明
docker compose ps 列出 Compose 專案中各容器的狀態、埠對映。
docker compose logs -f app 持續追蹤名為 app 的服務日誌;按 Ctrl+C 停止追蹤(不會停止容器)。

4.3 停止並移除容器

docker compose down
指令 說明
docker compose down 停止並刪除 Compose 建立的容器與預設網路;不會刪除映像。

若要連匿名 volume 一併刪除(會清掉資料庫檔案,慎用):

docker compose down -v

-v:移除 Compose 宣告的 volumes

4.4 驗證 API

應用對外為 宿主機 8080(見 ports: "8080:8080"):

  • Swagger UI:http://localhost:8080/swagger-ui.html
  • 登入:POST http://localhost:8080/auth/login

5. 方式二:僅建置與執行單一應用映像

自行在外部提供 PostgreSQL(本機或雲端),可只建置 app 映像。

5.1 建置映像

docker build -t baasid:1.0.0 .
參數 說明
docker build 依目前目錄的 Dockerfile 建置映像。
-t baasid:1.0.0 tag:映像名稱 baasid,標籤 1.0.0(可自訂,例如 latest)。
. 建置脈絡(context):把目前目錄(遵守 .dockerignore)送給 Docker daemon。

5.2 執行容器(連到宿主機的 PostgreSQL)

假設 PostgreSQL 跑在宿主機的 5432,在 Linux 上可使用:

docker run --rm -p 8080:8080 \
  -e SPRING_DATASOURCE_URL=jdbc:postgresql://host.docker.internal:5432/baasid \
  -e SPRING_DATASOURCE_USERNAME=postgres \
  -e SPRING_DATASOURCE_PASSWORD=postgres \
  baasid:1.0.0
參數 說明
docker run 從映像建立並啟動一個新容器。
--rm 容器結束後 自動刪除 容器,適合測試。
-p 8080:8080 埠對映宿主埠:容器埠;左側可改成例如 18080:8080
-e KEY=value 設定 環境變數,Spring Boot 會對應到 application.yml(例如 SPRING_DATASOURCE_URLspring.datasource.url)。
host.docker.internal Docker Desktop(Mac/Windows)提供的特殊主機名,指向宿主機;Linux 上可能需加 --add-host=host.docker.internal:host-gateway 或改用實際 IP。

5.3 查看映像與容器

docker images
docker ps -a
指令 說明
docker images 列出本機映像、大小、標籤。
docker ps 列出 執行中 的容器。
docker ps -a 列出 全部 容器(含已停止)。

6. Spring Boot 與環境變數對照

Compose 與 docker run -e 常用變數:

環境變數 對應設定 說明
SPRING_DATASOURCE_URL spring.datasource.url JDBC URL;Compose 內請用主機名 postgres
SPRING_DATASOURCE_USERNAME spring.datasource.username 資料庫使用者。
SPRING_DATASOURCE_PASSWORD spring.datasource.password 資料庫密碼。
JWT_SECRET jwt.secret 自訂屬性;正式環境請改為強隨機字串,勿使用範例預設值。
SPRING_PROFILES_ACTIVE spring.profiles.active 例如 dev 會載入 application-dev.yml(含 ddl-auto: update 等)。

注意: 預設 application.yml 使用 spring.jpa.hibernate.ddl-auto: validate,資料表須已存在(sql/init.sql 或手動建立)。若僅本地實驗,可透過 profile 調整(需自行評估風險)。


7. 疑難排解

現象 可能原因 處理方向
應用啟動失敗:無法連線 DB 資料庫尚未 healthy 或 URL 錯誤 確認 SPRING_DATASOURCE_URL 主機名在 Compose 網路內為 postgres;查看 docker compose logs postgres
validate 與 schema 不符 表結構與 Entity 不一致 對照 sql/init.sql 與 JPA Entity,或調整設定(僅限開發環境)。
建置很慢 未使用快取、網路下載依賴 確認 .dockerignore 已排除 build/;重複建置時前段層可命中快取。
埠已被占用 本機 8080 或 5432 已被使用 修改 docker-compose.ymlports 左側,例如 "8081:8080"

8. 指令速查表

指令 用途
docker compose up --build -d 建置並背景啟動 Compose 全部服務
docker compose down 停止並移除 Compose 容器與預設網路
docker compose logs -f <服務名> 追蹤指定服務日誌
docker build -t <名>:<標籤> . 建置單一映像
docker run --rm -p 8080:8080 -e ... <映像> 以前台執行單一容器(可搭配 -d 背景)
docker images / docker ps -a 檢視映像與容器

9. 安全與正式環境提醒

  • 不要在映像或公開儲存庫 放入正式資料庫密碼、JWT 密鑰;應使用 環境變數Docker secrets 或雲端密鑰管理。
  • 本文件範例之帳密僅供本機/開發使用。
  • 正式環境請啟用 HTTPS、限制資料庫曝露埠、定期更新基底映像(eclipse-temurinpostgres)。

以上說明對應專案根目錄的 Dockerfiledocker-compose.yml.dockerignore。若升級 Spring Boot 或變更 server.port,請同步調整 EXPOSE 與 Compose ports