玄貓在這些年的科技職場生涯中,每當需要建立新專案時,總是會遇到各種環境設定的挑戰。今天,我要分享一套經過多年實戰淬煉的專案結構與環境設定方法,這套方法不僅適用於Django專案,對任何Python Web開發都能帶來極大效益。
專案結構:建立直覺與可擴充套件的基礎
在實務開發中,一個好的專案結構對於長期維護至關重要。我觀察到許多專案的根目錄常雜亂無章,即使有README檔案,也往往無法及時更新。這種情況不僅增加了團隊溝通成本,也讓新成員難以快速上手。
核心目錄結構
project_root/
├── .env/ # 環境變數範本
├── docker/ # Docker相關設定
│ ├── local/ # 本地開發用Docker設定
│ └── production/ # 生產環境Docker設定
├── scripts/ # 工具指令碼
├── src/ # 原始碼目錄
│ ├── core/ # 核心邏輯
│ ├── api/ # API定義
│ └── config/ # 設定檔
├── tests/ # 測試程式碼
└── tools/ # 開發工具與輔助指令碼
關鍵設計原則
模組化分離:將不同功能的程式碼分門別類別,避免互相干擾。這種做法讓專案更容易維護,也方便其他開發者理解整體架構。
環境隔離:開發、測試和生產環境的設定應該清楚分開。玄貓建議在docker目錄下為不同環境建立獨立的設定檔案。
工具集中化:將所有開發和佈署相關的指令碼統一放在scripts或tools目錄下,方便管理和使用。
設定外部化:環境變數和設定檔案應該集中管理,避免散落在各處。這樣不僅安全性更高,也便於維護。
環境變數管理:安全與靈活
在多年的開發經驗中,我發現環境變數管理是專案成功的關鍵因素之一。這裡分享一個實用的方案:
# config/settings.py
from pathlib import Path
from decouple import config
BASE_DIR = Path(__file__).resolve().parent.parent
# 核心設定
DEBUG = config('DEBUG', default=False, cast=bool)
SECRET_KEY = config('SECRET_KEY')
# 資料函式庫
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'),
}
}
環境變數處理的最佳實踐
在實務開發中,我發現將環境變數分層管理特別有效:
- 開發環境:使用.env.local檔案
- 測試環境:使用.env.test檔案
- 生產環境:使用系統環境變數或安全的金鑰管理服務
這種方式不僅確保了安全性,也讓環境切換變得更加靈活。每個環境的設定檔都應該有明確的範本,但實際的值應該放在.gitignore中避擴音交。
Docker化開發環境
在現代開發流程中,Docker已經成為標準配備。以下是我最佳化過的Django專案Docker設定:
# docker/local/Dockerfile
FROM python:3.11-slim
WORKDIR /app
# 安裝系統依賴
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# 安裝Python套件
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 複製專案檔案
COPY . .
# 設定環境變數
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# 啟動命令
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Docker Compose設定
# docker-compose.yml
version: '3.8'
services:
web:
build:
context: .
dockerfile: docker/local/Dockerfile
volumes:
- .:/app
ports:
- "8000:8000"
depends_on:
- db
environment:
- DEBUG=1
- DB_HOST=db
db:
image: postgres:13
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=myproject
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypassword
volumes:
postgres_data:
這個設定提供了完整的本地開發環境,包含:
- 自動化的環境建置
- 開發環境與資料函式庫整隔離
- 程式碼熱多載支援
- 持久化的資料儲存
專案啟動與維護
為了簡化日常開發操作,我建議建立一個Makefile:
.PHONY: build up down test lint
build:
docker-compose build
up:
docker-compose up -d
down:
docker-compose down
test:
docker-compose run web python manage.py test
lint:
docker-compose run web flake8
這些命令大幅簡化了日常開發流程,讓團隊成員可以專注於開發工作,而不是糾結於環境問題。
經過這些年的經驗,我深體會到一個良好的開發環境設定可以為團隊節省大量時間。這套設定方案雖然看似繁瑣,但實際上可以大幅減少後續維護的負擔,讓團隊將精力集中在真正的開發工作上。
最重要的是,這個架構具有很強的靈活性,可以根據專案需求進行調整。無論是新增新的服務,還是整合新的工具,都能輕鬆應對。在實際專案中,這套架構已經幫助多個團隊提高了開發效率,減少了環境相關的問題。
Docker開發環境最佳實踐:目錄結構與設定管理
在多年的開發經驗中,我發現良好的專案結構對於團隊協作和開發效率至關重要。今天我要分享一個經過實戰驗證的 Docker 開發環境目錄結構,這套架構能大幅提升團隊的開發體驗。
核心目錄結構設計
首先來看整體的目錄設定:
.
├── .local_files/ # 本地開發檔案(gitignore)
│ ├── asgi/ # 主應用程式本地檔案
│ ├── celery/ # Celery 本地檔案
│ ├── nginx/ # Nginx 本地檔案
│ ├── postgres/ # PostgreSQL 本地檔案
│ └── redis/ # Redis 本地檔案
├── docker/ # Docker 相關設定
│ ├── composes/ # docker-compose 檔案
│ ├── confs/ # 服務設定檔案
│ ├── dockerfiles/ # Dockerfile 檔案
│ └── inits/ # 初始化指令碼
├── docs/ # 專案檔案
└── scripts/ # 常用操作指令碼
本地開發環境設定
.local_files
目錄包含所有本地開發所需的檔案:
.local_files/
├── asgi/
│ ├── log/ # 應用程式日誌
│ ├── media/ # 媒體檔案
│ ├── static/ # 靜態檔案
│ └── tmp/ # 暫存檔案
├── nginx/
│ ├── certs/ # SSL 憑證
│ ├── conf/ # Nginx 設定
│ └── log/ # Nginx 日誌
├── postgres/
│ ├── backup/ # 資料函式庫
│ ├── data/ # 資料函式庫
│ └── log/ # 資料函式庫
└── redis/
├── data/ # Redis 資料
└── log/ # Redis 日誌
Docker 設定管理
在 docker
目錄下,我們按功能劃分不同類別的設定:
docker/
├── composes/
│ ├── docker-compose.dev.yml # 開發環境設定
│ ├── docker-compose.prod.yml # 生產環境設定
│ ├── docker-compose.docs.yml # 檔案生成設定
│ └── docker-compose.override.yml # 本地覆寫設定
├── confs/
│ ├── nginx.dev.conf # Nginx 開發設定
│ └── nginx.prod.conf # Nginx 生產設定
└── dockerfiles/
├── asgi.dockerfile # 應用程式容器
└── postgres.dockerfile # 資料函式庫
輔助指令碼設計
scripts
目錄包含常用的操作指令:
scripts/
├── bash.sh # 容器 Shell 存取
├── dbshell.sh # 資料函式庫hell 存取
├── init.sh # 環境初始化
├── manage.sh # Django 管理指令
└── shell.sh # 應用程式 Shell
這些指令碼大幅簡化了日常開發操作,讓開發者能夠專注於程式邏輯而非環境設定。
開發環境啟動流程
- 初始化本地環境:
./scripts/init.sh
- 啟動開發環境:
docker-compose -f docker-compose.yml -f docker/composes/docker-compose.dev.yml up -d
- 存取容器或資料函式庫:
./scripts/bash.sh # 進入應用程式容器
./scripts/dbshell.sh # 進入資料函式庫
這套目錄結構的主要優勢在於:
- 清晰的職責分離,讓不同功能的設定各司其職
- 本地開發檔案與版控檔案明確區分
- 方便的指令碼工具提升開發效率
- 靈活的環境設定支援不同場景需求
在實際開發中,這套結構能夠很好地支援從小型專案到大型系統的各種需求。不過要注意,雖然這套架構在本地開發時非常便利,但在生產環境中還是建議使用 Kubernetes 等更成熟的容器管理方案。
正確的目錄結構設計不僅能提升開發效率,還能降低團隊成員的認知負擔。透過這套結構,新進開發者能快速理解專案設定,資深開發者也能更有效率地進行開發維護。持續最佳化和調整目錄結構,是提升團隊開發效能的重要手段。
在多年的 Django 開發經驗中,我深刻體會到良好的專案結構對於專案的可維護性和擴充套件性有多麼重要。今天玄貓要分享一套經過實戰驗證的 Django 專案目錄結構設計,這個結構不僅能提升開發效率,更能確保專案的長期可維護性。
核心目錄結構設計
src 目錄:應用程式核心
src 目錄是整個專案的核心,包含所有主要的應用程式碼:
src/
├── apps/ # 業務邏輯應用
├── config/ # Django 應用程式設定
├── contrib/ # 共用模組
├── plugins/ # 可選的業務邏輯應用
└── settings/ # 應用程式設定檔
設定檔結構
settings 目錄採用模組化設計,讓設定更容易管理:
settings/
├── apps_settings.py # 業務邏輯設定
├── base_settings.py # 基礎設定(路徑、模式、URL)
├── deps_settings.py # 第三方應用程式憑證
├── django_settings.py # Django 專用設定
├── local_settings.py # 本地設定(git 忽略)
├── local_settings.sample.py # 本地設定範例
└── test_settings.py # 測試環境設定
專案根目錄設定
在專案根目錄中,我們放置了一些重要的設定檔案:
├── .env.base # 基礎環境變數
├── .env.local # 本地環境變數(git 忽略)
├── .env.local.sample # 本地環境變數範例
├── docker-compose.yml # Docker Compose 主要設定
├── pyproject.toml # 專案元資料
└── pdm.lock # 相依性鎖設定檔案
開發環境與工具設定
Docker 相關設定
為了確保開發環境的一致性,我們在專案中加入了完整的 Docker 設定:
├── .dockerignore # Docker 忽略檔案
├── compose # Docker Compose 命令工具
└── docker/ # Docker 工具和設定目錄
本地檔案管理
local_files 目錄用於存放本地開發所需的檔案:
- 日誌檔案
- 備份檔案
- 暫存檔案
- 憑證檔案
- 應用程式設定
這些檔案通常會被加入 .gitignore,以避免意外推播到版本控制系統。
專案檔案與版本控制
為了確保專案的可維護性,我們加入了完整的檔案系統:
├── CHANGELOG.md # 版本變更記錄
├── README.md # 專案說明檔案
└── mkdocs.yml # 檔案設定
開發流程最佳實踐
在實務開發中,玄貓建議採用以下作法來維護這個目錄結構:
業務邏輯模組化:將所有業務邏輯放在 apps 目錄下,每個功能都作為獨立的 Django 應用程式。
設定檔分層:不同環境的設定檔應該清楚分離,避免設定互相汙染。在 local_settings.py 中匯入其他設定檔,這樣可以靈活調整不同環境的設定。
環境變數管理:使用 .env 檔案來管理環境變數,並提供 .env.sample 檔案作為範本。
Docker 工作流程:將所有 Docker 相關的設定集中在 docker 目錄下,方便管理和維護。
這個目錄結構不僅方便管理,還特別適合需要長期維護的大型專案。它讓新進開發者能快速理解專案架構,也讓經驗豐富的開發者能有效率地進行開發。
在實務運作中,這個結構已經幫助玄貓完成了多個大型 Django 專案,不僅提高了開發效率,也大幅降低了維護成本。透過清晰的目錄結構,我們可以更專注於業務邏輯的開發,而不是在混亂的程式碼結構中浪費時間。
當遇到專案需要擴充套件時,這個結構也提供了足夠的彈性。無論是加入新的功能模組,或是整合新的第三方服務,都能輕鬆地找到合適的位置。關鍵是要堅持目錄結構的規範,確保所有團隊成員都遵循相同的開發準則。
在多年帶領開發團隊的經驗中,玄貓深刻體會到良好的專案目錄結構對於專案的可維護性和團隊協作效率有著決定性的影響。今天讓我分享如何建立一個清晰與實用的專案結構,特別著重於Docker設定和環境變數管理的最佳實踐。
Docker相關設定的組織方式
為了讓Docker相關的設定更有條理,建議將所有Docker相關檔案集中在專門的目錄中。在實務上,玄貓建議採用以下結構:
docker/
├── composes/ # docker-compose檔案
├── dockerfiles/ # Dockerfile定義
├── inits/ # 容器初始化指令碼
└── confs/ # 設定檔案
這樣的結構有幾個明顯優勢:
- 相關設定集中管理,便於維護
- 檔案依據用途分類別,提高可讀性
- 降低新團隊成員的學習曲線
專案檔案結構
檔案目錄(docs)
在專案中,玄貓特別推薦使用MkDocs來管理技術檔案。透過設定MkDocs,我們可以:
- 自動產生API檔案
- 提供清晰的專案說明
- 維護開發和最佳實踐
CI/CD管線(pipelines)
GitLab的CI/CD設定檔案應該放在專門的pipelines目錄中。這樣做可以:
- 將CI/CD邏輯與應用程式碼分離
- 便於管理不同環境的佈署流程
- 提高設定檔案的可讀性
工具指令碼(scripts)
為了提升開發效率,玄貓建議將常用的操作指令封裝成指令碼:
scripts/
├── manage.sh # Django管理命令
├── dbshell.sh # 資料函式庫
└── shell_plus.sh # Django shell
這些指令碼可以透過符號連結放在專案根目錄,方便開發者使用。
原始碼目錄(src)
將應用程式碼獨立放在src目錄有幾個重要優勢:
- 便於建立Docker映像檔
- 明確區分專案環境設定和實際程式碼
- 提供更好的程式碼組織結構
環境變數管理
在環境變數的管理上,玄貓採用分層設定的方式:
.env.base # 基礎設定
.env # 本地開發設定
.env.prod # 生產環境設定
基礎環境變數範例
# 專案基本設定
COMPOSE_PROJECT_NAME=my_project
DJANGO_SETTINGS_MODULE=settings.local_settings
# 執行環境設定
DEBUG=False
PRODUCTION=False
WORKERS_COUNT=4
# 使用者識別
USER_NAME="${USER}"
USER_ID="$(id -u)"
GROUP_ID="$(id -g)"
# Docker映像檔設定
DOCKER_REGISTRY=registry.example.com
DOCKER_IMAGE=my_project
TAG=latest
這種環境變數管理方式有幾個關鍵優點:
- 基礎設定可以納入版本控制
- 敏感資訊保持在本地
- 開發者可以快速理解需要設定哪些變數
在實務經驗中,玄貓發現將基礎設定(非敏感資訊)納入版本控制,可以大幅減少新人上手時的困擾。同時,透過清晰的註解說明每個變數的用途,更有助於維護和理解。
文章內容到這裡,玄貓已經分享了建立一個結構良好的專案所需要的關鍵要素。這些實踐來自於多年的實戰經驗,能有效提升團隊的開發效率和程式碼的可維護性。透過這樣的結構設計,無論是新進開發者還是經驗豐富的工程師,都能快速理解專案架構並開始貢獻。記住,好的結構設計不僅是為了當下的開發效率,更是為了專案的長期健康發展。 這是一份關於使用Docker與環境變數設定的技術,讓我重新整理並深入解析這個設定系統的設計思路與實作細節。
Docker專案環境設定與本地化設定
專案目錄結構設計
首先,讓我們瞭解整個專案的核心目錄結構:
PROJECT_DIR/
├── src/ # 應用程式原始碼
├── docker/ # Docker相關設定
│ ├── composes/ # Docker Compose檔案
│ ├── confs/ # 服務設定檔案
│ ├── dockerfiles/ # Dockerfile定義
│ └── inits/ # 初始化指令碼
└── .local_files/ # 本地檔案目錄
連線埠設定策略
玄貓在這裡採用了一個重要的設計原則:明確區分外部(主機)和內部(Docker網路)的連線埠設定。這種設計有幾個關鍵優勢:
外部連線埠設定
ASGI_PORT_EXTERNAL=8000
POSTGRES_PORT_EXTERNAL=5432
REDIS_PORT_EXTERNAL=6379
NGINX_PORT_EXTERNAL=80
FLOWER_PORT_EXTERNAL=5555
DOCS_EXTERNAL_PORT=8001
內部連線埠設定
ASGI_PORT_INTERNAL=8000
POSTGRES_PORT_INTERNAL=5432
REDIS_PORT_INTERNAL=6379
NGINX_PORT_INTERNAL=80
FLOWER_PORT_INTERNAL=5555
DOCS_PORT_INTERNAL=8001
這種分離設計讓我們能夠:
- 靈活調整對外服務連線埠而不影響內部服務
- 避免連線埠衝突
- 提供更好的安全性隔離
服務設定開關
系統提供了一系列布林值設定項,用於控制各個服務的啟用狀態:
RUN_WITH_REDIS=True
RUN_WITH_POSTGRES=True
RUN_WITH_OVERRIDE_DOCKER_COMPOSE=True
RUN_WITH_BUILD_LOCALLY=False
RUN_WITH_DOCS=False
這些開關提供了極大的佈署彈性,讓開發者能根據需求自由選擇要啟用的服務。
本地化設定策略
玄貓特別注意到設定的本地化處理是一個關鍵議題。系統採用了 .env.local
作為本地設定檔案,這個檔案根據 .env.local.sample
範本生成,包含了:
核心設定專案
# 基礎設定
DEBUG=True
# 管理員設定
ADMIN_USERNAME=admin
ADMIN_PASSWORD=password_example
# 資料函式庫
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password_example
POSTGRES_DB=postgres
進階服務設定
# Redis設定
REDIS_HOST=redis
REDIS_PORT=6379
# 郵件服務設定
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=
MAIL_PASSWORD=
# 雲端儲存設定
USE_S3_STORAGE=False
AWS_STORAGE_BUCKET_NAME=
AWS_S3_ACCESS_KEY_ID=
AWS_S3_SECRET_ACCESS_KEY=
設定整合機制
所有的設定最終會整合到一個統一的 .env
檔案中。這個過程遵循以下原則:
- 基礎設定來自主要的環境變數檔案
- 本地設定(
.env.local
)可覆寫基礎設定 - 所有敏感資訊都存放在本地設定中
- 設定檔案經過適當的 gitignore 處理
這種設定管理方式特別適合團隊協作,因為它:
- 保護了敏感資訊
- 允許開發者維護個人化的本地設定
- 提供了清晰的設定層級結構
- 簡化了環境變數的管理
玄貓在多年的技術實務中發現,良好的設定管理是專案成功的關鍵因素之一。這個設定系統設計充分考慮了開發便利性、安全性與維護性,適合作為中大型專案的設定管理範本。
在現代軟體開發中,環境設定的自動化對於提升開發效率和確保環境一致性至關重要。玄貓今天要分享一個強大的Bash指令碼,這個指令碼能夠自動化處理專案的環境設定、Docker設定以及各種必要的檔案結構建立。
指令碼核心功能概述
這個自動化指令碼主要實作以下核心功能:
- 環境變數管理
- 專案結構初始化
- Docker服務設定
- 符號連結建立
讓我們逐步解析這個指令碼的重要部分。
環境變數處理
#!/bin/bash
# 輸出執行期間定義的變數
print_script_variables() {
set | sort | comm -13 .env.tmp -
}
# 將環境變數暫存
set | sort > .env.tmp
# 載入基礎環境設定
source ".env.base"
# 複製本地設定檔
cp -n ${PROJECT_DIR}/.env.local.sample ${PROJECT_DIR}/.env.local
cp -n ${SOURCE_DIR}/settings/local_settings.sample.py ${SOURCE_DIR}/settings/local_settings.py
# 載入本地環境變數
if [[ -f .env.local ]]; then
source ".env.local"
fi
這段程式碼主要處理環境變數的設定與管理:
- 建立函式用於追蹤指令碼執行期間的變數變化
- 將目前的環境變數存入暫存檔
- 載入基礎與本地環境設定
- 自動複製範本檔案作為本地設定
專案結構初始化
# 建立本地檔案目錄
mkdir -p "${LOCAL_FILES_DIR}"
# 建立符號連結
ln -sf "${PROJECT_DIR}/scripts/bash.sh" "${PROJECT_DIR}/bash"
ln -sf "${PROJECT_DIR}/scripts/dbshell.sh" "${PROJECT_DIR}/dbshell"
ln -sf "${PROJECT_DIR}/scripts/manage.sh" "${PROJECT_DIR}/manage"
ln -sf "${PROJECT_DIR}/scripts/shell.sh" "${PROJECT_DIR}/shell"
ln -sf "${PROJECT_DIR}/scripts/init.sh" "${PROJECT_DIR}/init"
這部分程式碼負責:
- 建立必要的本地檔案目錄
- 建立常用指令的符號連結,提供便捷的操作介面
- 確保專案結構的一致性
服務目錄結構建立
# PostgreSQL相關目錄
mkdir -p "${LOCAL_FILES_DIR}/postgres"
mkdir -p "${LOCAL_FILES_DIR}/postgres/log"
mkdir -p "${LOCAL_FILES_DIR}/postgres/data"
mkdir -p "${LOCAL_FILES_DIR}/postgres/backup"
# Redis相關目錄
mkdir -p "${LOCAL_FILES_DIR}/redis"
mkdir -p "${LOCAL_FILES_DIR}/redis/log"
mkdir -p "${LOCAL_FILES_DIR}/redis/data"
# ASGI相關目錄
mkdir -p "${LOCAL_FILES_DIR}/asgi"
mkdir -p "${LOCAL_FILES_DIR}/asgi/log"
mkdir -p "${LOCAL_FILES_DIR}/asgi/tmp"
mkdir -p "${LOCAL_FILES_DIR}/asgi/media"
這段程式碼為各個服務建立必要的目錄結構:
- 資料函式庫ostgreSQL)的資料、日誌和備份目錄
- Redis的資料和日誌目錄
- ASGI服務的媒體檔案和暫存目錄
- 確保每個服務都有獨立的資源管理空間
Nginx設定處理
# Nginx設定相關
mkdir -p "${LOCAL_FILES_DIR}/nginx"
mkdir -p "${LOCAL_FILES_DIR}/nginx/conf"
mkdir -p "${LOCAL_FILES_DIR}/nginx/log"
mkdir -p "${LOCAL_FILES_DIR}/nginx/certs"
# 設定環境變數
export NGINX_PORT_INTERNAL=${NGINX_PORT_INTERNAL}
export ASGI_PORT_INTERNAL=${ASGI_PORT_INTERNAL}
export DOCS_PORT_INTERNAL=${DOCS_PORT_INTERNAL}
export HOST_NAME=${HOST_NAME}
# 產生Nginx設定檔
envsubst '${NGINX_PORT_INTERNAL},${ASGI_PORT_INTERNAL},${DOCS_PORT_INTERNAL},${HOST_NAME}' \
< "${DOCKER_CONFS_DIR}/nginx.dev.conf" > "${LOCAL_FILES_DIR}/nginx/conf/nginx.dev.conf"
envsubst '${NGINX_PORT_INTERNAL},${ASGI_PORT_INTERNAL},${DOCS_PORT_INTERNAL},${HOST_NAME}' \
< "${DOCKER_CONFS_DIR}/nginx.prod.conf" > "${LOCAL_FILES_DIR}/nginx/conf/nginx.prod.conf"
這部分程式碼處理Nginx的設定:
- 建立Nginx相關目錄結構
- 設定必要的環境變數
- 使用範本產生開發和正式環境的Nginx設定檔
- 自動替換設定檔中的變數
在多年的開發經驗中,玄貓發現良好的自動化指令碼不僅能大幅提升開發效率,更能降低人為錯誤。這個指令碼特別注重環境一致性和可重複性,讓團隊成員能夠快速建立標準化的開發環境。
透過這個自動化指令碼,我們能夠確保:
- 所有開發者使用相同的環境設定
- 降低環境設定的人為錯誤
- 加速新專案的初始化過程
- 簡化開發環境的維護工作
在實際佈署時,建議根據專案需求適當調整目錄結構和服務設定,確保指令碼能夠最佳化支援團隊的開發流程。持續改進自動化工具,是提升開發效率的關鍵要素。 讓我將這段Shell指令碼與Docker設定重新整理並深入解析,重點說明其架構設計與實作考量。
Docker多環境佈署設定解析
基礎設定判斷邏輯
# Redis 服務設定
if [[ "${RUN_WITH_REDIS}" = "True" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.redis.yml"
fi
# PostgreSQL 服務設定
if [[ "${RUN_WITH_POSTGRES}" = "True" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.postgres.yml"
fi
# 覆寫設定處理
if [[ "${RUN_WITH_OVERRIDE_DOCKER_COMPOSE}" = "True" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.override.yml"
fi
# 檔案服務設定
if [[ "${RUN_WITH_DOCS}" = "True" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.docs.yml"
fi
這段設定指令碼的設計理念是採用模組化的方式來管理不同的服務元件。每個條件判斷都會根據環境變數來決定是否載入對應的 docker-compose 設定檔案。這種設計帶來幾個重要優勢:
- 彈性佈署:可以根據需求選擇性地啟用不同服務
- 環境隔離:開發、測試和生產環境可以使用不同的設定組合
- 維護性佳:每個服務都有獨立的設定檔案,便於管理和更新
本地建置設定
# 本地建置設定處理
if [[ "${RUN_WITH_BUILD_LOCALLY}" = "True" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.build-asgi-locally.yml"
if [[ "${RUN_WITH_DOCS}" = "True" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.build-docs-locally.yml"
fi
fi
本地建置設定的特點:
- 開發環境最佳化:提供專門的本地建置設定,方便開發測試
- 檔案即時更新:支援檔案服務的本地建置,確保檔案與程式碼同步
- 靈活設定:可以根據需求組合不同的建置選項
環境區分設定
# 環境區分設定
if [[ "${PRODUCTION}" = "False" ]]; then
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.dev.yml"
else
COMPOSE_FILE="${COMPOSE_FILE}:${DOCKER_COMPOSES_DIR}/docker-compose.prod.yml"
fi
這個設計實作了開發和生產環境的明確區分:
- 環境隔離:開發與生產使用不同的設定檔案
- 安全性考量:生產環境可以套用更嚴格的安全設定
- 效能最佳化:生產環境可以針對效能進行特別調校
Docker Compose 最佳實踐建議
在實作類別似的 Docker 設定時,玄貓建議注意以下幾點:
變數集中管理
- 使用
.env
檔案統一管理環境變數 - 避免在 docker-compose 檔案中硬編碼設定值
- 使用
資源設定最佳化
- 為容器設定適當的資源限制
- 使用 volumes 時優先考慮使用具名 volumes
- 注意網路設定的安全性
依賴關係處理
- 明確定義服務間的依賴關係
- 實作健康檢查確保服務可用性
- 使用 wait-for-it 或類別似工具處理啟動順序
維護性考量
- 保持設定檔案結構清晰
- 適當註解關鍵設定項
- 建立統一的命名規範
在實際專案中,玄貓發現這種模組化的設定方式特別適合需要在不同環境間切換的微服務架構。透過環境變數控制服務組合,既保持了靈活性,又降低了設定出錯的風險。不過要特別注意在生產環境中,應該仔細審查所有啟用的服務元件,確保不會暴露開發用的服務或測試介面。
最後,這種設定架構雖然靈活,但也需要團隊成員都能理解整體架構。建議製作完整的佈署檔案,並定期檢視各個環境的設定是否仍然符合專案需求。
在現代軟體開發中,容器化佈署已經成為標準實踐。透過 Docker Compose,我們可以優雅地管理多個相互依賴的服務。在這篇文章中,讓我分享如何建構一個完整的 Django 微服務架構。
基礎服務架構設計
這個架構包含了幾個核心元件:
- ASGI 服務:處理主要的應用程式邏輯
- Celery Beat:負責排程任務
- Celery Worker:執行非同步任務
- Flower:監控 Celery 任務執行狀態
- Nginx:作為反向代理伺服器
ASGI 服務設定
ASGI 服務是整個應用的核心,負責處理所有的 Web 請求:
asgi:
<<: *asgi-base
hostname: asgi
container_name: ${COMPOSE_PROJECT_NAME}-asgi
ports:
- "${ASGI_PORT_EXTERNAL}:${ASGI_PORT_INTERNAL}"
volumes:
- ${LOCAL_FILES_DIR}/asgi/log/:/var/log/asgi/
- ${LOCAL_FILES_DIR}/asgi/tmp/:/tmp/
- ${LOCAL_FILES_DIR}/asgi/static:/mnt/resource/static
- ${LOCAL_FILES_DIR}/asgi/media:/mnt/resource/media
這段設定的重點在於使用環境變數來設定連線埠對映,並且將日誌、暫存檔案、靜態檔案和媒體檔案都掛載到容器外部,方便管理和備份。
Celery 服務架構
Celery 相關服務包含了三個主要元件:
celery-beat:
<<: *asgi-base
hostname: celery-beat
container_name: ${COMPOSE_PROJECT_NAME}-celery-beat
command: bash -c 'celery -A config beat -l info --logfile=/var/log/celery/celery_beat.log -s celerybeat-schedule'
celery-default:
<<: *asgi-base
hostname: celery-default
container_name: ${COMPOSE_PROJECT_NAME}-celery-default
command: bash -c 'celery -A config worker -l info --concurrency=5 --logfile=/var/log/celery/celery_default.log -Q default'
flower:
<<: *asgi-base
hostname: flower
container_name: ${COMPOSE_PROJECT_NAME}-flower
command: bash -c 'celery -A config flower --address=0.0.0.0 --port=${FLOWER_PORT_INTERNAL}'
ports:
- "${FLOWER_PORT_EXTERNAL}:${FLOWER_PORT_INTERNAL}"
Celery Beat 服務:
- 使用
-A config
指定 Celery 應用程式設定 - 透過
--logfile
設定日誌檔案路徑 -s celerybeat-schedule
指定排程資料儲存位置
- 使用
Celery Worker 服務:
--concurrency=5
設定工作程式數量-Q default
指定處理預設佇列的任務- 同樣記錄詳細的執行日誌
Flower 監控服務:
- 設定監聽位址為 0.0.0.0 使外部可存取
- 使用環境變數設定連線埠
- 提供 Web 介面監控 Celery 任務
Nginx 反向代理設定
nginx:
image: nginx:1.25.3
hostname: nginx
container_name: ${COMPOSE_PROJECT_NAME}-nginx
restart: on-failure
ports:
- "${NGINX_PORT_EXTERNAL}:${NGINX_PORT_INTERNAL}"
volumes:
- ${LOCAL_FILES_DIR}/nginx/log/:/var/log/nginx/
- ${LOCAL_FILES_DIR}/asgi/tmp/:/tmp/
- ${LOCAL_FILES_DIR}/asgi/static:/mnt/resource/static
- ${LOCAL_FILES_DIR}/asgi/media:/mnt/resource/media
depends_on:
- asgi
networks:
- app-network
映像版本選擇:
- 使用穩定的 nginx 1.25.3 版本
- 設定自動重啟策略確保服務可用性
資源掛載:
- 將 Nginx 日誌導向外部儲存
- 掛載應用程式的靜態檔案和媒體檔案
- 確保與 ASGI 服務分享相同的檔案路徑
依賴關係:
- 透過 depends_on 確保 ASGI 服務先啟動
- 使用自定義網路實作服務間通訊
在實際佈署中,這個架構提供了良好的擴充套件性和可維護性。透過環境變數的運用,我們可以輕鬆地在不同環境中佈署相同的服務設定。每個服務都有自己的日誌管理,方便問題追蹤和效能最佳化。
此外,所有服務都在同一個 Docker 網路中執行,確保了服務間的安全通訊,同時透過 Nginx 反向代理統一管理外部存取。這種設計不僅提供了良好的安全性,也便於日後的維護和擴充套件。
最後,建議在生產環境中根據實際負載調整 Celery 工作程式數量,並考慮增加更多的特定任務佇列來最佳化處理效能。同時,別忘了定期備份掛載的資料目錄,確保服務的可靠性。
Docker Compose 設定檔深入解析
在現代微服務架構中,Docker Compose 扮演著關鍵角色,讓我們能夠輕鬆管理多個容器化服務。接下來,玄貓將深入解析不同環境下的 Docker Compose 設定,並分享多年實戰經驗中的最佳實踐。
開發環境設定 (docker-compose.dev.yaml)
開發環境需要支援即時程式碼更新(hot-reload)和依賴套件管理,以下是關鍵設定:
services:
asgi:
command: bash -c 'python manage.py runserver 0.0.0.0:${ASGI_PORT_INTERNAL}'
volumes:
- ${SOURCE_DIR}/:/project/src/
- ${PROJECT_DIR}/pdm.lock:/project/pdm.lock
- ${PROJECT_DIR}/pyproject.toml:/project/pyproject.toml
celery-beat:
volumes:
- ${SOURCE_DIR}/:/project/src/
celery-default:
volumes:
- ${SOURCE_DIR}/:/project/src/
nginx:
volumes:
- ${LOCAL_FILES_DIR}/nginx/conf/nginx.dev.conf:/etc/nginx/conf.d/default.conf
這個設定主要著重在:
- 掛載原始碼目錄,實作程式碼即時更新
- 掛載相依套件設定檔,確保套件管理工具正常運作
- 使用開發專用的 Nginx 設定
正式環境設定 (docker-compose.prod.yaml)
生產環境需要考慮效能與穩定性,設定重點有所不同:
services:
asgi:
command: bash -c 'python -m gunicorn config.asgi:application --bind 0.0.0.0:8000
--worker-class uvicorn.workers.UvicornWorker
--timeout 180
--workers $WORKERS_COUNT
--log-level debug
--access-logfile -
--error-logfile -
--pid /tmp/gunicorn.pid'
nginx:
volumes:
- ${LOCAL_FILES_DIR}/nginx/conf/nginx.prod.conf:/etc/nginx/conf.d/default.conf
生產環境設定重點:
- 使用 Gunicorn 搭配 Uvicorn worker 提供高效能的 ASGI 服務
- 可設定多個 worker 處理並發請求
- 採用生產環境專用的 Nginx 設定
檔案服務設定 (docker-compose.docs.yml)
針對技術檔案的服務設定:
services:
docs:
image: ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${TAG}
container_name: ${COMPOSE_PROJECT_NAME}-docs
env_file:
- ${PROJECT_DIR}/.env
environment:
- LOCAL_PYTEST=1
- ENVIRONMENT_TYPE=docker
volumes:
- ${PROJECT_DIR}:/src
- ${LOCAL_FILES_DIR}/asgi/static:/mnt/resource/static
- ${LOCAL_FILES_DIR}/asgi/media:/mnt/resource/media
- ${LOCAL_FILES_DIR}/asgi/tmp:/tmp
command: mkdocs serve --dev-addr 0.0.0.0:${DOCS_PORT_INTERNAL}
ports:
- "${DOCS_EXTERNAL_PORT}:${DOCS_PORT_INTERNAL}"
networks:
- app-network
檔案服務設定重點:
- 使用 MkDocs 提供即時檔案預覽服務
- 掛載必要的靜態資源和媒體檔案目錄
- 設定獨立的網路存取連線埠
在實際佈署時,玄貓建議:
- 開發環境保持程式碼同步更新,方便即時除錯
- 正式環境使用 Gunicorn 多工作程式提升效能
- 檔案服務最好在建置(CI/CD)階段就產生靜態檔案
- 各環境使用獨立的 Nginx 設定,以符合不同場景需求
以上設定雖然已經能滿足基本需求,但在大規模佈署時,建議諮詢 DevOps 工程師,針對特定場景進行最佳化調整。接下來,讓玄貓繼續分享 Redis 的設定。
在建構現代微服務架構時,妥善設定資料函式庫取服務是確保系統穩定性和效能的關鍵。讓我分享多年來在容器化環境中佈署Redis和PostgreSQL的實戰經驗,特別是如何透過Docker Compose實作高用性設定。
Redis服務設定精要
在處理快取服務時,Redis的設定雖然看似簡單,但其中仍有許多需要注意的細節。以下是一個經過最佳化的Redis服務設定:
services:
redis:
image: redis:7.4.0
container_name: ${COMPOSE_PROJECT_NAME}-redis
networks:
- app-network
ports:
- "${REDIS_PORT_EXTERNAL}:${REDIS_PORT_INTERNAL}"
這個設定雖然簡潔,但已經包含了幾個關鍵要素:
- 使用特定版本的Redis映像檔,避免版本不一致導致的問題
- 透過環境變數設定連線埠,提供更大的佈署彈性
- 將服務加入自定義網路,確保容器間的安全通訊
PostgreSQL進階設定
PostgreSQL的設定相對複雜,需要考慮到資料持久化、效能最佳化和備份機制:
services:
postgres:
build:
context: ${PROJECT_DIR}
dockerfile: ${DOCKER_DOCKERFILES_DIR}/postgres.dockerfile
container_name: ${COMPOSE_PROJECT_NAME}-postgres
command: ["postgres", "-c", "log_statement=all"]
shm_size: 1g
volumes:
- ${DOCKER_INITS_DIR}/postgresql.init.sql:/docker-entrypoint-initdb.d/init.sql
- ${LOCAL_FILES_DIR}/postgres/data/:/var/lib/postgresql/data/
- ${LOCAL_FILES_DIR}/postgres/log/:/var/log/postgresql/
- ${LOCAL_FILES_DIR}/postgres/backup/:/backup/
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_DB=${POSTGRES_DB}
ports:
- "${POSTGRES_PORT_EXTERNAL}:${POSTGRES_PORT_INTERNAL}"
networks:
- app-network
這個設定中,玄貓特別注意以下幾個關鍵點:
- 分享記憶體設定(shm_size):設定為1GB以提升資料函式庫
- 資料持久化:使用volume掛載確保資料安全
- 初始化指令碼:透過init.sql自動化資料函式庫設定
- 日誌記錄:設定完整的SQL陳述式記錄,便於除錯
- 備份機制:建立專用的備份目錄
應用程式建置最佳實踐
在本地開發環境中,有時需要更靈活的建置設定。以下是處理本地建置的關鍵設定:
x-asgi-local-build: &asgi-local-build
image: app:latest
build:
context: ${PROJECT_DIR}
dockerfile: ${DOCKER_DOCKERFILES_DIR}/asgi.dockerfile
target: development
args:
- USER_NAME=${USER_NAME}
- USER_ID=${USER_ID}
- GROUP_ID=${GROUP_ID}
services:
asgi:
<<: *asgi-local-build
這個設定特別適合開發階段使用,它提供了:
- 使用YAML錨點(anchor)重用設定
- 支援多階段建置
- 維持容器內外使用者許可權一致性
服務依賴關係管理
在微服務架構中,正確設定服務依賴關係至關重要:
asgi:
depends_on:
- redis
- postgres
links:
- postgres:postgres
celery-default:
depends_on:
- redis
- postgres
這樣的依賴設定確保了:
- 服務啟動順序的正確性
- 服務間網路連線的可靠性
- 系統啟動時的穩定性
在實際佈署中,這些設定檔案共同工作,構建了一個完整的開發環境。透過環境變數的靈活運用,可以在不同環境中輕鬆調整設定。這種方式不僅提高了系統的可維護性,也大幅降低了設定錯誤的風險。
在專案演進過程中,我們可能需要因應不同需求調整設定。例如,當需要新增函式庫整服務引數時,這些設定檔案提供了極大的靈活性。透過模組化的設定結構,我們可以輕鬆地進行區域性調整,而不影響整體系統的穩定性。
這些年來的實戰經驗告訴我們,良好的容器化設定不僅是技術細節的堆積積疊,更是對系統整體架構的深度思考。透過精心設計的Docker Compose設定,我們能夠建立一個既穩定又靈活的開發環境,為後續的系統擴充套件打下堅實基礎。
在現代軟體開發中,容器化已成為不可或缺的技術。今天玄貓要分享如何透過最佳實踐來最佳化 PostgreSQL 資料函式庫Python 應用程式的容器化建構流程。這些經驗來自於多年實際佈署大型系統的心得,能協助開發團隊建立更穩定、安全與易於維護的容器環境。
PostgreSQL 容器最佳化設計
基礎映像檔選擇與效能最佳化
首先來看 PostgreSQL 的 Dockerfile 設計:
FROM postgres:16.4-bullseye
# 安裝必要工具
RUN apt-get -y update
RUN apt-get -y install postgresql-16-repack
這個設計有幾個關鍵考量:
- 版本選擇:使用根據 Debian Bullseye 的 PostgreSQL 16.4,這是目前較為穩定與具備新功能的版本
- 工具安裝:加入 postgresql-repack 工具,用於資料函式庫與效能最佳化
- 建構最佳化:可以進一步合併 RUN 指令以減少映像檔層數
建議改良版本:
FROM postgres:16.4-bullseye
# 合併指令以減少層數並清理快取
RUN apt-get -y update \
&& apt-get -y install postgresql-16-repack \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Python 應用程式的多階段建構
基礎環境設定
Python 應用程式的容器化採用多階段建構方式,首先看基礎階段的設定:
FROM --platform=$BUILDPLATFORM python:3.12.6-slim AS python-base
# 系統引數設定
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG USER_NAME="user"
ARG GROUP_NAME="user"
# Python 環境變數設定
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=10 \
PDM_REQUEST_TIMEOUT=10 \
PDM_VERSION=2.19.1
關於環境設定的幾個重要考量:
- 使用 slim 版本基礎映像檔以減少容器大小
- 設定平台引數確保跨平台建構的一致性
- 設定使用者許可權,提升容器安全性
- 最佳化 Python 與套件管理工具的執行環境
PDM 相關設定
接著看 PDM 套件管理工具的設定:
FROM python-base AS base-pdm-builder
# 安裝建構依賴
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
DEBCONF_NONINTERACTIVE_SEEN=true DEBIAN_FRONTEND=noninteractive apt-get update \
&& apt-get install -y -qq --no-install-recommends \
build-essential \
ca-certificates \
gcc \
git \
curl
這個階段有幾個重要的最佳實踐:
- 使用建構快取加速後續建構
- 安裝最小化的必要套件
- 採用無互動式安裝減少建構時間
- 清理暫存檔案減少映像檔大小
開發、測試與生產環境的分離
不同環境使用不同的建構階段:
# 開發環境建構
FROM base-pdm-builder AS development-pdm-builder
RUN pdm install --check --dev
# 測試環境建構
FROM base-pdm-builder AS test-pdm-builder
RUN pdm install --check -G test --no-self
# 生產環境建構
FROM base-pdm-builder AS production-pdm-builder
RUN pdm install --check --production --no-self
這種分離的好處包括:
- 各環境擁有獨立的依賴項設定
- 生產環境映像檔更輕量
- 便於進行環境特定的最佳化
- 提升建構過程的可維護性
透過這樣的多階段建構設計,我們實作了:
- 最小化的最終映像檔大小
- 最佳化的建構效能
- 更好的安全性
- 靈活的環境設定
- 提升的可維護性
在實際佈署中,這種架構已經幫助玄貓的團隊顯著減少了容器相關的問題,並提升了整體系統的可靠性。記住,容器化不僅是將應用程式封裝進容器,更重要的是如何做好最佳化與安全性設計。
建議在實作類別似架構時,特別注意以下幾點:
- 確保基礎映像檔的安全性與更新
- 實施最小許可權原則
- 最佳化建構快取策略
- 定期檢查並更新依賴項
- 建立完整的監控與記錄機制
透過這些最佳實踐,能夠建立一個更加穩健的容器化環境,為應用程式的佈署與維護提供更好的基礎。
在現代軟體開發中,容器化已成為不可或缺的技術。在多年的容器化實踐中,玄貓發現許多開發團隊在建置 Python 應用程式的 Docker 映像檔時,常忽略了一些重要的最佳實踐。本文將分享如何透過多階段建置來最佳化 Python 應用程式的容器化流程。
基礎映像層的最佳實踐
在建置 Python 應用程式的 Docker 映像檔時,基礎層的設定至關重要。以下是關鍵的設定重點:
系統相依性管理
FROM python-base AS base-project-builder
ARG USER_ID
ARG GROUP_ID
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
DEBCONF_NONINTERACTIVE_SEEN=true \
DEBIAN_FRONTEND=noninteractive \
apt-get update && \
apt-get install -y -qq --no-install-recommends \
locales \
libmagic1 \
pkg-config \
libcairo2-dev \
libjpeg-dev \
libgif-dev
- 採用
--mount=type=cache
來快取 apt 相關目錄,提升建置效率 - 使用
DEBIAN_FRONTEND=noninteractive
確保安裝過程不會出現互動式提示 - 精確指定必要的系統依賴,避免安裝不必要的套件
- 使用
--no-install-recommends
降低映像檔大小
地區設定與使用者許可權
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
dpkg-reconfigure --frontend=noninteractive locales && \
update-locale LANG=en_US.UTF-8 && \
addgroup --gid $GROUP_ID $GROUP_NAME && \
adduser -q --gecos '' --disabled-password \
--ingroup $GROUP_NAME --shell /bin/bash --uid $USER_ID $USER_NAME
- 設定系統語言為 en_US.UTF-8,確保應用程式運作的一致性
- 建立特定的使用者和群組,遵循最小許可權原則
- 使用 ARG 傳入的 USER_ID 和 GROUP_ID,確保容器內外許可權一致
目錄結構與許可權設定
為了確保應用程式正常運作,必須建立適當的目錄結構並設定正確的許可權:
RUN mkdir -p /mnt/resource/static && \
mkdir -p /mnt/resource/media && \
mkdir -p $APPLICATION_PATH && \
touch $APPLICATION_PATH/celerybeat-schedule && \
chown -R $USER_ID:$GROUP_ID /tmp/ && \
chown -R $USER_ID:$GROUP_ID /mnt/ && \
chown -R $USER_ID:$GROUP_ID /opt/ && \
chown -R $USER_ID:$GROUP_ID /project/ && \
chown -R $USER_ID:$GROUP_ID /var/log/
- 建立靜態檔案和媒體檔案的儲存目錄
- 設定 Celery 排程檔案
- 確保所有目錄的擁有者為應用程式執行使用者
- 設定適當的目錄許可權,提升安全性
開發環境設定
開發環境的設定需要特別注意開發便利性和除錯功能:
FROM base-project-builder AS development
COPY --link --chown=$USER_ID:$GROUP_ID --from=development-pdm-builder $PDM_HOME $PDM_HOME
COPY --link --chown=$USER_ID:$GROUP_ID --from=development-pdm-builder $PROJECT_PATH $PROJECT_PATH
COPY --link ./src $APPLICATION_PATH
COPY --link ./docs $APPLICATION_PATH/docs
COPY --link ./mkdocs.yml $APPLICATION_PATH/mkdocs.yml
- 使用
--link
最佳化檔案複製效能 - 複製開發相關檔案和設定
- 確保檔案擁有者許可權正確
- 保留檔案方便開發時參考
測試與生產環境的差異化設定
測試和生產環境需要更嚴格的安全性考量:
FROM base-project-builder AS test
COPY --link --from=test-pdm-builder $PDM_HOME $PDM_HOME
COPY --link --from=test-pdm-builder $PROJECT_PATH $PROJECT_PATH
COPY --link ./src $APPLICATION_PATH
FROM base-project-builder AS production
COPY --link --from=production-pdm-builder $PDM_HOME $PDM_HOME
COPY --link --from=production-pdm-builder $PROJECT_PATH $PROJECT_PATH
COPY --link ./src $APPLICATION_PATH
- 測試環境和生產環境使用不同的基礎映像
- 精簡生產環境中的檔案和工具
- 確保各環境的依賴版本一致性
- 移除生產環境中的開發工具和檔案
在實務經驗中,玄貓發現合理的多階段建置不僅能提升映像檔的安全性,還能大幅減少最終映像檔的大小。透過區分開發、測試和生產環境的設定,我們能更好地管理應用程式在不同階段的需求,同時確保佈署過程的一致性和可靠性。
在建置 Python 應用程式的 Docker 映像檔時,安全性、效能和維護性是三個關鍵考量。透過適當的多階段建置設定,我們能在這三個導向取得良好的平衡。記得定期檢視和更新 Dockerfile,確保它能持續滿足專案需求,並反映最新的容器化最佳實踐。
在多年的後端開發經驗中,玄貓發現良好的專案環境設定與相依性管理是確保開發效率和專案穩定性的關鍵。今天要分享如何建立一個完整的 Django 專案開發環境,並使用現代化工具進行相依性管理。
環境需求與準備
開始之前,需要確保系統已安裝以下元件:
- Python 3.12.6 或以上版本
- Docker 27.2.1 或以上版本
- PDM 2.19.1 (Python 相依性管理工具)
專案啟動流程
玄貓設計了一個名為 compose
的指令碼來簡化專案啟動流程。這個指令碼主要負責:
- 準備執行環境
- 載入環境變數
- 轉發命令到 Docker Compose
以下是核心指令碼內容:
#!/bin/bash
bash.prepare.sh
source ".env"
ARGS_STRING=""
while [ $1 ]
do
ARGS_STRING+="$1 "
shift
done
docker compose ${ARGS_STRING}
指令碼解密
- 指令碼首先執行
bash.prepare.sh
進行環境準備 - 接著載入
.env
檔案中的環境變數 - 透過迴圈收集並組合所有傳入的引數
- 最後將引數轉發給
docker compose
命令執行
常用專案管理命令
開發過程中常用的專案管理指令:
# 建置並啟動容器
./compose up -d --build
# 重新啟動服務
./compose restart
# 關閉所有容器
./compose down
# 進入容器執行命令
./compose exec -it <container_name> <command>
PDM 相依性管理實務
在開發大型 Django 專案時,玄貓發現 PDM 是一個非常優秀的相依性管理工具。以下是一些關鍵的相依性管理操作:
新增依賴套件
# 新增一般依賴
./compose exec -it asgi pdm add <package_name>
# 新增特定群組的依賴
./compose exec -it asgi pdm add -dG <group> <package_name>
移除依賴套件
# 移除指定套件
./compose exec -it asgi pdm remove <package_name>
專案設定檔案說明
專案的 pyproject.toml
設定檔案定義了專案的基本資訊和依賴需求。以下是一個實用的設定範例:
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
[project]
name = "YOUR_PROJECT"
dynamic = ["version"]
description = "主要應用程式"
readme = "README.md"
requires-python = ">=3.12"
authors = [
{ name = "Your Name", email = "your@email.com" }
]
maintainers = [
{ name = "Your Name", email = "your@email.com" }
]
dependencies = [
# Django 核心套件
"django>=5.1.1",
"djangorestframework>=3.15.2",
"django-extensions>=3.2.3",
# CORS 處理
"django-cors-headers>=4.4.0",
"whitenoise>=6.7.0",
# Celery 相關套件
"celery>=5.4.0",
"django-celery-beat>=2.7.0",
"django-celery-results>=2.5.1",
"flower>=2.0.1",
# Redis 整合
"redis>=5.1.0",
"django-redis>=5.4.0",
# 資料驗證與序列化
"pydantic[email]>=2.9.2",
"pydantic-extra-types>=2.9.0",
# 檔案儲存
"django-storages[s3]>=1.14.4",
# Web 伺服器
"uvicorn>=0.31.0",
"gunicorn>=23.0.0"
]
透過這樣的設定,我們可以確保專案依賴的版本控制和環境一致性。以上的依賴清單是玄貓根據多年開發經驗精選的套件組合,涵蓋了大多數 Django 專案的基本需求。
在實際開發中,這些工具和設定可以大幅提升開發效率,減少環境相關的問題。特別是在團隊協作時,統一的環境設定和相依性管理方式更是不可或缺。透過容器化和現代化的相依性管理工具,能夠讓開發團隊專注於業務邏輯的實作,而不是浪費時間在環境問題的處理上。
在建置完這樣的開發環境後,開發團隊可以更專注於功能開發,同時也為後續的持續整合和佈署奠定良好的基礎。這種標準化的環境設定不僅提高了開發效率,也大幅降低了專案維護的成本。
在多年的 Python 開發經驗中,專案相依性管理與開發環境設定一直是確保專案品質的關鍵。今天玄貓要分享如何使用 PDM 這個現代化的 Python 套件管理工具,建立一個完整與專業的開發環境。
核心依賴設定
首先,讓我們設定專案的核心依賴。這些是專案執行所必需的基礎套件:
[project]
dependencies = [
"fastapi>=0.110.0",
"uvicorn-worker>=0.2.0",
"envparse>=0.2.0",
"toml>=0.10.2",
"markdown>=3.7",
"psycopg2-binary>=2.9.9",
"sentry-sdk[celery]>=2.15.0",
"requests>=2.32.3",
"pyjwt>=2.10.1",
"Pillow>=11.1.0"
]
- fastapi 與 uvicorn-worker:用於建立高效能的 Web API 服務
- envparse:處理環境變數的工具,簡化設定管理
- psycopg2-binary:PostgreSQL 資料函式庫程式
- sentry-sdk:錯誤追蹤與監控整合
- 其他工具如 markdown、Pillow 等則用於特定功能實作
開發環境相依性管理
在開發過程中,我們需要不同類別的工具支援,這些工具分為幾個主要類別:
[tool.pdm.dev-dependencies]
test = [
"pytest>=8.3.3",
"coverage>=7.6.1",
"pytest-cov>=6.0.0",
"pytest-django>=4.9.0",
"pytest-celery>=1.1.3"
]
doc = [
"mkdocs>=1.6.1",
"mkdocstrings[python]>=0.26.1",
"mkdocs-material>=9.5.39"
]
lint = [
"black>=24.8.0",
"ruff>=0.6.8"
]
dev = [
"pre-commit>=3.8.0"
]
- 測試工具:pytest 生態系統用於單元測試與覆寫率分析
- 檔案工具:使用 mkdocs 建立專案檔案
- 程式碼品質工具:black 用於程式碼格式化,ruff 用於靜態程式碼分析
- 開發工具:pre-commit 用於設定提交前的程式碼檢查
版本管理設定
版本控制是專案管理的重要環節,這裡使用 bump-my-version 來管理:
[tool.bumpversion]
current_version = "0.0.2"
tag = true
tag_name = "v{new_version}"
tag_message = "Bump version: {current_version} → {new_version}"
commit = true
message = "Bump version: {current_version} → {new_version}"
[[tool.bumpversion.files]]
filename = "src/__init__.py"
[[tool.bumpversion.files]]
filename = "README.md"
search = "Версия - v{current_version}"
replace = "Версия - v{new_version}"
- 自動化版本更新流程
- 自動建立 Git 標籤與提交訊息
- 同步更新多個檔案中的版本號
程式碼品質規範
使用 ruff 工具進行程式碼品質控制:
[tool.ruff]
target-version = "py312"
line-length = 120
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"C", # flake8-comprehensions
"B", # flake8-bugbear
"S", # flake8-bandit
"Q", # flake8-quotes
"PL", # Pylint
"RUF100" # Unused noqa directive
]
- 設定 Python 目標版本與程式碼行寬度限制
- 啟用多種程式碼檢查規則
- 包含安全性檢查、程式碼風格、效能最佳化等多個導向
測試環境設定
最後,設定測試環境的執行引數:
[tool.pytest.ini_options]
addopts = "--no-migrations --failed-first --verbose --maxfail=1 -p no:warnings --create-db --ds=settings.test_settings"
- 停用資料函式庫以加速測試
- 優先執行失敗的測試案例
- 設定測試資料函式庫
- 指定測試專用的 Django 設定檔
透過這套完整的設定,我們建立了一個高效能、易維護與品質可控的 Python 開發環境。這些設定不僅確保了程式碼品質,也大幅提升了開發團隊的工作效率。記得依據專案需求適當調整這些設定,以達到最佳的開發體驗。
在多年的開發經驗中,玄貓發現良好的專案設定可以避免許多常見問題,並為團隊節省大量時間。這些設定雖然前期需要投入時間設定,但從長遠來看,絕對是值得的投資。
在多年的Python專案開發經驗中,玄貓發現良好的專案設定是確保程式碼品質與團隊協作的關鍵。今天要分享如何整合pytest測試框架、mkdocs檔案系統與pre-commit程式碼檢查工具,開發一個專業的Python開發環境。
pytest測試設定精要
首先來看pytest的核心設定:
norecursedirs = ["static", "migrations", "templates"]
python_files = "test_*.py"
django_find_project = false
[tool.coverage.run]
omit = ['*/tests/*', '*/migrations/*', 'settings/*']
這組設定主要處理以下幾個重點:
- 設定不需要遞迴搜尋的目錄,避免測試執行時包含靜態檔案與遷移檔案
- 指定測試檔案的命名模式,確保測試檔案識別的一致性
- 排除特定目錄的程式碼覆寫率統計,使覆寫率報告更準確反映實際情況
mkdocs檔案系統設定
接下來是mkdocs的設定範例:
site_name: YOUR_SITE
nav:
- 首頁: index.md
theme:
name: material
highlightjs: true
hljs_languages:
- yaml
- python
features:
- navigation.instant
- navigation.instant.progress
- navigation.tracking
- navigation.tabs
- navigation.tabs.sticky
- navigation.sections
- navigation.expand
- navigation.path
- navigation.indexes
- navigation.top
- toc.follow
這個設定為檔案系統提供了:
- Material主題的現代化介面
- 程式碼高亮支援YAML與Python
- 豐富的導航功能,包含即時導航、進度顯示與標籤式導航
- 自動生成目錄與索引功能
pre-commit程式碼檢查設定
最後來看pre-commit的設定:
default_language_version:
python: python3.12
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-toml
- id: check-yaml
args:
- --unsafe
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.0
hooks:
- id: pyupgrade
args: [--py312-plus]
- repo: https://github.com/psf/black
rev: 24.8.0
hooks:
- id: black
args: [src, --config,./pyproject.toml, --skip-magic-trailing-comma]
這份設定整合了多個重要的程式碼品質工具:
- 基本的檔案檢查,如大型檔案檢測與格式驗證
- pyupgrade確保使用最新的Python語法特性
- black程式碼格式化工具,維持一致的程式碼風格
在建置大型Python專案時,這些工具的整合設定能夠顯著提升開發效率與程式碼品質。透過自動化的測試、檔案生成與程式碼檢查,我們可以專注於核心業務邏輯的開發,同時確保專案的可維護性和擴充套件性。
經過多年的專案經驗,玄貓建議在專案初期就建立完善的開發環境設定,這樣可以避免後期因程式碼品質問題而產生的技術債。這些工具的組合不僅能提升個人開發效率,更能促進團隊協作的順暢度。
在多年的後端開發經驗中,我發現良好的專案設定是確保開發效率和系統穩定性的關鍵。今天特別分享一套經過實戰檢驗的FastAPI專案設定方案,這些設定檔都是經過精心調校,適合團隊開發使用。
程式碼品質管理設定
在專案根目錄建立品質管理工具設定:
- --fix
- id: ruff-format
- repo: https://github.com/asottile/reorder-python-imports
rev: v3.14.0
hooks:
- id: reorder-python-imports
args: [--py312-plus]
這個設定主要用於確保程式碼風格統一,特別是針對Python匯入陳述式的排序。採用ruff-format作為程式碼格式化工具,能有效維持程式碼的一致性。
Git忽略規則設定
建立 .gitignore 檔案,排除不需要版本控制的檔案:
# 環境相關
/.env.local
/.pdm-python
/.venv/
/.ruff_cache/
/.cache/
# 專案特定
/.deploy/
/.local_files/
/src/settings/local_settings.py
/src/migrations/versions/
/src/celerybeat-schedule
/src/celerybeat-schedule.db
/src/settings/local.py
# 開發工具
/.idea/
/src/static/
/src/report.xml
/src/coverage.xml
/src/.coverage
/src/report.html
Docker忽略規則
設定 .dockerignore 以最佳化Docker映像檔建置:
# Python開發環境
.idea/
.venv/
# 專案本地檔案
.local_files/
.ruff_cache/
.env
.env.local
# 專案資料
/pipelines/
/scripts/
/src/celerybeat-schedule
/src/coverage.xml
/src/.coverage
/src/report.xml
/src/settings/local_settings.py
# 版本控制
.git
.gitignore
.gitattributes
基礎設定檔設定
在 src/settings/base_settings.py 中建立核心設定:
from __future__ import annotations
from pathlib import Path
import toml
from envparse import env
# 專案根目錄設定
BASE_DIR = Path(__file__).resolve().parent.parent
# 讀取專案metadata
with Path(BASE_DIR.parent, "pyproject.toml").open("r") as toml_file:
TOML_METADATA = toml.load(toml_file)
# 版本控制
VERSION = TOML_METADATA["tool"]["bumpversion"]["current_version"]
# 環境設定
DEBUG = env.bool("DEBUG", default=False)
PRODUCTION = env.bool("PRODUCTION", default=False)
TEST_MODE = False
# 安全設定
SECRET_KEY = env.str("SECRET_KEY", default="")
# 網站URL設定
SITE_PROTOCOL = env.str("SITE_PROTOCOL", default="http")
SITE_DOMAIN = env.str("SITE_DOMAIN", default="127.0.0.1")
SITE_PORT = env.str("SITE_PORT", default=None)
SITE_URL = f"{SITE_PROTOCOL}://{SITE_DOMAIN}"
SITE_API_PATH = env.str("SITE_API_PATH", default="api/v1")
if SITE_PORT:
SITE_URL = f"{SITE_URL}:{SITE_PORT}"
SITE_API_URL = f"{SITE_URL}/{SITE_API_PATH}"
Nginx伺服器設定
建立基礎的Nginx設定:
server {
listen 0.0.0.0:${NGINX_PORT_INTERNAL};
server_name 0.0.0.0 ${HOST_NAME};
set $backend asgi:${ASGI_PORT_INTERNAL};
set $docs docs:${DOCS_PORT_INTERNAL};
resolver 127.0.0.11 valid=10s;
client_max_body_size 100M;
location /media/ {
alias /media/;
autoindex off;
}
location /docs/ {
proxy_pass http://$docs;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass_request_headers on;
proxy_connect_timeout 1800;
}
}
Git忽略規則說明
- 環境相關檔案:包含所有本地環境設定和暫存檔案
- 專案特設定檔案:排除本地設定和資料函式庫檔案
- 開發工具產生的檔案:如IDE設定和測試報告
Docker忽略規則重點
- 開發環境檔案:避免將開發環境的設定帶入容器
- 本地設定檔案:確保容器使用正確的生產環境設定
- 版本控制相關:減少映像檔大小
基礎設定檔解析
- 路徑設定:使用Path確保跨平台相容性
- 環境變數處理:採用envparse處理設定變數
- URL設定:靈活的網站URL組合邏輯
Nginx設定要點
- 動態連線埠設定:使用環境變數方便調整
- 媒體檔案處理:獨立的媒體檔案存取設定
- API檔案代理:為Swagger檔案提供存取設定
在實際開發中,這些設定檔案都需要根據專案需求進行調整。特別是Nginx設定,建議在正式環境中加入更多安全性設定,如SSL設定、請求限制等。這些基礎設定提供了一個穩固的開發基礎,讓團隊可以專注於業務邏輯開發。
經過多年的專案開發,我深知設定檔的重要性。良好的設定不僅能提升開發效率,更能預防許多潛在問題。這些設定範本雖然看似簡單,但都凝聚了實戰經驗,希望能為其他開發者提供參考價值。
# 設定代理超時間
proxy_send_timeout 1800;
proxy_read_timeout 1800;
send_timeout 1800;
# 路由設定
location / {
# 代理傳遞設定
proxy_pass http://$backend;
proxy_http_version 1.1;
# WebSocket支援
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 請求標頭設定
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass_request_headers on;
# 代理超時設定
proxy_connect_timeout 1800;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
send_timeout 1800;
}
在長期建置與維護大型系統的過程中,玄貓發現合適的代理伺服器設定對於系統的穩定性與效能有著關鍵性的影響。在處理高併發場景時,適當的超時設定尤其重要。根據多年的實務經驗,這些設定引數的設定需要根據實際應用場景來調整,而不是簡單地照搬預設值。
以上的 Nginx 設定重點在於幾個關鍵方面:
首先是超時設定的統一性。所有相關的超時引數都設定為 1800 秒,這是根據大多數應用場景的實際需求所定。這樣的設定可以有效處理較長時間的連線請求,特別適用於需要處理大量資料傳輸或複雜運算的場景。
其次是 WebSocket 的支援設定。透過設定 Upgrade 和 Connection 標頭,確保 WebSocket 連線可以順利建立和維持。這在建置即時通訊或串流服務時特別重要。
再來是完整的代理標頭設定。這些設定確保了後端服務可以獲得真實的客戶端資訊,對於安全性監控和流量分析都很重要。特別是 X-Forwarded-For 標頭,它可以幫助追蹤請求的來源路徑。
最後要提到的是效能最佳化。proxy_http_version 1.1 的設定允許使用持久連線,這可以顯著減少連線建立的開銷。而 proxy_pass_request_headers 的啟用則確保所有重要的請求標頭都能正確傳遞給後端服務。
在實際佈署時,建議根據系統的具體需求來調整這些引數。例如,如果是處理較小的請求,可以適當縮短超時間;如果是需要處理大檔案上載,則可能需要延長超時設定。關鍵是要根據實際監控資料來最佳化這些設定。
這套設定經過實戰檢驗,能夠有效處理大多數的代理需求,同時保持了良好的擴充套件性和維護性。透過這樣的設定,可以建構出一個穩定、高效的代理層,為整個系統提供可靠的服務。