1. 环境准备与规划
1.1 系统要求
- 操作系统: Ubuntu 20.04 LTS 或 CentOS 8
- 内存: 至少 2GB RAM
- 存储: 至少 20GB 可用空间
- 网络: 固定的 IP 地址或域名
1.2 架构规划
以下是 Gitea 与自动化部署的完整架构流程图:
graph TD
A[开发者] -->|Git Push| B[Gitea 服务器]
B -->|触发 Webhook| C[Webhook 接收器]
C -->|执行部署脚本| D[应用服务器]
D -->|拉取代码| B
D -->|构建应用| E[生产环境]
F[用户] -->|访问应用| E
style A fill:#4CAF50,stroke:#388E3C,stroke-width:2px,color:white
style B fill:#2196F3,stroke:#1976D2,stroke-width:2px,color:white
style C fill:#FF9800,stroke:#F57C00,stroke-width:2px,color:white
style D fill:#9C27B0,stroke:#7B1FA2,stroke-width:2px,color:white
style E fill:#F44336,stroke:#D32F2F,stroke-width:2px,color:white
style F fill:#607D8B,stroke:#455A64,stroke-width:2px,color:white
2. Gitea 服务器安装与配置
2.1 系统环境准备
创建安装脚本文件:setup_gitea.sh
#!/bin/bash
# 设置颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}开始安装 Gitea 服务器...${NC}"
# 检查系统类型
if [ -f /etc/redhat-release ]; then
OS="centos"
elif [ -f /etc/lsb-release ]; then
OS="ubuntu"
else
echo -e "${RED}不支持的操作系统${NC}"
exit 1
fi
# 更新系统包
echo -e "${YELLOW}更新系统包...${NC}"
if [ "$OS" = "centos" ]; then
yum update -y
yum install -y wget curl git vim
else
apt-get update
apt-get upgrade -y
apt-get install -y wget curl git vim
fi
# 创建 Gitea 用户
echo -e "${YELLOW}创建 Gitea 用户...${NC}"
if ! id "gitea" &>/dev/null; then
useradd --system --shell /bin/bash --create-home --home-dir /home/gitea --comment 'Git Version Control' gitea
echo -e "${GREEN}Gitea 用户创建成功${NC}"
else
echo -e "${YELLOW}Gitea 用户已存在${NC}"
fi
# 创建必要的目录
echo -e "${YELLOW}创建目录结构...${NC}"
mkdir -p /var/lib/gitea/{custom,data,log}
mkdir -p /etc/gitea
chown -R gitea:gitea /var/lib/gitea
chmod -R 750 /var/lib/gitea
chown -R root:gitea /etc/gitea
chmod 770 /etc/gitea
echo -e "${GREEN}系统环境准备完成${NC}"
2.2 安装 MySQL 数据库
创建数据库安装脚本:setup_mysql.sh
#!/bin/bash
# 设置颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${YELLOW}安装 MySQL 数据库...${NC}"
if [ -f /etc/redhat-release ]; then
# CentOS 安装 MySQL
yum install -y mysql-server mysql-client
systemctl start mysqld
systemctl enable mysqld
# 获取初始密码
MYSQL_TEMP_PWD=$(grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}')
echo -e "${YELLOW}MySQL 初始密码: $MYSQL_TEMP_PWD${NC}"
elif [ -f /etc/lsb-release ]; then
# Ubuntu 安装 MySQL
apt-get install -y mysql-server mysql-client
systemctl start mysql
systemctl enable mysql
fi
# 创建 Gitea 数据库
echo -e "${YELLOW}配置 Gitea 数据库...${NC}"
mysql -u root -p <<EOF
CREATE DATABASE IF NOT EXISTS gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'gitea'@'localhost' IDENTIFIED BY 'GiteaPassword123!';
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost';
FLUSH PRIVILEGES;
EXIT;
EOF
echo -e "${GREEN}MySQL 数据库安装完成${NC}"
2.3 下载并安装 Gitea
创建 Gitea 安装脚本:install_gitea.sh
#!/bin/bash
# 设置颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${YELLOW}下载并安装 Gitea...${NC}"
# 获取最新版本号
GITEA_VERSION=$(curl -s https://api.github.com/repos/go-gitea/gitea/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
echo -e "${YELLOW}当前最新版本: $GITEA_VERSION${NC}"
# 下载 Gitea
cd /tmp
wget -O gitea https://dl.gitea.io/gitea/$GITEA_VERSION/gitea-$GITEA_VERSION-linux-amd64
chmod +x gitea
# 安装到系统路径
cp gitea /usr/local/bin/gitea
# 验证安装
/usr/local/bin/gitea --version
# 创建系统服务文件
echo -e "${YELLOW}创建系统服务...${NC}"
cat > /etc/systemd/system/gitea.service <<EOF
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
After=mysql.service
[Service]
RestartSec=2s
Type=simple
User=gitea
Group=gitea
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=gitea HOME=/home/gitea GITEA_WORK_DIR=/var/lib/gitea
[Install]
WantedBy=multi-user.target
EOF
# 重新加载 systemd
systemctl daemon-reload
systemctl enable gitea
echo -e "${GREEN}Gitea 安装完成${NC}"
2.4 配置 Gitea
创建 Gitea 配置文件:/etc/gitea/app.ini
APP_NAME = 我的 Gitea 服务器
RUN_USER = gitea
RUN_MODE = prod
[server]
APP_DATA_PATH = /var/lib/gitea/data
HTTP_PORT = 3000
ROOT_URL = http://your-domain.com:3000/
DISABLE_SSH = false
SSH_PORT = 22
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
LFS_CONTENT_PATH = /var/lib/gitea/data/lfs
DOMAIN = localhost
SSH_DOMAIN = localhost
OFFLINE_MODE = false
[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gitea
USER = gitea
PASSWD = GiteaPassword123!
SCHEMA =
SSL_MODE = disable
CHARSET = utf8mb4
PATH = /var/lib/gitea/data/gitea.db
[repository]
ROOT = /var/lib/gitea/data/gitea-repositories
[session]
PROVIDER = file
PROVIDER_CONFIG = /var/lib/gitea/data/sessions
[picture]
AVATAR_UPLOAD_PATH = /var/lib/gitea/data/avatars
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = false
[attachment]
PATH = /var/lib/gitea/data/attachments
[log]
ROOT_PATH = /var/lib/gitea/log
MODE = file
LEVEL = Info
[security]
INSTALL_LOCK = true
SECRET_KEY = your-secret-key-here
INTERNAL_TOKEN = your-internal-token-here
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.example.org
2.5 启动 Gitea 服务
执行启动命令:
# 设置配置文件权限
chown gitea:gitea /etc/gitea/app.ini
chmod 660 /etc/gitea/app.ini
# 启动 Gitea 服务
systemctl start gitea
systemctl status gitea
# 检查服务是否正常运行
netstat -tlnp | grep 3000
3. Gitea 初始配置
3.1 通过 Web 界面完成安装
- 打开浏览器访问
http://your-server-ip:3000 - 按照安装向导完成配置:
- 数据库类型选择 MySQL
- 填写数据库连接信息
- 设置管理员账户
- 配置服务器域名和端口
3.2 创建第一个仓库
通过 Web 界面创建:
- 登录 Gitea
- 点击右上角 "+" 号
- 选择 "新建仓库"
- 填写仓库名称和描述
- 选择仓库可见性
- 点击 "创建仓库"
4. Webhook 自动化部署配置
4.1 部署服务器准备
创建部署服务器设置脚本:setup_deploy_server.sh
#!/bin/bash
# 设置颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${YELLOW}设置部署服务器...${NC}"
# 创建部署用户
if ! id "deploy" &>/dev/null; then
useradd -m -s /bin/bash deploy
echo -e "${GREEN}部署用户创建成功${NC}"
# 设置部署用户密码
echo "deploy:DeployPassword123!" | chpasswd
else
echo -e "${YELLOW}部署用户已存在${NC}"
fi
# 安装必要的软件
if [ -f /etc/redhat-release ]; then
yum install -y nginx git nodejs npm python3 python3-pip
elif [ -f /etc/lsb-release ]; then
apt-get install -y nginx git nodejs npm python3 python3-pip
fi
# 创建部署目录
mkdir -p /home/deploy/apps
mkdir -p /home/deploy/scripts
mkdir -p /home/deploy/logs
chown -R deploy:deploy /home/deploy
# 生成 SSH 密钥对
echo -e "${YELLOW}生成 SSH 密钥...${NC}"
sudo -u deploy ssh-keygen -t rsa -b 4096 -f /home/deploy/.ssh/id_rsa -N ""
echo -e "${GREEN}部署服务器设置完成${NC}"
echo -e "${YELLOW}请将以下公钥添加到 Gitea 的部署密钥中:${NC}"
cat /home/deploy/.ssh/id_rsa.pub
4.2 创建 Webhook 接收器
创建 Flask Webhook 接收器:webhook_receiver.py
#!/usr/bin/env python3
"""
Gitea Webhook 接收器
用于接收 Gitea 的 Webhook 请求并触发自动化部署
"""
from flask import Flask, request, jsonify
import json
import hmac
import hashlib
import subprocess
import logging
import os
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/home/deploy/logs/webhook.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
app = Flask(__name__)
# Webhook 密钥(需要与 Gitea 中设置的密钥一致)
WEBHOOK_SECRET = 'YourWebhookSecretKey123!'
class WebhookProcessor:
def __init__(self):
self.deploy_scripts = {
'frontend': '/home/deploy/scripts/deploy_frontend.sh',
'backend': '/home/deploy/scripts/deploy_backend.sh',
'api': '/home/deploy/scripts/deploy_api.sh'
}
def verify_signature(self, payload, signature):
"""验证 Webhook 签名"""
expected_signature = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)
def parse_payload(self, payload):
"""解析 Webhook 负载"""
try:
data = json.loads(payload)
event_type = request.headers.get('X-Gitea-Event')
repository = data.get('repository', {})
return {
'event': event_type,
'repo_name': repository.get('name'),
'repo_url': repository.get('clone_url'),
'branch': data.get('ref', '').split('/')[-1],
'commit_id': data.get('after'),
'committer': data.get('committer', {}).get('name', ''),
'commit_message': data.get('head_commit', {}).get('message', '')
}
except Exception as e:
logger.error(f"解析负载失败: {e}")
return None
def determine_deploy_script(self, repo_name, branch):
"""根据仓库名和分支确定部署脚本"""
# 这里可以根据实际项目结构进行定制
if 'frontend' in repo_name.lower():
return self.deploy_scripts['frontend']
elif 'api' in repo_name.lower() or 'backend' in repo_name.lower():
return self.deploy_scripts['backend']
else:
return self.deploy_scripts.get(repo_name)
def execute_deploy_script(self, script_path, repo_info):
"""执行部署脚本"""
if not script_path or not os.path.exists(script_path):
logger.error(f"部署脚本不存在: {script_path}")
return False
try:
# 设置环境变量
env = os.environ.copy()
env.update({
'REPO_NAME': repo_info['repo_name'],
'REPO_URL': repo_info['repo_url'],
'BRANCH': repo_info['branch'],
'COMMIT_ID': repo_info['commit_id'],
'COMMITTER': repo_info['committer']
})
# 执行部署脚本
result = subprocess.run(
['bash', script_path],
env=env,
capture_output=True,
text=True,
timeout=300 # 5分钟超时
)
if result.returncode == 0:
logger.info(f"部署成功: {repo_info['repo_name']} - {repo_info['branch']}")
logger.info(f"部署输出: {result.stdout}")
return True
else:
logger.error(f"部署失败: {result.stderr}")
return False
except subprocess.TimeoutExpired:
logger.error("部署脚本执行超时")
return False
except Exception as e:
logger.error(f"执行部署脚本时发生错误: {e}")
return False
# 初始化处理器
processor = WebhookProcessor()
@app.route('/webhook', methods=['POST'])
def handle_webhook():
"""处理 Webhook 请求"""
try:
# 获取请求数据
payload = request.get_data()
signature = request.headers.get('X-Gitea-Signature', '').replace('sha256=', '')
# 验证签名
if not processor.verify_signature(payload, signature):
logger.warning("Webhook 签名验证失败")
return jsonify({'error': 'Invalid signature'}), 401
# 解析负载
repo_info = processor.parse_payload(payload)
if not repo_info:
return jsonify({'error': 'Invalid payload'}), 400
logger.info(f"接收到 Webhook 事件: {repo_info['event']}")
logger.info(f"仓库: {repo_info['repo_name']}, 分支: {repo_info['branch']}")
# 只处理 push 事件到特定分支
if repo_info['event'] == 'push' and repo_info['branch'] in ['main', 'master', 'develop']:
# 确定部署脚本
deploy_script = processor.determine_deploy_script(
repo_info['repo_name'],
repo_info['branch']
)
# 执行部署
success = processor.execute_deploy_script(deploy_script, repo_info)
if success:
return jsonify({'status': 'success', 'message': 'Deployment triggered'})
else:
return jsonify({'status': 'error', 'message': 'Deployment failed'}), 500
else:
logger.info(f"忽略事件: {repo_info['event']} 分支: {repo_info['branch']}")
return jsonify({'status': 'ignored', 'message': 'Event ignored'})
except Exception as e:
logger.error(f"处理 Webhook 时发生错误: {e}")
return jsonify({'error': 'Internal server error'}), 500
@app.route('/health', methods=['GET'])
def health_check():
"""健康检查端点"""
return jsonify({'status': 'healthy', 'timestamp': datetime.now().isoformat()})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)
4.3 创建部署脚本
创建前端项目部署脚本:/home/deploy/scripts/deploy_frontend.sh
#!/bin/bash
# 设置颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
}
warning() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}
# 环境变量
REPO_NAME=${REPO_NAME:-"unknown"}
REPO_URL=${REPO_URL:-""}
BRANCH=${BRANCH:-"main"}
COMMIT_ID=${COMMIT_ID:-""}
DEPLOY_USER="deploy"
APP_NAME="$REPO_NAME"
DEPLOY_DIR="/home/deploy/apps/$APP_NAME"
BACKUP_DIR="/home/deploy/backups/$APP_NAME"
LOG_FILE="/home/deploy/logs/${APP_NAME}_deploy.log"
NGINX_CONF="/etc/nginx/sites-available/$APP_NAME"
NGINX_ENABLED="/etc/nginx/sites-enabled/$APP_NAME"
# 创建目录
mkdir -p $DEPLOY_DIR $BACKUP_DIR $(dirname $LOG_FILE)
# 记录开始时间
START_TIME=$(date +%s)
log "开始部署项目: $APP_NAME"
log "仓库: $REPO_URL"
log "分支: $BRANCH"
log "提交ID: $COMMIT_ID"
# 检查必要的环境变量
if [ -z "$REPO_URL" ]; then
error "REPO_URL 环境变量未设置"
exit 1
fi
# 备份当前版本(如果存在)
backup_current_version() {
if [ -d "$DEPLOY_DIR" ] && [ "$(ls -A $DEPLOY_DIR)" ]; then
log "备份当前版本..."
BACKUP_FILE="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).tar.gz"
tar -czf "$BACKUP_FILE" -C "$DEPLOY_DIR" . >> $LOG_FILE 2>&1
if [ $? -eq 0 ]; then
log "备份成功: $BACKUP_FILE"
else
error "备份失败"
exit 1
fi
fi
}
# 克隆或更新代码
update_code() {
if [ ! -d "$DEPLOY_DIR/.git" ]; then
log "首次克隆代码库..."
git clone --branch $BRANCH $REPO_URL $DEPLOY_DIR >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
error "克隆代码库失败"
exit 1
fi
else
log "更新代码库..."
cd $DEPLOY_DIR
git fetch origin >> $LOG_FILE 2>&1
git checkout $BRANCH >> $LOG_FILE 2>&1
git reset --hard origin/$BRANCH >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
error "更新代码库失败"
exit 1
fi
fi
# 切换到特定提交(如果指定)
if [ ! -z "$COMMIT_ID" ]; then
log "切换到提交: $COMMIT_ID"
cd $DEPLOY_DIR
git reset --hard $COMMIT_ID >> $LOG_FILE 2>&1
fi
}
# 安装依赖
install_dependencies() {
log "安装项目依赖..."
cd $DEPLOY_DIR
if [ -f "package.json" ]; then
log "检测到 Node.js 项目,安装 npm 依赖..."
npm install >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
error "npm 依赖安装失败"
exit 1
fi
fi
if [ -f "requirements.txt" ]; then
log "检测到 Python 项目,安装 pip 依赖..."
pip3 install -r requirements.txt >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
error "pip 依赖安装失败"
exit 1
fi
fi
}
# 构建项目
build_project() {
log "构建项目..."
cd $DEPLOY_DIR
# Node.js 项目构建
if [ -f "package.json" ]; then
if grep -q "\"build\"" package.json; then
log "执行 npm build..."
npm run build >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
error "项目构建失败"
exit 1
fi
fi
fi
}
# 配置 Nginx
setup_nginx() {
log "配置 Nginx..."
# 创建 Nginx 配置文件
cat > $NGINX_CONF <<EOF
server {
listen 80;
server_name ${APP_NAME}.example.com;
root ${DEPLOY_DIR}/dist;
index index.html index.htm;
# 前端路由支持
location / {
try_files \$uri \$uri/ /index.html;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# API 代理(如果有后端)
location /api/ {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass \$http_upgrade;
}
access_log /var/log/nginx/${APP_NAME}_access.log;
error_log /var/log/nginx/${APP_NAME}_error.log;
}
EOF
# 启用站点
if [ ! -f "$NGINX_ENABLED" ]; then
ln -s $NGINX_CONF $NGINX_ENABLED
fi
# 测试并重新加载 Nginx
nginx -t >> $LOG_FILE 2>&1
if [ $? -eq 0 ]; then
systemctl reload nginx >> $LOG_FILE 2>&1
log "Nginx 配置已重载"
else
error "Nginx 配置测试失败"
exit 1
fi
}
# 设置文件权限
set_permissions() {
log "设置文件权限..."
chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_DIR
chmod -R 755 $DEPLOY_DIR
}
# 主部署流程
main() {
log "=== 开始部署流程 ==="
# 执行部署步骤
backup_current_version
update_code
install_dependencies
build_project
setup_nginx
set_permissions
# 计算部署时间
END_TIME=$(date +%s)
DEPLOY_TIME=$((END_TIME - START_TIME))
log "=== 部署完成 ==="
log "项目: $APP_NAME"
log "分支: $BRANCH"
log "提交: $COMMIT_ID"
log "部署时间: ${DEPLOY_TIME}秒"
log "部署目录: $DEPLOY_DIR"
log "日志文件: $LOG_FILE"
# 写入部署记录
echo "$(date +'%Y-%m-%d %H:%M:%S') - $APP_NAME - $BRANCH - $COMMIT_ID - 成功 - ${DEPLOY_TIME}秒" >> /home/deploy/logs/deploy_history.log
}
# 执行主函数
main "$@"
4.4 配置 Webhook 服务
创建 Webhook 服务配置:/etc/systemd/system/webhook.service
[Unit]
Description=Gitea Webhook Receiver
After=network.target
Wants=network.target
[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/home/deploy
ExecStart=/usr/bin/python3 /home/deploy/webhook_receiver.py
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
启动 Webhook 服务:
# 设置脚本权限
chmod +x /home/deploy/scripts/*.sh
chmod +x /home/deploy/webhook_receiver.py
# 安装 Python 依赖
pip3 install flask
# 启动 Webhook 服务
systemctl daemon-reload
systemctl enable webhook
systemctl start webhook
systemctl status webhook
5. Gitea Webhook 配置
5.1 在 Gitea 中配置 Webhook
- 登录 Gitea 并进入你的仓库
- 点击 设置 → Webhook → 添加 Webhook
- 选择 Gitea 类型
- 填写配置信息:
目标 URL: http://your-deploy-server:5000/webhook
密钥: YourWebhookSecretKey123!
触发事件: 选择 Push 事件
分支过滤: main,master,develop
5.2 测试 Webhook
创建测试脚本:test_webhook.sh
#!/bin/bash
# Webhook 测试脚本
GITEA_URL="http://your-gitea-server:3000"
WEBHOOK_URL="http://your-deploy-server:5000/webhook"
SECRET="YourWebhookSecretKey123!"
# 模拟 Webhook 负载
PAYLOAD='{
"ref": "refs/heads/main",
"before": "d4c7a6b2f9c7e8b1a0d5e8f7a6b5c4d3e2f1a0b9",
"after": "a1b2c3d4e5f6789012345678901234567890abcd",
"repository": {
"name": "test-frontend",
"clone_url": "http://your-gitea-server:3000/username/test-frontend.git"
},
"committer": {
"name": "Test User"
},
"head_commit": {
"message": "Test commit message"
}
}'
# 生成签名
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')
# 发送测试请求
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Gitea-Event: push" \
-H "X-Gitea-Signature: sha256=$SIGNATURE" \
-d "$PAYLOAD" \
"$WEBHOOK_URL"
echo -e "\nWebhook 测试完成"
6. 完整部署流程验证
6.1 部署流程验证
以下是完整的自动化部署流程验证步骤:
sequenceDiagram
participant D as 开发者
participant G as Gitea服务器
participant W as Webhook接收器
participant S as 部署服务器
participant N as Nginx
participant U as 最终用户
Note over D,S: 初始设置阶段
D->>G: 推送代码到仓库
G->>W: 发送Webhook通知
W->>S: 触发部署脚本
S->>G: 拉取最新代码
S->>S: 安装依赖和构建
S->>N: 更新Nginx配置
N->>N: 重载服务配置
S->>W: 返回部署结果
W->>G: 更新部署状态
U->>N: 访问应用
N->>U: 返回应用内容
Note over D,U: 自动化部署完成
6.2 监控和日志查看
创建监控脚本:monitor_deployments.sh
#!/bin/bash
# 部署监控脚本
echo "=== 部署服务状态 ==="
systemctl status webhook --no-pager -l
echo ""
echo "=== 最近部署记录 ==="
tail -20 /home/deploy/logs/deploy_history.log
echo ""
echo "=== Webhook 访问日志 ==="
tail -10 /home/deploy/logs/webhook.log
echo ""
echo "=== Nginx 错误日志 ==="
tail -10 /var/log/nginx/error.log
echo ""
echo "=== 磁盘使用情况 ==="
df -h /home/deploy
echo ""
echo "=== 内存使用情况 ==="
free -h
7. 高级配置和优化
7.1 数据库优化
创建数据库优化脚本:optimize_mysql.sh
#!/bin/bash
# MySQL 优化配置
# 备份原配置
cp /etc/mysql/my.cnf /etc/mysql/my.cnf.backup.$(date +%Y%m%d)
# 优化配置
cat >> /etc/mysql/my.cnf <<EOF
# Gitea 优化配置
[mysqld]
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
max_connections = 100
query_cache_size = 32M
query_cache_type = 1
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
[gitea]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
EOF
# 重启 MySQL
systemctl restart mysql
echo "MySQL 优化配置完成"
7.2 SSL 证书配置
创建 SSL 配置脚本:setup_ssl.sh
#!/bin/bash
# SSL 证书配置脚本
DOMAIN="your-domain.com"
EMAIL="admin@your-domain.com"
# 安装 Certbot
if [ -f /etc/redhat-release ]; then
yum install -y certbot python3-certbot-nginx
elif [ -f /etc/lsb-release ]; then
apt-get install -y certbot python3-certbot-nginx
fi
# 获取 SSL 证书
certbot --nginx -d $DOMAIN -d www.$DOMAIN --non-interactive --agree-tos -m $EMAIL
# 设置自动续期
echo "0 12 * * * root /usr/bin/certbot renew --quiet" >> /etc/crontab
echo "SSL 证书配置完成"
8. 故障排除和维护
8.1 常见问题解决
创建故障排除脚本:troubleshoot.sh
#!/bin/bash
# Gitea 和部署系统故障排除
echo "=== 系统检查 ==="
echo "1. 检查服务状态..."
systemctl is-active gitea
systemctl is-active webhook
systemctl is-active nginx
systemctl is-active mysql
echo -e "\n2. 检查端口监听..."
netstat -tlnp | grep -E ':(3000|5000|80|3306)'
echo -e "\n3. 检查磁盘空间..."
df -h
echo -e "\n4. 检查内存使用..."
free -h
echo -e "\n5. 检查最近错误..."
journalctl -u gitea --since "1 hour ago" | grep -i error
journalctl -u webhook --since "1 hour ago" | grep -i error
echo -e "\n6. 检查 Webhook 日志..."
tail -20 /home/deploy/logs/webhook.log
echo -e "\n7. 检查部署日志..."
tail -20 /home/deploy/logs/deploy_history.log
8.2 备份和恢复
创建备份脚本:backup_gitea.sh
#!/bin/bash
# Gitea 数据备份脚本
BACKUP_DIR="/home/deploy/backups/gitea"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="gitea_backup_$DATE.tar.gz"
# 创建备份目录
mkdir -p $BACKUP_DIR
echo "开始备份 Gitea..."
# 停止 Gitea 服务
systemctl stop gitea
# 备份数据
tar -czf $BACKUP_DIR/$BACKUP_FILE \
/var/lib/gitea \
/etc/gitea \
/home/gitea
# 备份数据库
mysqldump -u root -p gitea > $BACKUP_DIR/gitea_db_$DATE.sql
# 启动 Gitea 服务
systemctl start gitea
echo "备份完成: $BACKUP_DIR/$BACKUP_FILE"
echo "数据库备份: $BACKUP_DIR/gitea_db_$DATE.sql"
# 清理旧备份(保留最近7天)
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
find $BACKUP_DIR -name "*.sql" -mtime +7 -delete
总结
通过本教程,已经成功搭建了一个完整的 Gitea Git 服务器,并配置了完整的自动化部署系统。这个系统具有以下特点:
- 完整的 Git 服务: 使用 Gitea 提供企业级的 Git 仓库管理
- 自动化部署: 通过 Webhook 实现代码推送后的自动部署
- 灵活的部署脚本: 支持多种项目类型的自动化部署
- 安全可靠: 包含签名验证、错误处理和回滚机制
- 易于维护: 提供完整的监控、备份和故障排除工具
这个解决方案可以满足中小型团队的代码管理和自动化部署需求,提供了生产环境级别的稳定性和可靠性。