第 14 章 - 故障排除
第 14 章 - 故障排除
本章汇总 Git 服务器运维中的常见问题及其诊断与解决方案。
14.1 SSH 连接问题
14.1.1 连接被拒绝
症状:
$ git clone git@server:repo.git
# ssh: connect to host server port 22: Connection refused
诊断步骤:
# 1. 检查 SSH 服务是否运行
sudo systemctl status sshd
# 2. 检查端口监听
sudo ss -tlnp | grep :22
sudo netstat -tlnp | grep :22
# 3. 检查防火墙
sudo ufw status
sudo iptables -L -n | grep 22
# 4. 测试 SSH 连接(详细模式)
ssh -vvv git@server
# 5. 检查 SSH 配置
sudo cat /etc/ssh/sshd_config | grep -E "^(Port|ListenAddress|AllowUsers|DenyUsers)"
解决方案:
# 启动 SSH 服务
sudo systemctl start sshd
sudo systemctl enable sshd
# 开放防火墙端口
sudo ufw allow 22/tcp
# 或自定义端口
sudo ufw allow 2222/tcp
# 检查并修复 sshd_config
sudo vim /etc/ssh/sshd_config
sudo systemctl restart sshd
14.1.2 认证失败
症状:
$ git clone git@server:repo.git
# git@server: Permission denied (publickey).
诊断步骤:
# 1. 检查客户端密钥
ls -la ~/.ssh/
cat ~/.ssh/id_ed25519.pub
# 2. 检查 SSH Agent
ssh-add -l
# 如果没有密钥,添加
ssh-add ~/.ssh/id_ed25519
# 3. 检查服务器端 authorized_keys
sudo cat /home/git/.ssh/authorized_keys
# 确认公钥存在且格式正确
# 4. 检查文件权限
ls -la /home/git/.ssh/
# authorized_keys 应该是 600
# .ssh 目录应该是 700
# git 用户的 home 目录应该是 755
# 5. 测试 SSH 认证
ssh -Tvvv git@server 2>&1 | grep -i "auth\|publickey\|offer"
解决方案:
# 修复文件权限
sudo chmod 700 /home/git/.ssh
sudo chmod 600 /home/git/.ssh/authorized_keys
sudo chown -R git:git /home/git/.ssh
# 确认 authorized_keys 格式(单行)
# 正确格式:
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... comment
# 如果使用 git-shell
sudo usermod -s /usr/bin/git-shell git
# 检查 SELinux(如果启用)
getenforce
sudo restorecon -Rv /home/git/.ssh
14.1.3 SSH 密钥不匹配
症状:
$ ssh -T git@server
# debug1: Offering public key: /home/user/.ssh/id_rsa
# debug1: Authentications that can continue: publickey
# debug1: No more authentication methods to try.
诊断:
# 查看服务器端接受的密钥
sudo cat /home/git/.ssh/authorized_keys | awk '{print $1, $3}'
# 查看客户端使用的密钥
ssh -vvv git@server 2>&1 | grep "Offering\|accepted"
# 确认公钥匹配
# 客户端
ssh-keygen -lf ~/.ssh/id_ed25519.pub
# 输出: 256 SHA256:xxxxx comment
# 在 authorized_keys 中应该有匹配的公钥
sudo grep "SHA256:xxxxx" /home/git/.ssh/authorized_keys
14.1.4 SSH 连接超时
症状:
$ git clone git@server:repo.git
# ssh: connect to host server port 22: Connection timed out
诊断:
# 网络连通性测试
ping server
traceroute server
nc -zv server 22
# 检查 DNS 解析
nslookup server
dig server
# 检查防火墙规则
sudo iptables -L -n -v
sudo ufw status verbose
解决方案:
# 调整 SSH 超时配置(客户端)
# ~/.ssh/config
Host server
ServerAliveInterval 60
ServerAliveCountMax 3
ConnectTimeout 30
# 服务端 KeepAlive
# /etc/ssh/sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3
14.2 HTTP/HTTPS 访问问题
14.2.1 SSL 证书错误
症状:
$ git clone https://git.example.com/repo.git
# fatal: unable to access '...': SSL certificate problem: unable to get local issuer certificate
解决方案:
# 临时忽略 SSL 验证(不推荐生产使用)
git -c http.sslVerify=false clone https://git.example.com/repo.git
# 全局关闭 SSL 验证(不推荐)
git config --global http.sslVerify false
# 正确方案:安装正确的 CA 证书
sudo apt install ca-certificates
sudo update-ca-certificates
# 或者将自签名证书添加到信任列表
sudo cp ca-cert.pem /usr/local/share/ca-certificates/
sudo update-ca-certificates
# Git 使用特定 CA 文件
git config --global http.sslCAInfo /path/to/ca-cert.pem
14.2.2 403 Forbidden
症状:
$ git push origin main
# remote: Permission to org/repo.git denied to user.
# fatal: unable to access '...': The requested URL returned error: 403
诊断:
# 检查 Git 凭据
git config --list | grep credential
# 清除旧凭据
git credential reject << EOF
protocol=https
host=git.example.com
EOF
# 检查 Token 权限
curl -s -H "Authorization: token YOUR_TOKEN" \
https://git.example.com/api/v1/user | jq '.login'
# 检查仓库权限
curl -s -H "Authorization: token YOUR_TOKEN" \
https://git.example.com/api/v1/repos/org/repo | jq '.permissions'
14.2.3 Nginx 502 Bad Gateway
症状:访问 Git Web 界面显示 502 错误。
诊断:
# 检查 Gitea 是否运行
docker compose ps
sudo systemctl status gitea
# 检查 Gitea 日志
docker logs gitea --tail 100
sudo journalctl -u gitea -f
# 检查 Nginx 错误日志
sudo tail -f /var/log/nginx/error.log
# 检查端口
curl -v http://localhost:3000
解决方案:
# 确认 Gitea 正在监听正确端口
docker exec gitea netstat -tlnp 2>/dev/null || \
docker exec gitea ss -tlnp
# 确认 Nginx upstream 配置正确
# /etc/nginx/sites-available/git.example.com
# proxy_pass http://127.0.0.1:3000; # 确保端口匹配
# 重启服务
docker compose restart gitea
sudo systemctl restart nginx
14.3 权限问题
14.3.1 推送被拒绝
症状:
$ git push origin main
# remote: error: GH006: Protected branch update failed.
# remote: error: Required status check "ci/build" is expected.
诊断:
# 检查分支保护规则(Gitea API)
curl -s -H "Authorization: token $TOKEN" \
"$GITEA_URL/api/v1/repos/owner/repo/branches/main/protection" | jq
# 检查用户权限
curl -s -H "Authorization: token $TOKEN" \
"$GITEA_URL/api/v1/repos/owner/repo" | jq '.permissions'
解决方案:
# 方式一:等待 CI 通过后合并
# 方式二:调整分支保护规则(需要管理员权限)
curl -s -X DELETE -H "Authorization: token $ADMIN_TOKEN" \
"$GITEA_URL/api/v1/repos/owner/repo/branches/main/protection"
# 方式三:使用正确的合并流程
# 1. 创建 feature 分支
# 2. 提交 PR
# 3. 等待 CI 和 Review 通过
# 4. 由有权限的用户合并
14.3.2 文件权限问题
症状:
$ git push
# fatal: Unable to create '/opt/git/repo.git/./objects/pack/tmp_pack_XXXX': Permission denied
解决方案:
# 检查仓库目录权限
ls -la /opt/git/
ls -la /opt/git/repo.git/
# 修复权限
sudo chown -R git:git /opt/git/repo.git/
sudo chmod -R 775 /opt/git/repo.git/
# 如果使用 SGID
sudo find /opt/git/repo.git -type d -exec chmod g+s {} \;
# 确认 git 用户的 umask
sudo -u git umask
# 应该是 0002 或 0022
14.3.3 Gitolite 权限问题
症状:
$ git push origin main
# FATAL: R any repo alice DENIED by VREF/limit-push-size
诊断:
# 检查 Gitolite 配置
sudo -u git cat /home/git/.gitolite/conf/gitolite.conf
# 检查用户权限
sudo -u git /home/git/bin/gitolite info -u alice
# 检查日志
sudo cat /home/git/.gitolite/logs/gitolite-*.log | tail -50
14.4 性能问题
14.4.1 推送/拉取缓慢
诊断:
# 测量传输速度
time git clone git@server:large-repo.git
# 检查仓库大小
du -sh /opt/git/large-repo.git
# 检查大文件
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sed -n 's/^blob //p' | sort -rnk2 | head -20
# 检查网络带宽
iperf3 -c server -t 10
解决方案:
# 1. 清理仓库
cd /opt/git/large-repo.git
git gc --aggressive --prune=now
# 2. 使用 Git LFS 管理大文件
git lfs migrate import --include="*.zip,*.tar.gz,*.psd" --everything
# 3. 启用 Git 协议 v2
git config --global protocol.version 2
# 4. 使用浅克隆
git clone --depth 1 git@server:repo.git
# 5. 配置 Git 压缩
git config --global core.compression 6
git config --global pack.windowMemory 256m
14.4.2 GitLab 内存不足
症状:GitLab 服务不稳定或无法启动。
诊断:
# 检查内存使用
free -h
ps aux --sort=-%mem | head -20
# GitLab 组件内存
ps aux | grep -E "(puma|sidekiq|gitaly|postgres)" | awk '{print $4, $11}'
解决方案:
# /etc/gitlab/gitlab.rb
# 减少 Puma worker
puma['worker_processes'] = 2
# 减少 Sidekiq 并发
sidekiq['max_concurrency'] = 10
# 禁用不需要的服务
prometheus_monitoring['enable'] = false
alertmanager['enable'] = false
grafana['enable'] = false
# PostgreSQL 优化
postgresql['shared_buffers'] = "256MB"
postgresql['work_mem'] = "8MB"
# Redis 优化
redis['maxmemory'] = "128mb"
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart
14.4.3 数据库性能
# PostgreSQL 慢查询
sudo -u postgres psql -d gitea -c "
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;"
# 索引优化
sudo -u postgres psql -d gitea -c "
SELECT schemaname, tablename, indexname
FROM pg_indexes
WHERE schemaname = 'public'
ORDER BY tablename;"
# VACUUM
sudo -u postgres psql -d gitea -c "VACUUM ANALYZE;"
14.5 Docker 相关问题
14.5.1 容器无法启动
诊断:
# 查看容器日志
docker logs gitea --tail 100
# 检查容器状态
docker ps -a
# 检查资源限制
docker stats
# 检查磁盘空间
df -h
docker system df
# 检查 Docker 日志
sudo journalctl -u docker -f
常见原因和解决:
# 1. 端口被占用
sudo lsof -i :3000
# 停止占用端口的进程或修改端口映射
# 2. 磁盘空间不足
docker system prune -a --volumes # 谨慎使用
sudo apt autoremove
# 3. 权限问题
# 确保 Docker 卷目录权限正确
ls -la /var/lib/docker/volumes/
# 4. 网络问题
docker network ls
docker network inspect gitea-net
14.5.2 Docker 磁盘空间回收
# 查看 Docker 磁盘使用
docker system df
# 清理未使用的资源
docker system prune # 清理停止的容器、未使用的网络、悬空镜像
docker system prune -a # 清理所有未使用的镜像
docker volume prune # 清理未使用的卷
# 清理构建缓存
docker builder prune
# 清理特定时间前的镜像
docker image prune -a --filter "until=168h" # 7天前
14.6 Git 操作问题
14.6.1 合并冲突
# 拉取最新代码
git pull origin main
# 如果有冲突,手动解决
# 编辑冲突文件,删除 <<<<<<< ======= >>>>>>> 标记
git add .
git commit -m "Resolve merge conflict"
# 或者使用 rebase
git pull --rebase origin main
# 解决冲突后
git rebase --continue
14.6.2 误操作恢复
# 撤销最后一次提交(保留修改)
git reset --soft HEAD~1
# 撤销最后一次提交(丢弃修改)
git reset --hard HEAD~1
# 恢复误删的分支
git reflog # 查找分支的最后提交
git checkout -b recovered-branch <commit-hash>
# 恢复误删的文件
git checkout HEAD -- path/to/file
# 恢复到某个提交
git revert <commit-hash> # 创建新的反向提交(安全)
git reset --hard <commit-hash> # 直接重置(危险,会影响历史)
14.6.3 大仓库克隆超时
# 浅克隆
git clone --depth 1 --single-branch --branch main git@server:repo.git
# 分步获取历史
git fetch --depth 100
git fetch --depth 1000
git fetch --unshallow # 获取完整历史
# 使用 Git 部分克隆
git clone --filter=blob:none git@server:repo.git # 延迟下载 blob
git clone --filter=blob:limit=1m git@server:repo.git # 只下载小 blob
14.7 服务监控与告警
14.7.1 简单监控脚本
#!/bin/bash
# monitor-git.sh
GITEA_URL="https://git.example.com"
WEBHOOK_URL="https://hooks.example.com/alert"
check() {
local name="$1"
local url="$2"
local expected="${3:-200}"
code=$(curl -sf -o /dev/null -w "%{http_code}" --connect-timeout 5 "$url" 2>/dev/null || echo "000")
if [ "$code" != "$expected" ]; then
echo "❌ $name: HTTP $code"
curl -sf -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\":\"❌ Git 服务告警: $name 返回 HTTP $code\"}" > /dev/null &
return 1
else
echo "✅ $name: HTTP $code"
return 0
fi
}
echo "=== Git 服务监控 $(date) ==="
check "Gitea API" "${GITEA_URL}/api/v1/version"
check "Gitea Web" "${GITEA_URL}/"
# 检查 SSH
if ssh -o ConnectTimeout=5 -T git@localhost 2>&1 | grep -q "successfully"; then
echo "✅ SSH: OK"
else
echo "❌ SSH: Failed"
fi
# 检查磁盘
disk_usage=$(df /opt/git | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$disk_usage" -gt 85 ]; then
echo "⚠️ 磁盘使用率: ${disk_usage}%"
fi
# 检查内存
mem_available=$(free -m | awk '/^Mem:/ {print $7}')
if [ "$mem_available" -lt 512 ]; then
echo "⚠️ 可用内存: ${mem_available}MB"
fi
14.7.2 Cron 监控
# 每 5 分钟检查一次
*/5 * * * * /opt/scripts/monitor-git.sh >> /var/log/git-monitor.log 2>&1
14.8 扩展阅读
本章小结
| 学到了什么 | 关键要点 |
|---|---|
| SSH 问题 | 密钥认证、文件权限、防火墙是三大常见原因 |
| HTTP 问题 | SSL 证书、Nginx 配置、端口映射需逐一检查 |
| 权限问题 | 分支保护、文件权限、用户角色需对照排查 |
| 性能问题 | 大仓库用 LFS、GitLab 调内存、数据库优化 |
| Docker 问题 | 日志先行、磁盘空间、端口冲突是最常见原因 |
下一章:第 15 章 - 最佳实践 — 运维规范、备份策略、安全加固和团队协作。