Files
ai-proj-helper/plugins/ops-tools-plugin/ai-proj-deploy.md

7.5 KiB
Raw Blame History

AI-Proj 部署指南

创建时间: 2026-01-29 11:50:00 CST 父技能: ops-tools

环境概览

环境 服务器 域名 镜像标签
生产 tools_ai_proj (152.136.104.251) https://ai.pipexerp.com latest
测试 singapore (43.134.28.147) http://staging.ai.pipexerp.com test

镜像信息

服务 镜像
后端 saltthing123/ai-proj-backend
前端 saltthing123/ai-proj-frontend

标准部署流程

部署到测试环境

cd /path/to/new-ai-proj

# 构建后端 test 镜像
docker buildx build --platform linux/amd64 -f backend/Dockerfile --target production \
  -t saltthing123/ai-proj-backend:test --push backend/

# 构建前端 test 镜像
docker buildx build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
  --build-arg REACT_APP_API_URL=https://staging.ai.pipexerp.com/api/v1 \
  --build-arg REACT_APP_API_BASE_URL=https://staging.ai.pipexerp.com/api/v1 \
  --build-arg REACT_APP_ENV=staging \
  -t saltthing123/ai-proj-frontend:test --push frontend/

# 部署到测试服务器
ssh singapore "cd /opt/ai-project-staging && sudo docker-compose pull && sudo docker-compose up -d"

部署到生产环境

cd /path/to/new-ai-proj

# 构建后端 latest 镜像
docker buildx build --platform linux/amd64 -f backend/Dockerfile --target production \
  -t saltthing123/ai-proj-backend:latest --push backend/

# 构建前端 latest 镜像
docker buildx build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
  --build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
  --build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
  --build-arg REACT_APP_ENV=production \
  -t saltthing123/ai-proj-frontend:latest --push frontend/

# 部署到生产服务器
ssh tools_ai_proj "cd /opt/ai-project && \
  docker compose -f deploy/tencent-cloud/docker-compose.dockerhub.yml pull && \
  docker compose -f deploy/tencent-cloud/docker-compose.dockerhub.yml up -d"

新加坡服务器 Build备选方案

本地网络慢时,在新加坡服务器构建:

# 后端
ssh singapore "cd ~/projects/new-ai-proj && git pull && \
  docker build --platform linux/amd64 -f backend/Dockerfile --target production \
  -t saltthing123/ai-proj-backend:latest ./backend && \
  docker push saltthing123/ai-proj-backend:latest"

# 前端(生产)
ssh singapore "cd ~/projects/new-ai-proj && \
  docker build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
  --build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
  --build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
  --build-arg REACT_APP_ENV=production \
  -t saltthing123/ai-proj-frontend:latest ./frontend && \
  docker push saltthing123/ai-proj-frontend:latest"

自动部署Webhook

状态: 已启用 (2026-01-16)

git push main → Gitea webhook → Jenkins ai-proj → 生产自动部署

服务管理

# 查看容器状态
ssh tools_ai_proj "docker ps --format 'table {{.Names}}\t{{.Status}}'"

# 查看日志
ssh tools_ai_proj "docker logs -f ai_backend_prod --tail 100"

# 重启服务
ssh tools_ai_proj "docker restart ai_backend_prod"

# 健康检查
curl -s https://ai.pipexerp.com/api/v1/health | jq .

测试环境管理

# 查看状态
ssh singapore "sudo docker-compose -f /opt/ai-project-staging/docker-compose.yml ps"

# 查看日志
ssh singapore "sudo docker logs -f ai_backend_staging --tail 100"

# 健康检查
ssh singapore "curl -s -H 'Host: staging.ai.pipexerp.com' http://127.0.0.1/api/v1/health"

Docker Volumes 配置

重要: 数据卷必须标记为 external: true

volumes:
  postgres_prod_data:
    external: true
    name: ai-project_postgres_prod_data
  redis_prod_data:
    external: true
    name: ai-project_redis_prod_data

数据库操作

# 运行迁移
ssh tools_ai_proj "cd /opt/ai-project/backend/migrations && \
  for file in \$(ls *.sql | grep -v _down.sql | sort); do \
    docker exec -i ai_postgres_prod psql -U ai_prod_user -d ai_project_prod < \"\$file\"; \
  done"

# 备份
ssh tools_ai_proj "docker exec ai_postgres_prod pg_dump -U ai_prod_user ai_project_prod > /tmp/backup.sql"

用户管理

重要: 密码哈希必须使用 bcrypt cost 12,这是后端 utils/password.go 中的 DefaultCost 值。

创建用户完整流程

由于 bcrypt 哈希包含 $ 字符会被 shell 解释,必须使用文件传输方式:

# 1. 生成密码哈希(在有 Go 环境的机器上执行)
cd /path/to/new-ai-proj/backend
cat > /tmp/genhash.go << 'EOF'
package main
import ("fmt"; "golang.org/x/crypto/bcrypt")
func main() {
	hash, _ := bcrypt.GenerateFromPassword([]byte("用户密码"), 12)
	fmt.Println(string(hash))
}
EOF
HASH=$(go run /tmp/genhash.go)
echo "Generated hash: $HASH"

# 2. 创建 SQL 文件
cat > /tmp/create_user.sql << EOF
INSERT INTO users (username, email, password_hash, user_type, role, status, created_at, updated_at)
VALUES ('newuser', 'newuser@example.com', '$HASH', 'system', 'admin', 'active', NOW(), NOW());
EOF

# 3. 传输并执行
scp /tmp/create_user.sql tools_ai_proj:/tmp/
ssh tools_ai_proj "docker cp /tmp/create_user.sql ai_postgres_prod:/tmp/ && \
  docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/create_user.sql"

# 4. 验证
curl -s -X POST "https://ai.pipexerp.com/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"newuser","password":"用户密码"}' | jq '.success'

用户角色

user_type role 权限
system admin 系统管理员
system user 系统用户
tenant admin 租户管理员
tenant user 租户用户

重置密码

# 生成新哈希并更新
cd /path/to/new-ai-proj/backend
HASH=$(go run -e 'package main; import ("fmt";"golang.org/x/crypto/bcrypt"); func main() { h,_:=bcrypt.GenerateFromPassword([]byte("新密码"),12); fmt.Println(string(h)) }' 2>/dev/null || cat > /tmp/h.go << 'E'
package main
import ("fmt";"golang.org/x/crypto/bcrypt")
func main() { h,_:=bcrypt.GenerateFromPassword([]byte("新密码"),12); fmt.Println(string(h)) }
E
go run /tmp/h.go)

cat > /tmp/reset.sql << EOF
UPDATE users SET password_hash = '$HASH' WHERE username = 'targetuser';
EOF

scp /tmp/reset.sql tools_ai_proj:/tmp/
ssh tools_ai_proj "docker cp /tmp/reset.sql ai_postgres_prod:/tmp/ && \
  docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/reset.sql"

常见错误

问题 原因 解决
登录失败 bcrypt cost 不是 12 用 Go 重新生成 cost 12 的哈希
哈希被截断 shell 解释了 $ 符号 使用文件传输方式

已创建的系统用户

用户名 邮箱 user_type role 创建时间
qiudl qiudl@zhiyuncai.com system admin -
jiaxiang jiaxiang@joylodging.com system admin 2026-01
haiqing haiqing@joylodging.com system admin 2026-02

注意:密码信息不在文档中记录,如需重置请使用上述重置密码流程

前端构建注意事项

必须同时设置两个 URL 变量:

  • REACT_APP_API_URL
  • REACT_APP_API_BASE_URL

否则会使用 .env.production 中的生产 URL。

验证镜像中的 URL

docker exec <container> sh -c 'grep -oE "https://[a-zA-Z0-9.-]*pipexerp[a-zA-Z0-9./-]*" /usr/share/nginx/html/static/js/main*.js | sort | uniq -c'