今天要幫這段旅程畫上句號:
把 Todo API 打包成「一鍵啟動」的完整 Docker 應用。
👉 用一行指令啟動整個環境(API + PostgreSQL)
👉 資料持久化
👉 健康檢查
👉 生產級設定
這是現在的完整結構:
ts-todo-api/
├─ src/
│ ├─ controllers/
│ ├─ services/
│ ├─ dto/
│ ├─ routes/
│ └─ index.ts
├─ prisma/
│ ├─ schema.prisma
│ └─ migrations/
├─ Dockerfile
├─ docker-compose.yml # 開發用
├─ docker-compose.prod.yml # 生產用
├─ package.json
├─ tsconfig.json
└─ .env
# ========= Build stage =========
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ========= Run stage =========
FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S app && adduser -S app -G app
USER app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/prisma ./prisma
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/index.js"]
特點:
/health
這份 Compose 可以讓整個專案「一鍵啟動」。
version: "3.9"
services:
api:
build:
context: .
dockerfile: Dockerfile
image: ts-todo-api:latest
container_name: ts-todo-api
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/todo
depends_on:
- db
restart: always
db:
image: postgres:16-alpine
container_name: todo-db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: todo
volumes:
- db_data:/var/lib/postgresql/data
restart: always
volumes:
db_data:
這樣你只要執行:
docker compose -f docker-compose.prod.yml up -d --build
整個應用就會啟動(包含 PostgreSQL)。
在 src/index.ts 新增一個 /health 路由:
import express from "express";
const app = express();
app.get("/health", (req, res) => res.status(200).json({ status: "ok" }));
app.listen(3000, () => console.log("🚀 Todo API running on port 3000"));
Docker 的健康檢查會定期呼叫這個端點,確保 API 正常。
1️⃣ 建構映像:
docker compose -f docker-compose.prod.yml build
2️⃣ 啟動專案:
docker compose -f docker-compose.prod.yml up -d
3️⃣ 查看狀態:
docker compose -f docker-compose.prod.yml ps
輸出:
NAME SERVICE STATUS PORTS
ts-todo-api api running (healthy) 0.0.0.0:3000->3000/tcp
todo-db db running 0.0.0.0:5432->5432/tcp
🎉 看到 (healthy) 就代表成功!
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"task":"Docker 化成功"}'
curl http://localhost:3000/todos
輸出:
[
{
"id": 1,
"task": "Docker 化成功",
"done": false
}
]
停掉容器:
docker compose -f docker-compose.prod.yml down
重啟:
docker compose -f docker-compose.prod.yml up -d
再次查詢:
curl http://localhost:3000/todos
資料依然在 ✅
Volume 成功保存 PostgreSQL 資料。
讓別人能一看就懂怎麼用 👇
# 🐳 TS Todo API – Docker 化版本
這是一個以 TypeScript + Express + Prisma + PostgreSQL 打造的 Todo API,
並使用 Docker 容器化,支援一鍵啟動與持久化資料。
---
## 📦 啟動方式
```bash
docker compose -f docker-compose.prod.yml up -d --build
API 啟動後:
http://localhost:3000/todos
| 目錄/檔案 | 用途 |
|---|---|
src/ |
Express 程式碼 |
prisma/ |
資料庫設定與 Migration |
Dockerfile |
多階段建置設定 |
docker-compose.prod.yml |
生產環境設定 |
.env |
環境變數(DB 連線) |
GET /health
回傳:
{ "status": "ok" }
docker compose -f docker-compose.prod.yml down -v
這九天的 Docker 系列,從零到完整應用,我學到了:
以前覺得部署是神秘又麻煩的事,
但現在只要一句指令,就能在任何電腦、任何雲端跑起來:
docker compose -f docker-compose.prod.yml up -d
✨ 這就是「基礎後端工程師」邁向「DevOps 實戰」的第一步。