将 GitHub 仓库备份到 Amazon S3(没人提醒你的事)
发布: (2026年1月13日 GMT+8 22:05)
4 分钟阅读
原文: Dev.to
Source: Dev.to
请提供您希望翻译的正文内容,我将把它完整地译成简体中文并保留原有的格式、Markdown 语法以及技术术语。谢谢!
为什么要备份 GitHub 仓库?
GitHub 可能会成为您所关心工作的单点故障。仓库被删除、账户被锁定或强制推送都可能把所有内容抹掉。平台外的自动化备份可以解决此问题。
为什么选择 Amazon S3?
- 与 GitHub 无关
- 费用低廉
- 极其耐用
- 为长期存储而构建
本指南涵盖的内容
- 备份多个 GitHub 仓库
- 每周运行备份
- 保留完整的 Git 历史(分支 + 标签)
- 使用 OIDC + 临时凭证(无需长期 AWS 访问密钥)
- 安全地将备份存储在 Amazon S3
Git bundle 与 ZIP
ZIP 备份
- ❌ 丢失提交历史
- ❌ 丢失分支和标签
- ❌ 恢复时困难
Git bundle(单个可移植文件)
- 包含所有提交、分支和标签
git bundle create repo-backup.bundle --all
如果备份无法恢复历史,那就不是备份。
AWS 权限:常见陷阱
AWS 使用两种策略类型:
| 策略类型 | 用途 | 需要 Principal |
|---|---|---|
| IAM role policy | 身份权限 | ❌ |
| S3 bucket policy | 资源权限 | ✅ |
一个常见错误是把 IAM 角色策略粘贴到 S3 桶策略中,或使用了错误的 Principal ARN。
只有同时满足以下两点,上传才会成功
- IAM 角色策略允许该操作。
- S3 桶策略允许同一角色。
如果任意一方拒绝 → AccessDenied。
GitHub Actions 工作流
name: Weekly S3 Repo Backup
on:
schedule:
- cron: "15 3 * * 0" # Weekly
workflow_dispatch: {}
permissions:
id-token: write
contents: read
jobs:
backup:
runs-on: ubuntu-latest
steps:
- name: Checkout full history
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create git bundle
run: |
set -e
REPO_NAME="${GITHUB_REPOSITORY#*/}"
TS="$(date -u +%Y-%m-%dT%H-%M-%SZ)"
mkdir -p backups
git bundle create "backups/${REPO_NAME}-${TS}.bundle" --all
sha256sum "backups/${REPO_NAME}-${TS}.bundle" > "backups/${REPO_NAME}-${TS}.sha256"
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume:
aws-region:
- name: Upload to S3
run: |
aws s3 cp backups/ \
s3:///github-backups/${GITHUB_REPOSITORY}/ \
--recursive
最小 Terraform 配置
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = [
"sts.amazonaws.com"
]
thumbprint_list = [
"6938fd4d98bab03faadb97b34396831e3780aea1"
]
}
resource "aws_iam_role" "github_backup" {
name = "github-actions-s3-backup"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
Federated = aws_iam_openid_connect_provider.github.arn
}
Condition = {
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:*/*:*"
}
}
}]
})
}
resource "aws_iam_role_policy" "s3_backup" {
role = aws_iam_role.github_backup.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["s3:ListBucket"]
Resource = "arn:aws:s3:::example-backup-bucket"
},
{
Effect = "Allow"
Action = [
"s3:PutObject",
"s3:AbortMultipartUpload"
]
Resource = "arn:aws:s3:::example-backup-bucket/*"
}
]
})
}
恢复备份
git clone repo-backup.bundle restored-repo
cd restored-repo
git push --all origin
git push --tags origin
无需 GitHub API。
最佳实践清单
- 在编写策略之前,先绘制信任关系图。
- 不要盲目相信 AWS 错误信息。
- 切勿将根账户用作存储桶主体。
- 在扩展之前先使用单个仓库进行测试。
- 保持备份方式简单且可靠。
一个好的备份系统是你可以忘记它,直到需要它的那一天——它就应该自动工作。