From 3b8a55adea9d55d733d0794c4c8c9d54a089da61 Mon Sep 17 00:00:00 2001 From: fawney19 Date: Thu, 11 Dec 2025 18:16:19 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=92=8C=E9=85=8D=E7=BD=AE=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=A2=84=E6=9E=84=E5=BB=BA=E9=95=9C=E5=83=8F=E5=92=8C?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E6=9E=84=E5=BB=BA=E4=B8=A4=E7=A7=8D=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docker-publish.yml | 135 +++++++++++++++++++++++++++ README.md | 22 +++-- deploy.sh | 4 +- docker-compose.build.yml | 78 ++++++++++++++++ docker-compose.yml | 10 +- 5 files changed, 234 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/docker-publish.yml create mode 100644 docker-compose.build.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..a3b5f09 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,135 @@ +name: Build and Publish Docker Image + +on: + push: + branches: [master, main] + tags: ['v*'] + pull_request: + branches: [master, main] + workflow_dispatch: + inputs: + build_base: + description: 'Rebuild base image' + required: false + default: false + type: boolean + +env: + REGISTRY: ghcr.io + BASE_IMAGE_NAME: ${{ github.repository }}-base + APP_IMAGE_NAME: ${{ github.repository }} + +jobs: + check-base-changes: + runs-on: ubuntu-latest + outputs: + base_changed: ${{ steps.check.outputs.base_changed }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Check if base image needs rebuild + id: check + run: | + if [ "${{ github.event.inputs.build_base }}" == "true" ]; then + echo "base_changed=true" >> $GITHUB_OUTPUT + exit 0 + fi + + # Check if base-related files changed + if git diff --name-only HEAD~1 HEAD | grep -qE '^(Dockerfile\.base|pyproject\.toml|frontend/package.*\.json)$'; then + echo "base_changed=true" >> $GITHUB_OUTPUT + else + echo "base_changed=false" >> $GITHUB_OUTPUT + fi + + build-base: + needs: check-base-changes + if: needs.check-base-changes.outputs.base_changed == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for base image + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.BASE_IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,prefix= + + - name: Build and push base image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.base + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 + + build-app: + needs: [check-base-changes, build-base] + if: always() && (needs.build-base.result == 'success' || needs.build-base.result == 'skipped') + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for app image + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.APP_IMAGE_NAME }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix= + + - name: Update Dockerfile.app to use registry base image + run: | + sed -i "s|FROM aether-base:latest|FROM ${{ env.REGISTRY }}/${{ env.BASE_IMAGE_NAME }}:latest|g" Dockerfile.app + + - name: Build and push app image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.app + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 diff --git a/README.md b/README.md index 2faf73d..693815d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Aether 是一个自托管的 AI API 网关,为团队和个人提供多租户 ## 部署 -### Docker Compose(推荐) +### Docker Compose(推荐:预构建镜像) ```bash # 1. 克隆代码 @@ -58,16 +58,24 @@ cp .env.example .env python generate_keys.py # 生成密钥, 并将生成的密钥填入 .env # 3. 部署 -./deploy.sh # 自动构建、启动、迁移 +docker-compose up -d + +# 4. 更新 +docker-compose pull && docker-compose up -d ``` -### 更新 +### Docker Compose(本地构建镜像) ```bash -# 拉取最新代码 -git pull +# 1. 克隆代码 +git clone https://github.com/fawney19/Aether.git +cd aether -# 自动部署脚本 +# 2. 配置环境变量 +cp .env.example .env +python generate_keys.py # 生成密钥, 并将生成的密钥填入 .env + +# 3. 部署 / 更新(自动构建、启动、迁移) ./deploy.sh ``` @@ -75,7 +83,7 @@ git pull ```bash # 启动依赖 -docker-compose up -d postgres redis +docker-compose -f docker-compose.build.yml up -d postgres redis # 后端 uv sync diff --git a/deploy.sh b/deploy.sh index 233396e..6e039d3 100755 --- a/deploy.sh +++ b/deploy.sh @@ -11,9 +11,9 @@ cd "$(dirname "$0")" # 兼容 docker-compose 和 docker compose if command -v docker-compose &> /dev/null; then - DC="docker-compose" + DC="docker-compose -f docker-compose.build.yml" else - DC="docker compose" + DC="docker compose -f docker-compose.build.yml" fi # 缓存文件 diff --git a/docker-compose.build.yml b/docker-compose.build.yml new file mode 100644 index 0000000..e89a878 --- /dev/null +++ b/docker-compose.build.yml @@ -0,0 +1,78 @@ +# Aether 部署配置 - 本地构建 +# 使用方法: +# 首次构建 base: docker build -f Dockerfile.base -t aether-base:latest . +# 启动服务: docker-compose -f docker-compose.build.yml up -d --build + +services: + postgres: + image: postgres:15 + container_name: aether-postgres + environment: + POSTGRES_DB: aether + POSTGRES_USER: postgres + POSTGRES_PASSWORD: ${DB_PASSWORD} + TZ: Asia/Shanghai + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "${DB_PORT:-5432}:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + restart: unless-stopped + + redis: + image: redis:7-alpine + container_name: aether-redis + command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} + volumes: + - redis_data:/data + ports: + - "${REDIS_PORT:-6379}:6379" + healthcheck: + test: ["CMD", "redis-cli", "--raw", "incr", "ping"] + interval: 5s + timeout: 3s + retries: 5 + restart: unless-stopped + + app: + build: + context: . + dockerfile: Dockerfile.app + image: aether-app:latest + container_name: aether-app + environment: + DATABASE_URL: postgresql://postgres:${DB_PASSWORD}@postgres:5432/aether + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0 + PORT: 8084 + JWT_SECRET_KEY: ${JWT_SECRET_KEY} + ENCRYPTION_KEY: ${ENCRYPTION_KEY} + JWT_ALGORITHM: HS256 + JWT_EXPIRATION_DELTA: 86400 + LOG_LEVEL: ${LOG_LEVEL:-INFO} + ADMIN_EMAIL: ${ADMIN_EMAIL} + ADMIN_USERNAME: ${ADMIN_USERNAME} + ADMIN_PASSWORD: ${ADMIN_PASSWORD} + API_KEY_PREFIX: ${API_KEY_PREFIX:-sk} + GUNICORN_WORKERS: ${GUNICORN_WORKERS:-4} + TZ: Asia/Shanghai + PYTHONIOENCODING: utf-8 + LANG: C.UTF-8 + LC_ALL: C.UTF-8 + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + ports: + - "${APP_PORT:-8084}:80" + volumes: + - ./logs:/app/logs + restart: unless-stopped + +volumes: + postgres_data: + redis_data: diff --git a/docker-compose.yml b/docker-compose.yml index efcd7b5..60afccf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ -# Aether 部署配置 -# 使用 ./deploy.sh 自动部署 +# Aether 部署配置 - 使用预构建镜像 +# 使用方法: docker-compose up -d services: postgres: @@ -37,7 +37,7 @@ services: restart: unless-stopped app: - image: aether-app:latest + image: ghcr.io/fawney19/aether:latest container_name: aether-app environment: DATABASE_URL: postgresql://postgres:${DB_PASSWORD}@postgres:5432/aether @@ -65,11 +65,9 @@ services: ports: - "${APP_PORT:-8084}:80" volumes: - # 挂载日志目录到主机,便于调试和持久化 - ./logs:/app/logs restart: unless-stopped - volumes: postgres_data: - redis_data: \ No newline at end of file + redis_data: