iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0

經過了 28 天的學習與實戰,我們終於來到了最後的關鍵一哩路:部署。一個應用程式無論功能多強大,如果不能穩定地在伺服器上運行,就無法真正發揮價值。今天,我們將探討如何將 FastAPI AI 應用打包、管理,並透過反向代理提供服務,甚至啟用 GPU 支援。

今天我們將採用一套更現代化、整合度更高的工具來完成部署:Docker ComposeCaddy Server。這套組合能讓我們用一個指令就啟動包含應用、資料庫和反向代理在內的完整服務。

什麼是 Docker Compose?

如果說 Dockerfile 是用來定義「一個」容器的藍圖,那麼 Docker Compose 就是用來定義和運行「多個」容器應用的劇本。我們可以透過一個 docker-compose.yml 設定檔,來描述我們的服務架構,例如:「我的應用需要一個 FastAPI 容器、一個 PostgreSQL 資料庫容器,以及一個 Caddy 反向代理容器」,然後用 docker-compose up 指令一鍵啟動所有服務。

Caddy:內建自動化 HTTPS 的現代反向代理

之前我們提到了 Nginx,而 Caddy 則是一個更年輕的替代方案,它最大的特色就是自動化 HTTPS。只要您的伺服器有公網 IP 和一個指向它的域名,Caddy 就會自動向 Let's Encrypt 申請、設定並續訂 SSL 憑證,完全無需手動操作,極大地簡化了安全設定。

一個基礎的 Caddyfile 設定極其簡潔:

Caddyfile

your-domain.com {
    # 將所有請求反向代理到名為 "fastapi_app" 的容器的 8000 port
    reverse_proxy fastapi_app:8000
}

這邊就簡單地把 80 port 導進來就好:

:80 {
    reverse_proxy fastapi_app:8000
}

整合範例:FastAPI + PostgreSQL + Caddy

現在,讓我們用 docker-compose.yml 把所有東西串起來。請確保您的專案目錄結構如下:

.
├── app/
│   ├── main.py              # FastAPI 程式碼
│   ├── requirements.txt     # Python 依賴套件
│   └── Dockerfile.fastapi   # FastAPI 的 Dockerfile
│
├── Caddyfile                # Caddy 的設定檔
├── docker-compose.yaml      # Docker Compose 主設定檔
└── .env                     # 環境變數 (用於存放密碼)

1. Dockerfile

這個檔案負責打包你的 FastAPI 應用。

# 步驟 1: 選擇包含 CUDA 和 Python 的基礎映像
# 我們選擇 CUDA 12.4.1 的開發版,它通常已包含 Python
FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04

# 步驟 2: 設定環境變數,避免互動式提示
ENV TZ=Asia/Taipei
ENV DEBIAN_FRONTEND=noninteractive

# 步驟 3: 安裝 Python 3.10+ 和 pip
RUN apt-get update && apt-get install -y \
    python3.10 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

# 步驟 4: 設定工作目錄
WORKDIR /app

# 步驟 5: 複製 requirements.txt 並安裝依賴套件
COPY ./requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt

# 步驟 6: 複製應用程式程式碼
COPY . .

# 步驟 7: 開放容器的 8000 port
EXPOSE 8000

# 步驟 8: 執行 FastAPI 服務
CMD ["fastapi", "run", "main.py", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

2. docker-compose.yaml (核心劇本)

這個檔案定義了我們的三個服務以及它們之間的關係。

version: "3.9"

services:
  # 1. FastAPI 應用程式服務 (支援 GPU)
  fastapi_app:
    build:
      context: ./app
      dockerfile: Dockerfile.fastapi
    restart: unless-stopped
    networks:
      - app_network
    depends_on:
      - db
    # <<<<<<<< 這是啟用 GPU 的關鍵設定 >>>>>>>>
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all  # "all" 表示使用所有可用的 GPU
              capabilities: [gpu]

  # 2. PostgreSQL 資料庫服務
  db:
    image: postgres:15-alpine
    restart: unless-stopped
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - app_network
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}

  # 3. Caddy 反向代理服務
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"       # HTTP
      - "443:443"     # HTTPS
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
    networks:
      - app_network
    depends_on:
      - fastapi_app

# 定義網路和資料卷
networks:
  app_network:
    driver: bridge

volumes:
  postgres_data:

其中 fastapi_app 服務中有一個 deploy 區塊:

  • deploy: 這是 Docker Compose 中用來定義服務部署與執行階段相關設定的標準區塊。
  • resources.reservations.devices: 我們在這裡宣告這個服務需要預留硬體資源,具體來說是「裝置 (devices)」。
  • driver: nvidia: 指定我們要使用的是 NVIDIA 的驅動。
  • count: all: 表示請求主機上「所有」可用的 GPU。您也可以指定特定的 GPU 數量(例如 count: 1)或特定的 GPU ID。
  • capabilities: [gpu]: 這是必須的選項,用來賦予容器存取 GPU 的能力。

GPU 支援的前置條件

重要提醒:要讓 Docker 容器能夠使用 GPU,系統必須額外安裝 NVIDIA Container Toolkit

  • 如果使用 Docker Desktop:恭喜!Docker Desktop 內建了 GPU 支援,無需額外安裝。
  • 如果使用 Docker Engine(Linux 伺服器環境):需要手動安裝 NVIDIA Container Toolkit。

如果沒有安裝,就直接啟動的話,會看到這個錯誤:

Error response from daemon: could not select device driver "nvidia" with capabilities: [[gpu]]

詳細的安裝說明可以參考文件。以下將以 Ubuntu 系統為例進行說明:

在 Ubuntu/Debian 系統上安裝 NVIDIA Container Toolkit:

# 新增 NVIDIA 的套件庫
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# 更新
sudo apt-get update
# 安裝 NVIDIA Container Toolkit
export NVIDIA_CONTAINER_TOOLKIT_VERSION=1.17.8-1
  sudo apt-get install -y \
      nvidia-container-toolkit=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      nvidia-container-toolkit-base=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      libnvidia-container-tools=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      libnvidia-container1=${NVIDIA_CONTAINER_TOOLKIT_VERSION}
# 重新啟動 Docker 服務
sudo systemctl restart docker

安裝完成後,可以用以下指令測試 GPU 是否可在容器中正常使用:

docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

或是也可以直接在 FastAPI 的 main.py 加入一些測試的程式碼:

import torch
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import List, Optional

# --- Pydantic Models for Response ---
class GpuDevice(BaseModel):
    index: int = Field(..., description="GPU 裝置索引")
    name: str = Field(..., description="GPU 型號名稱")

class GpuInfo(BaseModel):
    cuda_available: bool = Field(..., description="CUDA 是否可用")
    device_count: int = Field(..., description="可用的 GPU 數量")
    devices: Optional[List[GpuDevice]] = Field(None, description="GPU 裝置列表")

# --- FastAPI App ---
app = FastAPI(
    title="GPU Check API",
    description="一個用於檢查 PyTorch CUDA 可用性的簡單 API",
    version="1.0.0"
)

@app.get("/api/gpu-check", response_model=GpuInfo)
def check_gpu_status():
    """
    檢查 PyTorch 是否可以使用 CUDA GPU,並返回詳細資訊。
    """
    is_available = torch.cuda.is_available()
    device_count = torch.cuda.device_count() if is_available else 0
    devices_info = []

    if is_available:
        for i in range(device_count):
            devices_info.append(
                GpuDevice(index=i, name=torch.cuda.get_device_name(i))
            )

    return GpuInfo(
        cuda_available=is_available,
        device_count=device_count,
        devices=devices_info if devices_info else None
    )

@app.get("/")
def read_root():
    return {"message": "Welcome to the GPU Check API. Go to /api/gpu-check to see GPU status."}

如何啟動?

準備好以上三個檔案 (Dockerfile, Caddyfile, docker-compose.yml) 後,只需在專案根目錄執行一個指令:

# -d 參數代表在背景分離模式 (detached mode) 運行
docker compose up --build -d

Caddy 會自動偵測到 Caddyfile 的設定,開始代理流量到你的 FastAPI 應用,如果設定了域名,它還會默默地在背景幫你處理好 HTTPS 的一切。至此,一個包含資料庫、應用和安全反向代理的生產級服務就成功運行起來了!

確認是否可以使用 GPU

可以使用 Postman 測試一下 API (http://localhost/api/gpu-check)

也可以進入 Docker 容器中測試 nvidia-smi 指令,有 Docker Desktop 的話就可以直接從 UI 介面上進去下指令:

或是直接在 terminal 下指令也可以

小結

今天學習了使用 Docker Compose 和 Caddy 來部署 FastAPI 應用。透過一個指令即可啟動包含 GPU 支援的完整服務架構。


上一篇
[Day 28] 實戰範例 (四):多模型並行處理
系列文
用 FastAPI 打造你的 AI 服務29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言