iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
AI Engineering

30天用 Claude Code + LangGraph 實作個人化 AI 學習教練系列 第 29 篇

Day 29:部署上線(簡化版) - 從本地到生產環境

  • 分享至 

  • xImage
  •  

28 天來,系統只跑在你自己的電腦上。朋友想試用,就得登入你的電腦,這行不通。今天要把系統部署到雲端,讓任何人用瀏覽器就能存取。

做法是先用 Docker 把應用打包成容器(像一個隨身攜帶所有依賴的盒子),再推到 Render。Render 是適合初學者的雲端平台,會自動偵測 GitHub 上的程式碼更新,並重新部署應用。

概念:Docker 是一個行李箱

想像你要搬家到另一個城市。最簡單的方法是把所有東西放進一個行李箱,拎著行李箱上飛機。到了目的地,打開行李箱,東西都在,不用重新買。

Docker 容器就是這樣一個行李箱。你在行李箱裡放:

  • 應用程式碼
  • Python 3.11
  • 所有 pip 套件
  • 環境變數設定

不管在誰的電腦上打開這個行李箱,裡面的內容都一樣。「在我的機器上能跑」這個問題就此解決。

本地開發
  ↓ git push
GitHub 倉庫
  ↓ Render 偵測到新 commit
Render 拉代碼,執行 Dockerfile
  ↓ 容器啟動
生產環境公開 URL 可訪問

Render 支援自動部署:每次 push 到 GitHub,它就會自動重新建置並部署。


實作步驟

步驟 1:安裝 Docker

macOS 和 Windows

下載 Docker Desktop,安裝並啟動。

驗證安裝:

docker --version
# Docker version 24.x.x

Linux

sudo apt-get install docker.io
sudo usermod -aG docker $USER  # 無需 sudo 執行 docker

步驟 2:編寫後端 Dockerfile

檔案位置: backend/Dockerfile
狀態: 新建檔案
用途: 定義如何把後端打包成容器

# 使用官方 Python 基礎映像
FROM python:3.11-slim

# 設定工作目錄
WORKDIR /app

# 安裝系統依賴(某些 Python 套件需要編譯工具)
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 複製 requirements.txt
COPY requirements.txt .

# 安裝 Python 依賴
RUN pip install --no-cache-dir -r requirements.txt

# 複製整個 backend 資料夾
COPY . .

# 暴露 8000 埠
EXPOSE 8000

# 啟動應用
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

步驟 3:編寫 docker-compose 本地測試

檔案位置: docker-compose.yml(放在項目根目錄)
狀態: 新建檔案
用途: 用容器本地測試後端和前端

version: '3.8'

services:
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    environment:
      - SECRET_KEY=dev-secret-key-only-for-testing
      - DATABASE_URL=sqlite:///./app.db
    volumes:
      - ./backend:/app  # 開發模式下保持代碼同步
    command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NEXT_PUBLIC_API_URL=http://localhost:8000
    depends_on:
      - backend

步驟 4:編寫前端 Dockerfile

檔案位置: frontend/Dockerfile
狀態: 新建檔案
用途: 把前端打包成容器

# Build stage - 編譯 Next.js
FROM node:18-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci

COPY . .

# 建立環境變數
ARG NEXT_PUBLIC_API_URL=http://localhost:8000
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}

RUN npm run build

# Production stage - 執行應用
FROM node:18-alpine

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --only=production

COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public

EXPOSE 3000

CMD ["npm", "start"]

步驟 5:本地測試容器

# 建立並啟動容器(第一次會下載基礎映像和依賴,較慢)
docker-compose up --build

# 檢查服務是否啟動
# 後端:http://localhost:8000/docs
# 前端:http://localhost:3000

如果看到後端的 Swagger 文件頁面,容器設定正確。

停止容器:

docker-compose down

步驟 6:建立 Render 帳號並連接 GitHub

  1. 前往 render.com
  2. 用 GitHub 帳號登入(或建立新帳號)
  3. 授權 Render 存取你的 GitHub 倉庫

步驟 7:部署後端服務

在 Render dashboard:

  1. 點 「New +」 → 「Web Service」

  2. 連接你的 GitHub 倉庫

  3. 設定如下:

    • Name: learning-coach-backend
    • Runtime: Python 3
    • Build Command: pip install -r requirements.txt
    • Start Command: uvicorn main:app --host 0.0.0.0 --port 8000
    • Root Directory: backend(如果後端在 backend 資料夾)
  4. 點 「Advanced」,設定環境變數:

    SECRET_KEY = (生成一個隨機字串,見下方)
    DATABASE_URL = sqlite:///./app.db
    
  5. 點 「Create Web Service」

Render 會自動:

  • 從 GitHub 拉取程式碼
  • 執行 Build Command
  • 啟動應用
  • 分配一個公開 URL(類似 https://learning-coach-backend.onrender.com)

步驟 8:部署前端服務

  1. 點 「New +」 → 「Web Service」

  2. 連接同一個 GitHub 倉庫

  3. 設定如下:

    • Name: learning-coach-frontend
    • Runtime: Node
    • Build Command: npm install && npm run build
    • Start Command: npm start
    • Root Directory: frontend
  4. 點 「Advanced」,設定環境變數:

    NEXT_PUBLIC_API_URL = https://learning-coach-backend.onrender.com
    

    (用剛才部署的後端 URL)

  5. 點 「Create Web Service」

步驟 9:生成安全的 SECRET_KEY

在終端執行:

# macOS / Linux
openssl rand -hex 32

# Windows PowerShell
[System.Convert]::ToBase64String((1..32 | ForEach-Object {Get-Random -Maximum 256})) | Select-Object -First 32

複製輸出的字串,貼到 Render 的環境變數 SECRET_KEY。

步驟 10:查看部署進度和日誌

在 Render dashboard:

  1. 點進「Backend」服務
  2. 「Logs」標籤查看即時日誌
  3. 「Events」標籤查看部署歷史

如果有錯誤,日誌會告訴你。

步驟 11:測試生產環境

# 替換成你的 Render URL
BACKEND_URL="https://learning-coach-backend.onrender.com"

# 測試後端 health check
curl $BACKEND_URL/docs

# 註冊測試用戶
curl -X POST $BACKEND_URL/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"prod@example.com","password":"password123"}'

# 應該回傳 token

打開前端 URL(類似 https://learning-coach-frontend.onrender.com),應該會看到登入頁。


常見問題與解決

問題 1:「Deployment failed」

查看 Logs,通常是因為:

  1. 依賴安裝失敗

    ModuleNotFoundError: No module named 'fastapi'
    

    解決:確認 requirements.txt 在正確的位置(backend/requirements.txt)

  2. 環境變數缺少

    KeyError: 'SECRET_KEY'
    

    解決:在 Render 的環境變數中加上缺少的變數

  3. Port 綁定失敗

    Address already in use
    

    解決:確認 Start Command 用的是 --port 8000(Render 預期 8000)

問題 2:「502 Bad Gateway」

應用啟動了但收不到請求。通常是:

  • Start Command 有誤
  • 應用內部崩潰

查看日誌,找出具體錯誤訊息。

問題 3:前端連不到後端

前端收到 CORS 錯誤或超時。解決方法:

  1. 檢查環境變數 NEXT_PUBLIC_API_URL 是否設對
  2. 確認後端服務已啟動(查看 Render dashboard)
  3. 在後端 main.py 加上 CORS 設定:
from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 簡化版允許所有來源
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

問題 4:資料庫每次重啟都清空

Render 上的容器重啟時,SQLite 資料庫檔案(app.db)會遺失。

暫時解決:改用 PostgreSQL(Render 提供免費版本,見延伸思考)

問題 5:部署後程式碼改動沒有生效

Render 有快取。解決方法:

  1. 在 Render dashboard 手動點「Manual Deploy」
  2. 或者 push 一個新 commit 自動觸發部署

當日驗收清單

應用成功容器化

  • 檢查:執行 docker-compose up,兩個服務都啟動,沒有錯誤

部署到 Render 成功

  • 檢查:Render dashboard 看到綠色「Live」狀態

公開 URL 可存取

  • 檢查:用瀏覽器打開前端 URL,能看到登入頁

後端 API 正常

  • 檢查:curl https://xxx/docs 能看到 API 文件頁面

認證流程在生產環境可用

  • 檢查:用公開 URL 登入,能獲得 token,能存取 /auth/me

查看日誌

  • 檢查:在 Render dashboard 的 Logs 裡看到應用啟動訊息

前後端整合正常

  • 檢查:前端登入成功後能看到儀表板

監控與維護

查看應用狀態

Render dashboard → 你的服務 → 頁面頂部顯示狀態:

  • Live(綠色):應用運行正常
  • Deploying(黃色):正在部署
  • Suspended(灰色):免費層超過時數限制

查看日誌

Render dashboard
  ↓
你的服務
  ↓
Logs 標籤
  ↓
看到所有應用輸出

手動重啟應用

如果應用出現異常:

  1. Render dashboard → 服務
  2. 「Manual Deploy」 → 選「Deploy latest commit」

監控效能

Render 提供基本的 CPU、記憶體使用率圖表。免費層資源有限,如果看到經常 100%,可能需要升級。


常見問題

Dockerfile 層疊太多,映像檔很大

每個 RUN 指令都會建立新層。壞的寫法:

RUN apt-get update
RUN apt-get install -y gcc
RUN apt-get install -y make
RUN rm -rf /var/lib/apt/lists/*  # 這層前面的層已經存了 cache 檔案

改成:

RUN apt-get update && apt-get install -y gcc make && rm -rf /var/lib/apt/lists/*

複製整個專案,包括 .git、node_modules、pycache

映像檔會變得非常大,部署也會很慢。

解決:建立 .dockerignore 檔案(類似 .gitignore):

__pycache__
*.pyc
.git
.gitignore
.env
.DS_Store
node_modules
dist
build

硬寫密碼或 API key 進 Dockerfile

只要有人看到 Dockerfile,密碼就等於外洩。

解決:所有敏感資訊都用環境變數,從 Render 設定注入。

忘記設定 CORS,前端收到「跨域請求被拒」

解決:在後端 main.py 前面加上 CORS middleware(見上方「問題 3」)。


明天是最後一天。沒有新功能,只是把整個系統梳理一遍、寫完整的 README、錄一個演示影片、分享 30 天的心得。

部署後,系統正式上線。任何人用公開 URL 就能體驗個人化 AI 學習教練。


上一篇
Day 28:基本單元測試 - 自動化測試確保應用品質
下一篇
Day 30:發表與收尾 - 從 Prototype 到 Product
系列文
30天用 Claude Code + LangGraph 實作個人化 AI 學習教練 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言