# Git 私有仓库 + 自动部署流水线 (AI可读) > 基于阿里云服务器 `8.136.137.59`,部署 Gitea 私有 Git 仓库 + Webhook 自动部署流水线。 > 遵循现有架构:beian-nginx → main-nginx → 服务容器。 > **所有 Git 相关文件统一放在 `/home/Git/`,能容器化的全部容器化。** --- ## 一、架构总览 ``` 外网 git.dxz99wyr.cn │ ▼ beian-nginx (:80/:443) │ 新增: git.dxz99wyr.cn → 172.19.0.1:8080 ▼ main-nginx (:8080) │ 新增: git.dxz99wyr.cn → gitea:3000 ▼ ┌─────────────────────────────────────────────┐ │ gitea (Docker) │ │ 镜像: gitea/gitea:latest │ │ 内部端口: 3000 (Web UI) │ │ 内部端口: 22 (SSH Git) → 宿主机映射 2222 │ │ 数据卷: /home/Git/gitea/data → /data │ │ 网络: aliyun-app-network │ └──────────┬──────────────────────────────────┘ │ Webhook POST (push 事件) │ URL: http://webhook:9000/hooks/xxx ▼ ┌─────────────────────────────────────────────┐ │ webhook (Docker / 自定义镜像) │ │ 内部端口: 9000 │ │ 内置: git + docker CLI + webhook 二进制 │ │ 收到 push → 执行对应脚本 │ │ 网络: aliyun-app-network │ │ 挂载: docker.sock(操控宿主机 Docker) │ │ /home/Git/webhook/ → 配置只读 │ │ /opt/ALiYunManager/ → 更新代码+重载 │ │ /opt/services/ → 更新各服务代码 │ │ /home/Git/logs/ → 部署日志 │ └──────────┬──────────────────────────────────┘ │ git clone/pull(Docker 内网 HTTP) │ http://${GITEA_TOKEN}@gitea:3000/... │ docker-compose up -d(通过 docker.sock) ▼ ┌──────┴──────┬──────────┐ │ │ │ resume-web resume-api 其他服务... (自动拉代码、构建、重启) ``` ### 端口规划 | 端口 | 用途 | 对外网 | 说明 | |------|------|--------|------| | `2222` | Git SSH 克隆/推送(开发者用) | 开放 | gitea 容器 22 → 宿主机 2222 | | `3000` | Gitea Web UI(容器内部) | 不开放 | 仅 Docker 网络内,通过 nginx 代理 | | `9000` | Webhook 接收器(容器内部) | 不开放 | 仅 Docker 网络内,gitea 调用 | > 2222 端口需要在阿里云安全组和服务器防火墙中放行。 ### 宿主机文件总览(仅 `/home/Git/` 目录) ``` /home/Git/ ├── gitea/ │ ├── docker-compose.yml # Gitea 容器定义 │ └── data/ # Gitea 全部数据(SQLite + 仓库 + 配置) ├── webhook/ │ ├── Dockerfile # 自定义镜像(git + docker CLI + webhook) │ ├── docker-compose.yml # Webhook 容器定义 │ ├── hooks.json # Webhook 路由规则 │ ├── .env # GITEA_TOKEN 等敏感变量 │ └── scripts/ # 各服务部署脚本 │ ├── deploy-common.sh │ ├── deploy-resume-web.sh │ ├── deploy-resume-api.sh │ ├── deploy-aliyun-manager.sh │ └── deploy-miniapp-web.sh └── logs/ └── deploy.log # 部署历史日志 ``` > 除此之外无需在宿主机创建其他文件。SSH 密钥、Git 配置等均在 Docker 容器内部处理。 --- ## 二、部署步骤 ### 步骤 1:服务器环境准备 ```bash ssh -i "D:\003_Project\小程序连接.pem" root@8.136.137.59 # 创建目录结构(一次性) mkdir -p /home/Git/gitea/data mkdir -p /home/Git/webhook/scripts mkdir -p /home/Git/logs # 放行 Git SSH 端口 ufw allow 2222/tcp # 阿里云安全组也需要添加 2222 入方向规则 ``` ### 步骤 2:部署 Gitea 容器 创建 `/home/Git/gitea/docker-compose.yml`: ```yaml version: "3.8" services: gitea: image: gitea/gitea:latest container_name: gitea restart: always environment: - USER_UID=1000 - USER_GID=1000 - GITEA__server__DOMAIN=git.dxz99wyr.cn - GITEA__server__SSH_DOMAIN=8.136.137.59 - GITEA__server__SSH_PORT=2222 - GITEA__server__ROOT_URL=https://git.dxz99wyr.cn - GITEA__server__HTTP_PORT=3000 - GITEA__server__DISABLE_SSH=false - GITEA__database__DB_TYPE=sqlite3 - GITEA__repository__ENABLE_PUSH_CREATE_USER=true - GITEA__repository__ENABLE_PUSH_CREATE_ORG=true - GITEA__service__DISABLE_REGISTRATION=true ports: - "2222:22" volumes: - /home/Git/gitea/data:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro networks: - gitea-network networks: gitea-network: driver: bridge name: aliyun-app-network ``` ```bash cd /home/Git/gitea docker-compose up -d # 验证 docker-compose ps docker-compose logs -f ``` ### 步骤 3:配置 Nginx 反向代理 #### 3a. main-nginx 配置 — 已存在,确认即可 文件 `nginx/conf.d/git.conf`(已在项目中创建): ```nginx server { listen 80; server_name git.dxz99wyr.cn; access_log /var/log/nginx/git.access.log main; error_log /var/log/nginx/git.error.log warn; location / { proxy_pass http://gitea:3000; proxy_http_version 1.1; 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_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; proxy_send_timeout 300s; client_max_body_size 512m; } } ``` #### 3b. 重载 main-nginx ```bash cd /opt/ALiYunManager docker-compose exec nginx nginx -t && docker-compose exec nginx nginx -s reload ``` #### 3c. beian-nginx 追加中转 ```bash # 备份 cp /opt/beian-docker/nginx.conf /opt/beian-docker/nginx.conf.bak.$(date +%Y%m%d_%H%M) # 编辑配置,追加以下 server 块 vim /opt/beian-docker/nginx.conf ``` 在 `http {}` 内追加: ```nginx # Gitea 私有 Git 仓库 server { listen 80; server_name git.dxz99wyr.cn; location / { proxy_pass http://172.19.0.1:8080; proxy_http_version 1.1; 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_read_timeout 300s; proxy_send_timeout 300s; client_max_body_size 512m; } } ``` ```bash docker exec beian-nginx nginx -t && docker exec beian-nginx nginx -s reload ``` ### 步骤 4:DNS 解析 阿里云域名控制台添加: | 记录类型 | 主机记录 | 记录值 | |---------|---------|--------| | A | git | 8.136.137.59 | ### 步骤 5:初始化 Gitea 1. 浏览器访问 `http://git.dxz99wyr.cn` 2. 首次访问进入安装页(大部分配置已由 docker-compose.yml 环境变量预设) 3. 设置管理员账号: - 用户名:`admin` - 密码:**设置强密码并牢记** - 邮箱:`admin@dxz99wyr.cn` 4. 点击「安装 Gitea」 ### 步骤 6:创建 Gitea 访问令牌(供 Webhook 脚本拉取代码用) 1. Gitea Web UI → 右上角头像 → **Settings** → **Applications** 2. **Generate New Token**: - Token Name:`deploy-token` - 权限:勾选 `read:repository` 3. 复制生成的 Token(只显示一次),保存备用 ### 步骤 7:创建仓库 在 Gitea Web UI 中创建: | 仓库名 | 用途 | |--------|------| | `aliyun-manager` | ALiYunManager 部署项目 | | `resume-web` | 个人简历前端 | | `resume-api` | 个人简历后台 | | `miniapp-web` | 小程序前端 | | `miniapp-api` | 小程序后台 | --- ## 三、Webhook 自动部署流水线 ``` git push → Gitea → Webhook POST → webhook:9000/hooks/xxx → 对应脚本 → clone/pull → docker-compose 重建 ``` ### 步骤 8:构建 Webhook 自定义镜像 创建 `/home/Git/webhook/Dockerfile`: ```dockerfile # ============================================ # Webhook 接收器自定义镜像 # 内置: docker CLI + git + bash + webhook 二进制 # ============================================ FROM docker:cli RUN apk add --no-cache git bash curl ARG WEBHOOK_VERSION=2.8.1 ADD https://github.com/adnanh/webhook/releases/download/${WEBHOOK_VERSION}/webhook-linux-amd64.tar.gz /tmp/ RUN tar -xzf /tmp/webhook-linux-amd64.tar.gz -C /usr/local/bin/ webhook && \ chmod +x /usr/local/bin/webhook && \ rm /tmp/webhook-linux-amd64.tar.gz WORKDIR /opt/webhook ENTRYPOINT ["/usr/local/bin/webhook"] ``` ### 步骤 9:创建 Webhook 配置文件 #### 9a. 环境变量 `/home/Git/webhook/.env` ```bash # Gitea 访问令牌(步骤 6 中生成的) GITEA_TOKEN=粘贴你的token到这里 # 各个 Webhook Secret(随机生成,与 Gitea Webhook 设置保持一致) SECRET_RESUME_WEB=resume-web-deploy-secret SECRET_RESUME_API=resume-api-deploy-secret SECRET_ALIYUN_MANAGER=aliyun-manager-deploy-secret SECRET_MINIAPP_WEB=miniapp-web-deploy-secret ``` #### 9b. Webhook 路由 `/home/Git/webhook/hooks.json` ```json [ { "id": "resume-web", "execute-command": "/opt/webhook/scripts/deploy-resume-web.sh", "command-working-directory": "/opt/webhook/scripts", "trigger-rule": { "match": { "type": "value", "value": "resume-web-deploy-secret", "parameter": { "source": "payload", "name": "secret" } } } }, { "id": "resume-api", "execute-command": "/opt/webhook/scripts/deploy-resume-api.sh", "command-working-directory": "/opt/webhook/scripts", "trigger-rule": { "match": { "type": "value", "value": "resume-api-deploy-secret", "parameter": { "source": "payload", "name": "secret" } } } }, { "id": "aliyun-manager", "execute-command": "/opt/webhook/scripts/deploy-aliyun-manager.sh", "command-working-directory": "/opt/webhook/scripts", "trigger-rule": { "match": { "type": "value", "value": "aliyun-manager-deploy-secret", "parameter": { "source": "payload", "name": "secret" } } } }, { "id": "miniapp-web", "execute-command": "/opt/webhook/scripts/deploy-miniapp-web.sh", "command-working-directory": "/opt/webhook/scripts", "trigger-rule": { "match": { "type": "value", "value": "miniapp-web-deploy-secret", "parameter": { "source": "payload", "name": "secret" } } } } ] ``` #### 9c. docker-compose `/home/Git/webhook/docker-compose.yml` ```yaml version: "3.8" services: webhook: build: . image: webhook-receiver:latest container_name: webhook restart: always ports: - "9000:9000" env_file: - .env volumes: # Webhook 配置(只读) - /home/Git/webhook/hooks.json:/opt/webhook/hooks.json:ro - /home/Git/webhook/scripts:/opt/webhook/scripts:ro # 部署日志(读写) - /home/Git/logs:/opt/webhook/logs # 宿主机 Docker 控制权 - /var/run/docker.sock:/var/run/docker.sock # 各项目代码目录(用于 git pull 更新) - /opt/ALiYunManager:/opt/ALiYunManager - /opt/services/resume-web:/opt/services/resume-web - /opt/services/resume-api:/opt/services/resume-api - /opt/services/miniapp-web:/opt/services/miniapp-web networks: - webhook-network command: - "-hooks=/opt/webhook/hooks.json" - "-verbose" - "-hot-reload" networks: webhook-network: driver: bridge name: aliyun-app-network ``` > **说明**: > - `-hot-reload`:修改 hooks.json 后无需重启容器 > - 代码目录挂载:webhook 容器直接 git pull 到这些目录,然后通过 docker.sock 执行 docker-compose > - 容器内部通过 HTTP 访问 gitea:`http://gitea:3000`,无需 SSH #### 9d. 通用部署函数 `/home/Git/webhook/scripts/deploy-common.sh` ```bash #!/bin/bash # ============================================ # 通用部署函数库 # 被各服务脚本 source 引用 # 运行在 webhook 容器内 # ============================================ set -e LOG_DIR="/opt/webhook/logs" TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S") log() { local SERVICE=$1 local MESSAGE=$2 echo "[$TIMESTAMP] [$SERVICE] $MESSAGE" | tee -a "$LOG_DIR/deploy.log" } # 从 Gitea 拉取最新代码(Docker 内网 HTTP) # 参数: REPO_NAME GIT_DIR BRANCH # 使用 GITEA_TOKEN 环境变量认证 clone_or_pull() { local REPO_NAME=$1 local GIT_DIR=$2 local BRANCH=${3:-main} local REPO_URL="http://${GITEA_TOKEN}@gitea:3000/admin/${REPO_NAME}.git" if [ -d "$GIT_DIR/.git" ]; then log "git" "拉取最新代码: ${REPO_NAME} → ${GIT_DIR} (分支: ${BRANCH})" cd "$GIT_DIR" git fetch origin git reset --hard "origin/${BRANCH}" else log "git" "克隆仓库: ${REPO_NAME} → ${GIT_DIR} (分支: ${BRANCH})" git clone -b "$BRANCH" "$REPO_URL" "$GIT_DIR" fi } # 重建并重启 Docker 服务 # 参数: COMPOSE_DIR SERVICE_NAME docker_rebuild() { local COMPOSE_DIR=$1 local SERVICE_NAME=$2 cd "$COMPOSE_DIR" if [ -f "Dockerfile" ]; then log "$SERVICE_NAME" "构建镜像..." docker-compose build "$SERVICE_NAME" fi log "$SERVICE_NAME" "重启容器..." docker-compose up -d --no-deps --force-recreate "$SERVICE_NAME" log "$SERVICE_NAME" "部署完成" } ``` > **关键点**:`clone_or_pull` 使用 `http://${GITEA_TOKEN}@gitea:3000/...` 格式, > Gitea 和 webhook 同属 `aliyun-app-network`,直接用容器名 `gitea:3000` 通信, > 不经过外网,也不需要 SSH。 #### 9e. 各服务部署脚本 **个人简历前端** `/home/Git/webhook/scripts/deploy-resume-web.sh`: ```bash #!/bin/bash source /opt/webhook/scripts/deploy-common.sh SERVICE="resume-web" REPO_NAME="resume-web" GIT_DIR="/opt/services/resume-web" BRANCH="main" log "$SERVICE" "========== 开始部署 ==========" clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" docker_rebuild "$GIT_DIR" "$SERVICE" log "$SERVICE" "========== 部署完成 ==========" ``` **个人简历后台** `/home/Git/webhook/scripts/deploy-resume-api.sh`: ```bash #!/bin/bash source /opt/webhook/scripts/deploy-common.sh SERVICE="resume-api" REPO_NAME="resume-api" GIT_DIR="/opt/services/resume-api" BRANCH="main" log "$SERVICE" "========== 开始部署 ==========" clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" docker_rebuild "$GIT_DIR" "$SERVICE" log "$SERVICE" "========== 部署完成 ==========" ``` **ALiYunManager(nginx 配置部署)** `/home/Git/webhook/scripts/deploy-aliyun-manager.sh`: ```bash #!/bin/bash source /opt/webhook/scripts/deploy-common.sh SERVICE="aliyun-manager" REPO_NAME="aliyun-manager" GIT_DIR="/opt/ALiYunManager" BRANCH="main" log "$SERVICE" "========== 开始部署 ==========" clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" cd "$GIT_DIR" # 重载 main-nginx 配置(不重启容器,零停机) docker-compose exec -T nginx nginx -t && docker-compose exec -T nginx nginx -s reload log "$SERVICE" "main-nginx 配置已重载" log "$SERVICE" "========== 部署完成 ==========" ``` **小程序前端** `/home/Git/webhook/scripts/deploy-miniapp-web.sh`: ```bash #!/bin/bash source /opt/webhook/scripts/deploy-common.sh SERVICE="miniapp-web" REPO_NAME="miniapp-web" GIT_DIR="/opt/services/miniapp-web" BRANCH="main" log "$SERVICE" "========== 开始部署 ==========" clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" docker_rebuild "$GIT_DIR" "$SERVICE" log "$SERVICE" "========== 部署完成 ==========" ``` ### 步骤 10:构建并启动 Webhook 容器 ```bash # 赋予脚本执行权限 chmod +x /home/Git/webhook/scripts/*.sh # 构建自定义镜像并启动 cd /home/Git/webhook docker-compose build docker-compose up -d # 验证 docker-compose ps docker-compose logs -f ``` --- ## 四、Gitea Webhook 配置 对每个仓库,在 Gitea Web UI 中操作: ### 配置步骤 1. 进入仓库 → **Settings** → **Webhooks** 2. 点击 **Add Webhook** → 选择 **Gitea** 3. 填写: | 字段 | 值 | |------|-----| | Target URL | `http://webhook:9000/hooks/resume-web`(对应 hooks.json 中的 id) | | HTTP Method | `POST` | | POST Content Type | `application/json` | | Secret | `resume-web-deploy-secret`(与 hooks.json 和 .env 一致) | | Trigger On | 勾选 **Push** | 4. 点击 **Add Webhook** 5. 点击 **Test Delivery** 验证 ### 各仓库 Webhook 配置汇总 | 仓库 | Target URL | Secret | |------|-----------|--------| | `resume-web` | `http://webhook:9000/hooks/resume-web` | `resume-web-deploy-secret` | | `resume-api` | `http://webhook:9000/hooks/resume-api` | `resume-api-deploy-secret` | | `aliyun-manager` | `http://webhook:9000/hooks/aliyun-manager` | `aliyun-manager-deploy-secret` | | `miniapp-web` | `http://webhook:9000/hooks/miniapp-web` | `miniapp-web-deploy-secret` | > Gitea 和 webhook 同属 `aliyun-app-network`,用容器名 `webhook` 直接通信。 --- ## 五、本地开发环境配置 ### 个人 Git 配置 ```bash git config --global user.name "Your Name" git config --global user.email "your-email@example.com" ``` ### SSH 密钥(用于 git push) ```bash # 生成密钥(如果还没有) ssh-keygen -t ed25519 -C "your-email@example.com" # 将公钥添加到 Gitea cat ~/.ssh/id_ed25519.pub # Gitea Web UI → Settings → SSH/GPG Keys → Add Key 粘贴 ``` ### 关联远程仓库并推送 ```bash # 以 resume-web 为例 cd D:\003_Project\ALiYunManager\services\resume-web git init git add . git commit -m "init" # 添加远程仓库(走 SSH,端口 2222) git remote add origin ssh://git@8.136.137.59:2222/admin/resume-web.git # 推送(此后每次推送自动触发服务器部署) git push -u origin main ``` ### SSH 别名(可选,简化地址) 编辑 `~/.ssh/config`: ``` Host gitea HostName 8.136.137.59 Port 2222 User git IdentityFile ~/.ssh/id_ed25519 ``` 之后: ```bash git clone gitea:admin/resume-web.git ``` ### 日常开发流程 ```bash git add . git commit -m "feat: 更新xxx" git push # ↑ 推送后自动触发 Webhook → 服务器自动拉代码并部署,无需手动 ssh ``` --- ## 六、安全设计 | 措施 | 说明 | |------|------| | 禁用公开注册 | `DISABLE_REGISTRATION=true` | | Webhook 仅内网可达 | 9000 端口无宿主机映射,仅 Docker 网络内 gitea 可调用 | | 独立 Secret | 每个仓库使用不同的 Webhook Secret | | 令牌最小权限 | Gitea Token 仅勾选 `read:repository`,只能拉代码 | | Token 存于 .env | 不硬编码在脚本中,`.env` 文件权限 600 | | docker.sock 隔离 | webhook 是唯一挂载 docker.sock 的辅助容器,不对外暴露端口 | --- ## 七、完整部署清单(执行顺序) | # | 操作 | 位置 | |---|------|------| | 1 | `mkdir -p /home/Git/{gitea/data,webhook/scripts,logs}` | 服务器 | | 2 | 部署 Gitea 容器 | `/home/Git/gitea/docker-compose.yml` | | 3 | 重载 main-nginx(git.conf 已就绪) | `/opt/ALiYunManager/` | | 4 | beian-nginx 追加 git 中转 + 重载 | `/opt/beian-docker/nginx.conf` | | 5 | DNS 添加 `git` A 记录 → `8.136.137.59` | 阿里云控制台 | | 6 | Gitea Web 安装 + 管理员注册 | `http://git.dxz99wyr.cn` | | 7 | 生成 Gitea Access Token (read:repository) | Gitea Settings → Applications | | 8 | 创建各项目仓库 | Gitea Web UI | | 9 | 填写 `/home/Git/webhook/.env`(GITEA_TOKEN + Secrets)| 服务器 | | 10 | 写入 hooks.json + 各部署脚本 | `/home/Git/webhook/` | | 11 | 构建自定义镜像 + 启动 webhook 容器 | `/home/Git/webhook/` | | 12 | 每个仓库配置 Webhook | Gitea Web UI | | 13 | 本地推送测试自动部署 | 开发机 | --- ## 八、故障排查 ### Webhook 不触发 ```bash docker logs webhook -f # Gitea Web UI → Settings → Webhooks → Recent Deliveries 查看投递状态 ``` ### 部署脚本报错 ```bash # 查看部署日志 tail -f /home/Git/logs/deploy.log # 进入容器手动测试 docker exec -it webhook sh cd /opt/webhook/scripts bash deploy-resume-web.sh ``` ### Git clone 认证失败 ```bash # 检查 Token 是否正确 docker exec webhook env | grep GITEA_TOKEN # 测试容器内能否访问 Gitea docker exec webhook curl -s http://gitea:3000/api/v1/version ``` ### Gitea 无法访问 ```bash docker ps | grep gitea docker network inspect aliyun-app-network | grep gitea docker logs gitea -f ``` --- ## 九、ICP 备案提醒 `git.dxz99wyr.cn` 页面底部中间必须显示: `浙ICP备2026030774号-1` 并链接到 `https://beian.miit.gov.cn` 配置方式:Gitea 管理后台 → 自定义 → Footer HTML。