chore(deploy): add backend ECR deployment flow
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
# 觅爻生产部署指南
|
||||
|
||||
## 目录说明
|
||||
|
||||
`deploy/` 用于存放生产环境启动所需文件:
|
||||
|
||||
- `docker-compose.prod.yml`:生产 Docker Compose 启动配置,只拉取已有镜像,不负责构建。
|
||||
- `.env`:生产环境变量文件,本文件包含敏感信息,不应提交到 Git。
|
||||
|
||||
## 前置条件
|
||||
|
||||
生产机器需要安装:
|
||||
|
||||
- Docker
|
||||
- Docker Compose v2
|
||||
- AWS CLI v2
|
||||
|
||||
确认命令:
|
||||
|
||||
```bash
|
||||
docker --version
|
||||
docker compose version
|
||||
aws --version
|
||||
```
|
||||
|
||||
## 环境变量
|
||||
|
||||
`docker-compose.prod.yml` 默认从当前目录读取 `.env`:
|
||||
|
||||
```bash
|
||||
deploy/.env
|
||||
```
|
||||
|
||||
必须包含 AWS ECR 镜像定位变量:
|
||||
|
||||
```text
|
||||
AWS_ACCOUNT_ID=<你的 AWS 账号 ID>
|
||||
AWS_REGION=<ECR 所在区域>
|
||||
ECR_REPOSITORY=<ECR 仓库名>
|
||||
```
|
||||
|
||||
如果本目录下的 `.env` 是从项目根目录 `.env` 复制过来的,通常还需要手动追加以上三个变量。
|
||||
|
||||
默认镜像地址会拼接为:
|
||||
|
||||
```text
|
||||
${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}:latest
|
||||
```
|
||||
|
||||
如果要手动指定完整镜像地址,可以在 `.env` 中设置:
|
||||
|
||||
```text
|
||||
ERYAO_BACKEND_IMAGE=<完整镜像地址>
|
||||
```
|
||||
|
||||
Web 服务端口使用项目环境变量:
|
||||
|
||||
```text
|
||||
ERYAO_WEB__PORT=5775
|
||||
```
|
||||
|
||||
默认只绑定本机回环地址:
|
||||
|
||||
```text
|
||||
ERYAO_DEPLOY_BIND_HOST=127.0.0.1
|
||||
```
|
||||
|
||||
如果生产机器没有 Nginx、ALB 或其他反向代理,需要直接对外暴露端口,可改为:
|
||||
|
||||
```text
|
||||
ERYAO_DEPLOY_BIND_HOST=0.0.0.0
|
||||
```
|
||||
|
||||
## 登录 ECR
|
||||
|
||||
进入部署目录,并把 `.env` 加载到当前 shell:
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
set -a
|
||||
. ./.env
|
||||
set +a
|
||||
```
|
||||
|
||||
在生产机器上配置好 AWS 凭据后执行:
|
||||
|
||||
```bash
|
||||
aws ecr get-login-password --region "$AWS_REGION" \
|
||||
| docker login --username AWS --password-stdin \
|
||||
"${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
|
||||
```
|
||||
|
||||
## 启动服务
|
||||
|
||||
启动 Web、Redis 和 worker:
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers pull
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers up -d
|
||||
```
|
||||
|
||||
只启动 Web 和 Redis:
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
## 健康检查
|
||||
|
||||
如果 `ERYAO_WEB__PORT=5775`:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:5775/health
|
||||
```
|
||||
|
||||
期望返回:
|
||||
|
||||
```json
|
||||
{"status":"ok"}
|
||||
```
|
||||
|
||||
## 查看状态和日志
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers ps
|
||||
docker logs -f eryao-prod-backend
|
||||
docker logs -f eryao-prod-worker-agent
|
||||
docker logs -f eryao-prod-worker-general
|
||||
docker logs -f eryao-prod-redis
|
||||
```
|
||||
|
||||
## 更新版本
|
||||
|
||||
CI 推送新镜像到 ECR 后,在生产机器执行:
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers pull
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers up -d
|
||||
```
|
||||
|
||||
## 停止服务
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers down
|
||||
```
|
||||
|
||||
如需连 Redis 数据卷一起删除:
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers down -v
|
||||
```
|
||||
|
||||
谨慎使用 `down -v`,它会删除 Redis 持久化数据。
|
||||
@@ -0,0 +1,79 @@
|
||||
name: eryao-prod
|
||||
|
||||
x-backend-common: &backend-common
|
||||
image: ${ERYAO_BACKEND_IMAGE:-${AWS_ACCOUNT_ID:?AWS_ACCOUNT_ID is required}.dkr.ecr.${AWS_REGION:?AWS_REGION is required}.amazonaws.com/${ECR_REPOSITORY:?ECR_REPOSITORY is required}:latest}
|
||||
env_file:
|
||||
- path: ./.env
|
||||
required: true
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
services:
|
||||
backend:
|
||||
<<: *backend-common
|
||||
container_name: eryao-prod-backend
|
||||
environment:
|
||||
ERYAO_RUNTIME__ENVIRONMENT: prod
|
||||
ERYAO_RUNTIME__SERVICE_NAME: web
|
||||
ERYAO_REDIS__HOST: redis
|
||||
ERYAO_REDIS__PORT: 6379
|
||||
ports:
|
||||
- "${ERYAO_DEPLOY_BIND_HOST:-127.0.0.1}:${ERYAO_WEB__PORT:-5775}:${ERYAO_WEB__PORT:-5775}"
|
||||
|
||||
worker-agent:
|
||||
<<: *backend-common
|
||||
container_name: eryao-prod-worker-agent
|
||||
profiles: ["workers"]
|
||||
environment:
|
||||
ERYAO_RUNTIME__ENVIRONMENT: prod
|
||||
ERYAO_RUNTIME__SERVICE_NAME: worker-agent
|
||||
ERYAO_REDIS__HOST: redis
|
||||
ERYAO_REDIS__PORT: 6379
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- exec taskiq worker core.taskiq.app:worker_agent_broker core.agentscope.runtime.tasks --workers ${ERYAO_WORKER__GROUPS__AGENT__CONCURRENCY:-2}
|
||||
|
||||
worker-general:
|
||||
<<: *backend-common
|
||||
container_name: eryao-prod-worker-general
|
||||
profiles: ["workers"]
|
||||
environment:
|
||||
ERYAO_RUNTIME__ENVIRONMENT: prod
|
||||
ERYAO_RUNTIME__SERVICE_NAME: worker-general
|
||||
ERYAO_REDIS__HOST: redis
|
||||
ERYAO_REDIS__PORT: 6379
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- exec taskiq worker core.taskiq.app:worker_general_broker core.agentscope.runtime.tasks v1.feedback.tasks --workers ${ERYAO_WORKER__GROUPS__GENERAL__CONCURRENCY:-1}
|
||||
|
||||
redis:
|
||||
image: redis:7.4.2-alpine
|
||||
container_name: eryao-prod-redis
|
||||
env_file:
|
||||
- path: ./.env
|
||||
required: true
|
||||
environment:
|
||||
REDIS_PASSWORD: ${ERYAO_REDIS__PASSWORD:-}
|
||||
command: >
|
||||
sh -c 'if [ -n "$$REDIS_PASSWORD" ]; then redis-server --appendonly yes --requirepass "$$REDIS_PASSWORD"; else redis-server --appendonly yes; fi'
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"sh",
|
||||
"-c",
|
||||
'if [ -n "$$REDIS_PASSWORD" ]; then redis-cli -a "$$REDIS_PASSWORD" ping; else redis-cli ping; fi',
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
redis_data:
|
||||
Reference in New Issue
Block a user