Files

767 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/pullDocker 内网 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
```
### 步骤 4DNS 解析
阿里云域名控制台添加:
| 记录类型 | 主机记录 | 记录值 |
|---------|---------|--------|
| 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" "========== 部署完成 =========="
```
**ALiYunManagernginx 配置部署)** `/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-nginxgit.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。