sqlite-web 0.7.2
gitea.db
action_run_job
Create
Query
access
access_token
action
action_artifact
action_run
action_run_index
action_run_job
action_runner
action_runner_token
action_schedule
action_schedule_spec
action_task
action_task_output
action_task_step
action_tasks_version
action_variable
app_state
attachment
auth_token
badge
branch
collaboration
comment
commit_status
commit_status_index
commit_status_summary
commit_sync_log
commit_sync_status
dbfs_data
dbfs_meta
deploy_key
email_address
email_hash
external_login_user
follow
gpg_key
gpg_key_import
hook_task
issue
issue_assignees
issue_content_history
issue_dependency
issue_index
issue_label
issue_pin
issue_user
issue_watch
label
language_stat
lfs_lock
lfs_meta_object
login_source
milestone
mirror
notice
notification
oauth2_application
oauth2_authorization_code
oauth2_grant
org_user
package
package_blob
package_blob_upload
package_cleanup_rule
package_file
package_property
package_version
project
project_board
project_issue
protected_branch
protected_tag
public_key
pull_auto_merge
pull_request
push_mirror
reaction
release
renamed_branch
repo_archiver
repo_hidden_file
repo_indexer_status
repo_license
repo_redirect
repo_topic
repo_transfer
repo_unit
repository
review
review_state
secret
session
sqlite_sequence
star
stopwatch
system_setting
task
team
team_invite
team_repo
team_unit
team_user
topic
tracked_time
two_factor
upload
user
user_badge
user_blocking
user_open_id
user_redirect
user_setting
version
watch
webauthn_credential
webhook
Toggle helper tables
Structure
Content
Query
Insert
Drop
Import
Export
Delete row 7902 from action_run_job
id
7902
run_id
6713
repo_id
6
owner_id
5
commit_sha
b7eb415d7a9689f1efec941bcb2dcd7d098e9c28
is_fork_pull_request
0
name
部署到 Production
attempt
1
workflow_payload
name: Deploy "on": push: branc
name: Deploy "on": push: branches: [main] tags: ['v*'] workflow_dispatch: inputs: environment: description: '部署环境' required: true default: 'staging' type: choice options: - staging - production - rollback skip_tests: description: '跳过测试(紧急修复时使用)' required: false default: false type: boolean env: IMAGE_PREFIX: ${{ github.repository_owner }}/juhi NODE_VERSION: "20" PNPM_VERSION: "8" REGISTRY: ghcr.io jobs: deploy-production: name: 部署到 Production runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.environment == 'production' steps: - name: 检出代码 uses: actions/checkout@v4 - name: 配置 SSH uses: webfactory/ssh-agent@v0.8.0 with: ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }} - name: 配置 SSH Known Hosts run: | mkdir -p ~/.ssh echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts chmod 644 ~/.ssh/known_hosts - name: 同步部署文件 run: | rsync -avz --delete \ docker-compose.prod.yml \ scripts/ \ deploy/ \ $USER@$HOST:$DEPLOY_PATH/ env: HOST: ${{ secrets.PRODUCTION_HOST }} USER: ${{ secrets.PRODUCTION_USER }} DEPLOY_PATH: /opt/juhi - name: 部署前检查 run: | ssh $USER@$HOST << 'EOF' cd /opt/juhi # 运行部署前检查(如果脚本存在) if [ -f "./scripts/pre-deploy-check.sh" ]; then chmod +x ./scripts/pre-deploy-check.sh ./scripts/pre-deploy-check.sh || { echo "部署前检查未通过,终止部署" exit 1 } fi EOF env: HOST: ${{ secrets.PRODUCTION_HOST }} USER: ${{ secrets.PRODUCTION_USER }} - name: 数据库备份 run: | ssh $USER@$HOST << 'EOF' cd /opt/juhi echo "==> 执行部署前数据库备份..." BACKUP_DIR="/opt/juhi/backups" mkdir -p "$BACKUP_DIR" TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/pre_deploy_${TIMESTAMP}.sql" docker compose -f docker-compose.prod.yml exec -T postgres \ pg_dump -U "${DB_USER:-juhi}" -d "${DB_NAME:-juhi_revops}" -Fc > "$BACKUP_FILE" if [ $? -eq 0 ]; then BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1) echo "==> 备份完成: $BACKUP_FILE ($BACKUP_SIZE)" else echo "==> 备份失败,终止部署" exit 1 fi # 清理 30 天前的旧备份 find "$BACKUP_DIR" -name "pre_deploy_*.sql" -mtime +30 -delete 2>/dev/null || true EOF env: HOST: ${{ secrets.PRODUCTION_HOST }} USER: ${{ secrets.PRODUCTION_USER }} - name: 部署到 Production 服务器 run: | ssh $USER@$HOST << EOF cd $DEPLOY_PATH # 更新镜像标签 export API_IMAGE="${API_IMAGE}" export FRONTEND_IMAGE="${FRONTEND_IMAGE}" # 拉取最新镜像 docker compose -f docker-compose.prod.yml pull api frontend # 执行数据库迁移(Prisma) echo "==> 执行数据库迁移..." docker compose -f docker-compose.prod.yml --profile migrate run --rm migrate if [ \$? -ne 0 ]; then echo "数据库迁移失败,终止部署" exit 1 fi # 记录部署历史(回滚用) CURRENT_API=\$(docker inspect --format='{{.Config.Image}}' juhi-api 2>/dev/null || echo "none") CURRENT_FE=\$(docker inspect --format='{{.Config.Image}}' juhi-frontend 2>/dev/null || echo "none") echo "\$(date -Iseconds)|\${CURRENT_API}|\${CURRENT_FE}" >> .deploy-history # 只保留最近 20 条部署历史 tail -20 .deploy-history > .deploy-history.tmp && mv .deploy-history.tmp .deploy-history # 蓝绿部署 - 启动新 API 容器 echo "==> 蓝绿部署:启动新实例..." docker compose -f docker-compose.prod.yml up -d --no-deps --scale api=2 api # 健康检查新实例(带重试) echo "==> 等待新实例就绪..." RETRY=0 MAX_RETRY=15 until curl -sf http://localhost:3000/health > /dev/null 2>&1; do RETRY=\$((RETRY + 1)) if [ \$RETRY -ge \$MAX_RETRY ]; then echo "新实例健康检查超时(75s),回滚到单实例" docker compose -f docker-compose.prod.yml up -d --no-deps --scale api=1 api exit 1 fi echo " 等待就绪... (\${RETRY}/\${MAX_RETRY})" sleep 5 done echo "==> 新实例健康检查通过" # 切换流量 - 缩减到新实例 docker compose -f docker-compose.prod.yml up -d --no-deps --scale api=1 api # 更新前端 docker compose -f docker-compose.prod.yml up -d --no-deps frontend # 重载 Nginx docker compose -f docker-compose.prod.yml exec -T nginx nginx -s reload 2>/dev/null || true # 清理旧镜像 docker image prune -f # 记录部署版本 echo "${VERSION}" > .deployed_version echo "==> 部署完成:版本 ${VERSION}" EOF env: HOST: ${{ secrets.PRODUCTION_HOST }} USER: ${{ secrets.PRODUCTION_USER }} DEPLOY_PATH: /opt/juhi API_IMAGE: ${{ needs.build-and-push.outputs.api-image }} FRONTEND_IMAGE: ${{ needs.build-and-push.outputs.frontend-image }} VERSION: ${{ needs.build-and-push.outputs.version }} - name: 部署验证 run: | ssh $USER@$HOST << 'EOF' cd /opt/juhi echo "==> 执行部署后验证..." # 运行部署后验证(如果脚本存在) if [ -f "./scripts/post-deploy-verify.sh" ]; then chmod +x ./scripts/post-deploy-verify.sh ./scripts/post-deploy-verify.sh --quick || { echo "部署验证未通过" exit 1 } else # 基础验证 # 1. API 健康检查 curl -sf http://localhost:3000/health || { echo "API 健康检查失败"; exit 1; } echo "API 健康检查通过" # 2. Nginx 代理检查 curl -sf http://localhost/health || echo "⚠️ Nginx 代理检查跳过" # 3. 检查容器状态 UNHEALTHY=$(docker compose -f docker-compose.prod.yml ps --format json | grep -c '"unhealthy"' || true) if [ "$UNHEALTHY" -gt 0 ]; then echo "发现不健康的容器:" docker compose -f docker-compose.prod.yml ps exit 1 fi echo "所有容器状态正常" fi EOF env: HOST: ${{ secrets.PRODUCTION_HOST }} USER: ${{ secrets.PRODUCTION_USER }} - if: startsWith(github.ref, 'refs/tags/v') name: 创建 GitHub Release uses: softprops/action-gh-release@v2 with: generate_release_notes: "true" - if: always() name: Slack 通知 uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} text: 'Production 部署 ${{ job.status }} - 版本: ${{ needs.build-and-push.outputs.version }}' webhook_url: ${{ secrets.SLACK_WEBHOOK }} timeout-minutes: "20"
...
job_id
deploy-production
needs
["build-and-push","deploy-staging"
["build-and-push","deploy-staging"]
...
runs_on
["ubuntu-latest"]
task_id
6836
status
4
started
1773833387
stopped
1773833387
created
1773832744
updated
1773833387
raw_concurrency
is_concurrency_evaluated
1
concurrency_group
concurrency_cancel
0
Delete
Cancel