Django Docker 容器化部署完全指南 | Django 教學
將 Django 應用部署到生產環境是開發流程的最後一哩路,而 Docker(容器化技術) 已成為現代部署的主流方案。透過 Docker,你可以將應用程式、執行環境和所有依賴打包成一個標準化的 映像(Image),確保「在我的機器上能跑」的程式碼在任何環境都能一致運行。本篇將從 Docker 基礎概念出發,逐步帶你撰寫 Dockerfile(含 多階段建置 與非 root 使用者安全設定)、設定 .dockerignore、管理 requirements.txt,再用 docker-compose.yml 編排 Django + PostgreSQL + Redis 的完整服務架構,涵蓋環境變數管理、Volume(資料卷) 持久化、Healthcheck(健康檢查) 設定、開發與生產環境的 docker-compose 分離策略,以及常見問題排除。
Docker 基礎概念
在開始撰寫 Dockerfile 之前,先釐清幾個核心概念。
映像(Image)vs 容器(Container)
| 概念 | 映像(Image) | 容器(Container) |
|---|---|---|
| 類比 | 安裝光碟 / 類別定義 | 安裝好的系統 / 物件實例 |
| 狀態 | 唯讀(Read-only) | 可讀寫(Read-write) |
| 建立方式 | 透過 Dockerfile build | 透過映像 run |
| 可複製性 | 一個映像可建立多個容器 | 每個容器是獨立的執行環境 |
# 從 Dockerfile 建立映像
docker build -t myapp:latest .
# 從映像建立並啟動容器
docker run -d --name myapp-1 myapp:latest
# 查看執行中的容器
docker ps
# 查看所有映像
docker images
Docker 分層架構
Dockerfile 中的每一條指令(FROM、RUN、COPY 等)都會建立一個 層(Layer)。Docker 會對每一層進行快取,如果該層的內容沒有變動,就會直接使用快取,大幅加速建置速度。這就是為什麼我們要把變動頻率低的指令(如安裝系統套件)放在前面,變動頻率高的指令(如複製程式碼)放在後面。
Dockerfile 撰寫
基礎映像選擇:slim vs alpine
選擇基礎映像是 Dockerfile 的第一步,常見的 Python 基礎映像比較如下:
| 映像 | 基於 | 體積 | 優點 | 缺點 |
|---|---|---|---|---|
python:3.12 | Debian(完整版) | ~900MB | 所有工具齊全 | 體積過大,不適合生產 |
python:3.12-slim | Debian(精簡版) | ~120MB | 相容性佳,套件可直接安裝 | 體積較 Alpine 大 |
python:3.12-alpine | Alpine Linux | ~50MB | 體積最小 | musl libc,C 擴展套件編譯困難 |
推薦使用 python:3.12-slim。Alpine 雖然體積小,但在安裝 psycopg2、Pillow、numpy 等依賴 C 擴展的套件時,需要額外安裝大量編譯工具(gcc、musl-dev、libffi-dev 等),最終映像反而可能比 slim 更大,建置時間也更長。
基礎版 Dockerfile
先從一個簡單的 Dockerfile 開始理解基本結構:
# 使用 Python 3.12 slim 映像(精簡版,不含編譯工具)
FROM python:3.12-slim
# 設定工作目錄
WORKDIR /app
# 設定環境變數
ENV PYTHONDONTWRITEBYTECODE=1 # 不產生 .pyc 檔案
ENV PYTHONUNBUFFERED=1 # 不緩衝 stdout/stderr(即時輸出日誌)
# 安裝系統依賴(PostgreSQL 客戶端程式庫)
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
# 安裝 Python 依賴(先複製 requirements.txt 利用快取層)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 複製應用程式碼
COPY . .
# 開放 8000 埠
EXPOSE 8000
# 啟動指令
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
多階段建置(Multi-stage Build)
多階段建置是 Docker 的進階技巧,將「建置階段」和「執行階段」分離,讓最終映像只包含執行時所需的檔案,大幅縮小體積:
# === Stage 1: Builder(建置階段)===
FROM python:3.12-slim AS builder
WORKDIR /app
# 安裝「編譯」依賴(gcc、libpq-dev 等,最終映像不需要)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 安裝 Python 依賴到使用者目錄(方便後續複製)
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# === Stage 2: Production(生產階段)===
FROM python:3.12-slim AS production
WORKDIR /app
# 只安裝「執行時」依賴(libpq5 而非 libpq-dev)
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
curl \
&& rm -rf /var/lib/apt/lists/*
# 從 builder 階段複製已安裝的 Python 套件
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# 複製應用程式碼
COPY . .
# 環境變數
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV DJANGO_SETTINGS_MODULE=myproject.settings.production
# 安全:建立非 root 使用者
RUN useradd --no-create-home --shell /bin/false appuser \
&& mkdir -p /app/staticfiles /app/media \
&& chown -R appuser:appuser /app
# 收集靜態檔案(在切換使用者之前執行,確保有寫入權限)
RUN python manage.py collectstatic --noinput
# 切換為非 root 使用者
USER appuser
EXPOSE 8000
# 健康檢查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz/')" || exit 1
CMD ["gunicorn", "myproject.wsgi:application", "-c", "gunicorn.conf.py"]
這段 Dockerfile 的關鍵設計:
- 快取層優化:先複製
requirements.txt並安裝依賴,只要依賴沒變就使用快取,大幅加速後續建置 - 多階段分離:
build-essential、libpq-dev等編譯工具只存在於 builder 階段,不會進入最終映像 - 非 root 使用者:以
appuser身份執行應用,限制潛在攻擊的影響範圍
非 root 使用者安全設定
預設情況下,Docker 容器中的程序以 root 身份執行。如果應用程式存在漏洞,攻擊者可能獲得容器內的 root 權限。使用非 root 使用者是 容器安全最佳實踐(Container Security Best Practice) 之一:
# 建立系統使用者(無家目錄、無 shell 登入)
RUN useradd --no-create-home --shell /bin/false appuser
# 確保應用目錄與需要寫入的目錄擁有權正確
RUN chown -R appuser:appuser /app
# 切換使用者(後續所有指令以 appuser 執行)
USER appuser
.dockerignore 設定
.dockerignore 的作用類似 .gitignore,告訴 Docker 在建置映像時忽略哪些檔案,可以加速建置過程並避免將敏感資訊打包進映像:
# .dockerignore
# Git
.git
.gitignore
# Python
__pycache__
*.pyc
*.pyo
*.egg-info
.eggs
# 虛擬環境
venv/
.venv/
env/
# IDE
.vscode/
.idea/
*.swp
*.swo
# 環境變數檔案(含敏感資訊,絕不打包!)
.env
.env.*
# Docker 自身
Dockerfile
docker-compose*.yml
.dockerignore
# 測試與文件
tests/
docs/
*.md
.coverage
htmlcov/
# 靜態檔案(將在容器內重新 collectstatic)
staticfiles/
media/
# OS
.DS_Store
Thumbs.db
requirements.txt 管理
良好的依賴管理是可重現建置的基礎。建議區分開發和生產依賴:
# requirements/base.txt(共用依賴)
Django==5.1
gunicorn==22.0.0
psycopg2-binary==2.9.9
django-redis==5.4.0
whitenoise==6.7.0
python-decouple==3.8
# requirements/production.txt(生產環境)
-r base.txt
sentry-sdk[django]==2.0.0
# requirements/development.txt(開發環境)
-r base.txt
django-debug-toolbar==4.4.0
pytest-django==4.8.0
在 Dockerfile 中使用生產依賴:
COPY requirements/base.txt requirements/base.txt
COPY requirements/production.txt requirements/production.txt
RUN pip install --no-cache-dir -r requirements/production.txt
也可以使用 pip-tools 來管理鎖定版本,確保每次建置都使用完全相同的依賴版本,避免因為版本差異導致「在我的環境可以跑」的問題:
# 安裝 pip-tools
pip install pip-tools
# 從 requirements.in 產生鎖定版本的 requirements.txt
pip-compile requirements.in --output-file requirements.txt
docker-compose.yml 完整範例
Docker Compose 是一個用來定義和管理多容器應用的工具,透過一個 YAML 檔案描述所有服務的配置,一條指令即可啟動完整環境。
Django + PostgreSQL + Redis 完整架構
# docker-compose.yml
services:
# === Django + Gunicorn ===
web:
build:
context: .
dockerfile: Dockerfile
env_file: .env
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/media
depends_on:
db:
condition: service_healthy # 等待 DB 健康檢查通過
redis:
condition: service_healthy # 等待 Redis 健康檢查通過
restart: unless-stopped
networks:
- app_network
# === PostgreSQL 資料庫 ===
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data # 資料持久化
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- app_network
# === Redis(快取 + Celery Broker)===
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data # 資料持久化
healthcheck:
test: ["CMD", "redis-cli", "--no-auth-warning", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- app_network
# === Nginx 反向代理 ===
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro # 唯讀掛載設定檔
- static_volume:/var/www/staticfiles:ro # 靜態檔案
- media_volume:/var/www/media:ro # 媒體檔案
depends_on:
- web
restart: unless-stopped
networks:
- app_network
# === Volume 定義 ===
volumes:
postgres_data: # PostgreSQL 資料持久化
redis_data: # Redis 資料持久化
static_volume: # Django 靜態檔案共享
media_volume: # Django 媒體檔案共享
# === Network 定義 ===
networks:
app_network:
driver: bridge
服務間依賴(depends_on)
depends_on 用來定義服務的啟動順序,但有一個常見的陷阱需要注意:
# 錯誤做法:只保證啟動順序,不保證服務就緒
depends_on:
- db
- redis
# 正確做法:搭配 healthcheck,等待服務真正就緒
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
加上 condition: service_healthy 後,Docker Compose 會等到 db 和 redis 的 healthcheck 通過後才啟動 web 服務,避免 Django 啟動時因資料庫尚未就緒而報錯。
環境變數管理
環境變數是 Docker 化應用最推薦的設定管理方式,遵循 12-Factor App(十二要素應用) 的最佳實踐,將設定與程式碼徹底分離。
.env 檔案範例
# .env(絕對不進版本控制!加入 .gitignore)
# Django
DJANGO_SECRET_KEY=your-very-long-random-secret-key-here
DJANGO_SETTINGS_MODULE=myproject.settings.production
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
DEBUG=False
# Database(DB_HOST 使用 docker-compose 的服務名稱)
DB_NAME=myappdb
DB_USER=myappuser
DB_PASSWORD=strong-db-password
DB_HOST=db
DB_PORT=5432
# Redis(同樣使用服務名稱 redis 作為 hostname)
REDIS_URL=redis://:strong-redis-password@redis:6379/0
REDIS_PASSWORD=strong-redis-password
注意 DB_HOST=db 和 REDIS_URL 中的 redis,這裡使用的是 docker-compose 定義的服務名稱。Docker 的內部 DNS 會自動將服務名稱解析到對應容器的 IP 位址,無需硬編碼 IP。
Django settings 讀取環境變數
# settings/production.py
from decouple import config, Csv
SECRET_KEY = config('DJANGO_SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST', default='localhost'),
'PORT': config('DB_PORT', default=5432, cast=int),
}
}
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': config('REDIS_URL'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
docker-compose 中的 env_file 設定
services:
web:
build: .
env_file: .env # 從 .env 檔案載入所有環境變數
# 也可以直接覆寫特定變數
environment:
- DJANGO_SETTINGS_MODULE=myproject.settings.production
env_file 會載入 .env 中的所有鍵值對作為容器的環境變數,而 environment 則可以覆寫或新增特定變數。
collectstatic 在容器中執行
Django 的靜態檔案(CSS、JavaScript、圖片等)需要透過 collectstatic 指令收集到 STATIC_ROOT 目錄。在 Docker 環境中有兩種執行方式:
方式一:在 Dockerfile 中執行(推薦)
# 在建置映像時執行 collectstatic
ENV DJANGO_SETTINGS_MODULE=myproject.settings.production
RUN python manage.py collectstatic --noinput
優點:靜態檔案直接包含在映像中,啟動即可使用,每次部署都能保證一致性。
方式二:在容器啟動時透過 Entrypoint 腳本執行
#!/bin/bash
# docker-entrypoint.sh
set -e
echo "收集靜態檔案..."
python manage.py collectstatic --noinput
echo "執行資料庫遷移..."
python manage.py migrate --noinput
echo "啟動 Gunicorn..."
exec gunicorn myproject.wsgi:application -c gunicorn.conf.py
# Dockerfile 中設定 entrypoint
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
這種方式適合需要在啟動時才能確定靜態檔案內容的場景,例如使用了環境變數動態產生 JavaScript 設定檔。注意 exec 關鍵字會讓 Gunicorn 取代 shell 程序成為 PID 1,確保能正確接收 Docker 的停止信號。
Volume 資料持久化
Docker 容器是 無狀態(Stateless) 的 — 容器刪除後,容器內的資料也會消失。對於需要持久化的資料(如資料庫、上傳的媒體檔案),必須使用 Volume(資料卷)。
Volume 類型比較
| 類型 | 語法 | 管理者 | 適用場景 |
|---|---|---|---|
| Named Volume | volume_name:/path | Docker | 資料庫、持久化資料 |
| Bind Mount | ./host/path:/container/path | 使用者 | 設定檔、開發時的程式碼同步 |
| tmpfs | tmpfs: /path | 記憶體 | 敏感臨時資料 |
各 Volume 的用途與掛載路徑
volumes:
postgres_data: # PostgreSQL 資料持久化 → /var/lib/postgresql/data
redis_data: # Redis AOF 持久化 → /data
static_volume: # Django 靜態檔案 → /app/staticfiles(web)→ /var/www/staticfiles(nginx)
media_volume: # 使用者上傳媒體 → /app/media(web)→ /var/www/media(nginx)
static_volume 和 media_volume 是 Django 和 Nginx 之間共享靜態資源的關鍵。Django 將檔案寫入 Volume,Nginx 從同一個 Volume 以唯讀模式(:ro)讀取並直接服務給瀏覽器,不需要經過 Gunicorn,效能大幅提升。
資料備份與還原
# 備份 PostgreSQL 資料庫
docker compose exec db pg_dump -U ${DB_USER} ${DB_NAME} > backup_$(date +%Y%m%d).sql
# 還原 PostgreSQL 資料庫
docker compose exec -T db psql -U ${DB_USER} ${DB_NAME} < backup_20260630.sql
# 備份媒體檔案 Volume
docker run --rm -v myproject_media_volume:/data -v $(pwd):/backup alpine \
tar czf /backup/media_backup.tar.gz -C /data .
Healthcheck 設定
Healthcheck(健康檢查) 讓 Docker 和編排工具可以判斷容器內的服務是否正常運行,不只是「容器有在跑」,而是「服務真的能回應請求」。
Django 健康檢查端點
# myapp/views.py
from django.http import JsonResponse
from django.db import connection
def health_check(request):
"""Liveness Probe:應用是否存活"""
return JsonResponse({'status': 'ok'})
def readiness_check(request):
"""Readiness Probe:應用是否就緒接受流量"""
checks = {}
# 檢查資料庫連線
try:
connection.ensure_connection()
checks['database'] = 'ok'
except Exception as e:
checks['database'] = str(e)
# 檢查 Redis 連線
try:
from django.core.cache import cache
cache.set('healthcheck', '1', timeout=5)
checks['cache'] = 'ok'
except Exception as e:
checks['cache'] = str(e)
status_code = 200 if all(v == 'ok' for v in checks.values()) else 503
return JsonResponse(checks, status=status_code)
# urls.py
urlpatterns = [
path('healthz/', health_check), # Liveness
path('readyz/', readiness_check), # Readiness
# ... 其他 URL
]
Healthcheck 參數說明
| 參數 | 說明 | 建議值 |
|---|---|---|
--interval | 檢查間隔 | 30s |
--timeout | 單次檢查超時 | 10s |
--start-period | 容器啟動後的寬限期 | 5s ~ 40s |
--retries | 連續失敗幾次視為不健康 | 3 |
在 Dockerfile 中加入 Healthcheck:
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz/')" || exit 1
開發環境 vs 生產環境的 docker-compose 分離
開發環境和生產環境的需求差異很大。Docker Compose 支援多檔案疊加機制,可以用一個基礎設定搭配不同的覆寫檔來滿足兩種環境。
基礎設定:docker-compose.yml
上面展示的 docker-compose.yml 就是基礎設定,包含 web、db、redis 三個核心服務。
開發環境覆寫:docker-compose.override.yml
# docker-compose.override.yml(開發環境,docker compose up 自動載入)
services:
web:
# 開發環境使用 runserver 並掛載本機程式碼
command: python manage.py runserver 0.0.0.0:8000
environment:
- DEBUG=True
- DJANGO_SETTINGS_MODULE=myproject.settings.development
volumes:
- .:/app # 掛載本機程式碼,修改後自動重載
- static_volume:/app/staticfiles
- media_volume:/app/media
ports:
- "8000:8000"
開發環境的特點:
- 使用
runserver而非 Gunicorn,支援自動重載 - 掛載本機程式碼(Bind Mount),修改後即時生效,不需重新建置映像
- 開啟
DEBUG=True,顯示詳細錯誤頁面 - 直接暴露 port 8000
生產環境覆寫:docker-compose.prod.yml
# docker-compose.prod.yml(生產環境)
services:
web:
environment:
- DEBUG=False
- DJANGO_SETTINGS_MODULE=myproject.settings.production
# 生產環境不直接暴露 port,由 Nginx 反向代理
ports: []
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- static_volume:/var/www/staticfiles:ro
- media_volume:/var/www/media:ro
depends_on:
- web
restart: unless-stopped
networks:
- app_network
啟動指令
# 開發環境(自動載入 docker-compose.yml + docker-compose.override.yml)
docker compose up
# 生產環境(指定基礎設定 + 生產覆寫,跳過 override)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# 生產環境建置並重啟
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
這種分離策略的好處是:基礎設定只維護一份,開發與生產的差異透過覆寫檔管理,避免重複設定且降低出錯機率。
常見問題排除
容器化部署最常遇到的問題集中在資料庫連線、靜態檔案和權限三個面向。
問題一:資料庫連線被拒
django.db.utils.OperationalError: could not connect to server: Connection refused
原因與解法:
- DB_HOST 設定錯誤:在 docker-compose 中,
DB_HOST必須使用服務名稱(如db),不能用localhost或127.0.0.1,因為每個容器有獨立的網路空間 - 資料庫尚未就緒:使用
depends_on搭配condition: service_healthy確保資料庫完全啟動 - 密碼或帳號不匹配:確認
.env中的DB_USER、DB_PASSWORD與 PostgreSQL 容器的POSTGRES_USER、POSTGRES_PASSWORD一致
# 除錯:測試容器間的資料庫連線
docker compose exec web python -c "
import psycopg2
conn = psycopg2.connect(host='db', dbname='myappdb', user='myappuser', password='strong-db-password')
print('連線成功!')
conn.close()
"
問題二:靜態檔案 404
原因:Nginx 無法存取 Django 的靜態檔案目錄。
解法:透過共享 Volume 讓 Nginx 存取靜態檔案,並確保路徑一致:
services:
web:
volumes:
- static_volume:/app/staticfiles # Django 寫入
nginx:
volumes:
- static_volume:/var/www/staticfiles:ro # Nginx 讀取
# settings.py 中 STATIC_ROOT 必須與 Volume 掛載路徑一致
STATIC_URL = '/static/'
STATIC_ROOT = '/app/staticfiles'
問題三:檔案權限問題
PermissionError: [Errno 13] Permission denied
原因:使用非 root 使用者但檔案屬於 root。
解法:在 Dockerfile 中切換使用者之前設定目錄權限:
# 先建立需要寫入的目錄並設定權限
RUN mkdir -p /app/staticfiles /app/media \
&& useradd --no-create-home --shell /bin/false appuser \
&& chown -R appuser:appuser /app
USER appuser
問題四:映像過大
# 診斷:查看映像大小
docker images myapp
# 查看各層大小,找出肥大的層
docker history myapp:latest
解法:
- 使用
python:3.12-slim而非python:3.12(節省約 600MB) - 使用多階段建置分離編譯工具
- 在
RUN指令結尾清理快取:rm -rf /var/lib/apt/lists/* - 合併多個
RUN指令減少層數 - 確認
.dockerignore排除了不必要的檔案
常用 Docker 除錯指令
# 建置並啟動所有服務
docker compose up -d --build
# 查看服務即時日誌
docker compose logs -f web
# 進入容器執行 Django shell
docker compose exec web python manage.py shell
# 執行資料庫遷移
docker compose exec web python manage.py migrate
# 建立超級管理員
docker compose exec web python manage.py createsuperuser
# 停止所有服務(保留 Volume 資料)
docker compose down
# 停止並刪除所有資料(含 Volume,慎用!)
docker compose down -v
# 重新建置並重啟單一服務(不影響其他服務)
docker compose up -d --no-deps --build web
總結
Docker 容器化部署讓 Django 應用的環境一致性和可攜性達到了新的高度。透過 Dockerfile 的多階段建置,我們可以建立精簡且安全的生產映像;透過 .dockerignore 排除不必要的檔案,加速建置並保護敏感資訊;透過 docker-compose.yml 編排 Django、PostgreSQL、Redis、Nginx 等服務,一條指令即可啟動完整的生產環境。環境變數管理遵循 12-Factor App 原則,將設定與程式碼分離;Volume 資料持久化確保資料庫和媒體檔案不會隨容器銷毀而遺失;Healthcheck 讓編排工具能夠自動偵測服務健康狀態並做出相應處理;開發與生產環境的 docker-compose 分離策略則讓團隊能在一致的基礎上靈活切換不同環境。掌握這些 Docker 部署技巧後,你的 Django 應用就已經具備了現代化生產環境部署的完整基礎。