Azure DevOps 提供 99.9% 的 SLA 服务等级保证,表示一年之中必须要有 99.9% 的时间正常营运,如果 Azure DevOps 在特定月份遗漏 SLA,则会将每月费用的一部分退款。
换言之,无法提供服务的时间为 8 小时 45 分 36 秒。
(60秒 * 60分 * 24小时 * 365天 ) * 0.1% = 31536秒 = 8 小时 45 分 36 秒
为了防止意外删除资料,Microsoft 也会针对 Azure Blob 和 Azure SQL 资料库进行时间点备份。Azure DevOps 会利用这项功能维护您的资料 28 天,这些备份也会在配对区域中複写,以协助从区域中断复原。
Azure DevOps 可以在删除后最多 28 天复原已删除的组织或专案。
这些备份仅适用于商务持续性,并协助从中断或灾害案例中复原。不包括客户意外删除资产(例如储存库、工作专案、附件或成品)不支援还原客户意外删除的资产虽然 Azure DevOps 有 99.9 的 SLA,但它仍然有趴下的可能性。
又或是哪天某位同事突然中邪把 Repository 给删了
在组织评估其资讯系统与资产所面临的潜在风险时,就必须将这一点纳入考量,尤其是资讯单位同时又担任 RD 的角色时,程式码版本管控伺服器的备援就相当重要。
在资讯安全风险评鉴的过程,我们就会列举资讯系统可能遇到的风险情境与影响範围,根据损害的等级与发生的可能性来估算风险值。
若超出可承受之风险值,组织就必须有所作为。
例如新增风险处理措施来备份 Azure DevOps Git 储存库,并评估残余风险值是否在可接受之範围。
如何备份 Azure DevOps Git 储存库
以下我们将了解如何使用 YAML 档案备份储存库。
包括以下步骤:
建立 Azure DevOps 个人存取权杖 (PAT)建立 YAML 文件建立订阅连接建立 Azure DevOps 个人存取权杖 (PAT)
登入您的 Azure DevOps 门户,前往个人存取权杖。
点选 New Token 建立令牌
输入 Token 的名字,例如 Repo Backup Token。
选择您的 Organization
範围选择 Custom defined,只给予该 Token 对 Code 有读取权限
到期日可以选择 Custom defined,最久可以设定一年。
注意:複製并保存 Token,因为您将无法再次看到它。
建立 YAML 文件
前往 Pipelines,建立 Pipeline。
选择 Azure Repos Git
选择您要备份的 Repository。
选择 Starter pipeline
以下是您将看到的预设代码
将 yaml 更新为以下程式码
trigger: branches: include: - '*'stages: - stage: _default jobs: - job: Job pool: vmImage: windows-latest steps: - task: CmdLine@2 inputs: script: git clone --mirror https://{pat-token}@dev.azure.com/{organization}/{project}/_git/{repo} - task: ArchiveFiles@2 inputs: rootFolderOrFile: $(System.DefaultWorkingDirectory) includeRootFolder: true archiveType: zip archiveFile : $(Build.ArtifactStagingDirectory)/Backup.zip replaceExistingArchive: true - task: AzureFileCopy@3 displayName: AzureBlob File Copy inputs: SourcePath: $(Build.ArtifactStagingDirectory)/Backup.zip azureSubscription: '{subscription-connection}' Destination: 'AzureBlob' storage: '{storage-name}' ContainerName : '{container-name}' BlobPrefix : '{blob-name}'
Trigger:通配符 * 将监视所有分支,储存库中有任何变更时都会触发管道。
CmdLine:呼叫 git clone –mirror 来建立储存库的副本,取得储存库时需要使用个人存取权杖 (PAT)。
存档档案:将取得上一个步骤中複製的 git 储存库,压缩为 Backup.zip。
档案複製:它将取得存档副本并将其传送至 Azure Blob 存储
建立订阅连接
前往专案设定
前往 Service Connections
建立 Service Connection
选择 Azure Resource Manager
认证方式选择 Service Principal (automatic)
选择您拥有储存帐户的资源群组
输入订阅连接的名字,例如 repobackup。
储存后完成
回到 YAML 文件
我们需要填写以下参数
{pat-token}:使用上面取得的 PAT 个人存取权杖{organization}:您的组织名称{project}:储存库所在的专案名称,例如 UPInstrument。{repo}:要备份的储存库,例如 Wpf_ASTM。{subscription-connection}:替换为 Azure Service Connection Name,例如 repobackup。{storage-name}:存放备份的储存体帐号名称{container-name}:存放备份的容器名称{blob-name}:设定 BlobPrefix,选用的。确认完成后,点选 Save and Run。
第一次执行会遇到权限请求,点选 View。
允许存取
没有意外的话,通常会执行成功。
Pipeline 也会发信通知您
前往储存体帐号进行验证,资料果然产生了。
建议设定 BlobPrefix,会多一层资料夹方便我们区分备份档案。
点进去就可以看到储存库的备份了
我们也可以使用变数把日期加入档名
trigger: branches: include: - '*'variables: backup_date: $[format('{0:yyyy}-{0:MM}-{0:dd}T{0:HH}-{0:mm}-{0:ss}', pipeline.startTime)]stages: - stage: _default jobs: - job: Job pool: vmImage: windows-latest steps: - task: CmdLine@2 inputs: script: git clone --mirror https://{pat-token}@dev.azure.com/{organization}/{project}/_git/{repo} - task: ArchiveFiles@2 inputs: rootFolderOrFile: $(System.DefaultWorkingDirectory) includeRootFolder: true archiveType: zip archiveFile : $(Build.ArtifactStagingDirectory)/$(backup_date)_Backup.zip replaceExistingArchive: true - task: AzureFileCopy@3 displayName: AzureBlob File Copy inputs: SourcePath: $(Build.ArtifactStagingDirectory)/$(backup_date)_Backup.zip azureSubscription: '{subscription-connection}' Destination: 'AzureBlob' storage: '{storage-name}' ContainerName : '{container-name}' BlobPrefix : '{blob-name}'
每次产出的备份档案就不会被覆写了
定期删除备份
我们可以到 Stroage Account 的 Lifecycle Management,新增规则。
输入规则名称
若 Blob 超过 30 天没有修改,则进行删除。
当然您也可以设定先搬至冷储存在进行删除,来节省储存体的费用。
还原备份档案
接下来我们要透过 Backup.zip 去还原 Azure DevOps 的 Repository,很多人备份都不做还原测试,等出事之后才发现备份档根本无效,我们事情不要做半套阿。
If you don’t like your job, you don’t strike! You just go in every day and do it really half-assed. That’s the American way.
如果你不喜欢你的工作,你不主动出击,你就每天一样去上班,然后把事情乱做或做一半,这就是美国人的做法。
下载备份档案
接其解压缩
使用命令提示字元切换到该路径底下
就可以透过下列指令进行还原到原本的 Repository
git push --force --mirror https://dev.azure.com/{your_organization}/{your_project}/_git/{your_repo}
发生错误,缺少 ForcePush 权限。
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0To https://dev.azure.com/{your_organization}/UPInstrument/_git/Wpf_ASTM * [new reference] origin/main -> origin/main ! [remote rejected] main (TF401027: You need the Git 'ForcePush' permission to perform this action. Details: identity '61d9f138-8c41-45f6-8c24-e69e4dc9b580\ivan_cheng@domain', scope 'branch'.)error: failed to push some refs to 'https://dev.azure.com/{your_organization}/UPInstrument/_git/Wpf_ASTM'
前往专案设定,调整自己所属角色的权限允许 ForcePush。
再试一次就成功了
Enumerating objects: 12, done.Counting objects: 100% (12/12), done.Delta compression using up to 8 threadsCompressing objects: 100% (12/12), done.Writing objects: 100% (12/12), 9.00 KiB | 4.50 MiB/s, done.Total 12 (delta 1), reused 0 (delta 0), pack-reused 0remote: Analyzing objects... (12/12) (7 ms)remote: Validating commits... (2/2) done (0 ms)remote: Storing packfile... done (50 ms)remote: Storing index... done (66 ms)To https://dev.azure.com/{your_organization}/UPInstrument/_git/Wpf_ASTM - [deleted] origin/dd11a2ae47a38e348d72515e83759e37436c97a1 - [deleted] origin/main * [new branch] ivan -> ivan * [new branch] main -> main * [new branch] master -> master
也可以还原到新的 Repository,建立一个新的叫 Wpf_ASTM_Restore
Enumerating objects: 38, done.Counting objects: 100% (38/38), done.Delta compression using up to 8 threadsCompressing objects: 100% (37/37), done.Writing objects: 100% (38/38), 12.73 KiB | 2.54 MiB/s, done.Total 38 (delta 9), reused 0 (delta 0), pack-reused 0remote: Analyzing objects... (38/38) (7 ms)remote: Validating commits... (12/12) done (0 ms)remote: Storing packfile... done (49 ms)remote: Storing index... done (50 ms)To https://dev.azure.com/{your_organization}/UPInstrument/_git/Wpf_ASTM_Restore + 80e8be0...dd11a2a main -> main (forced update) * [new branch] ivan -> ivan * [new branch] master -> master
回到 Repository 检查,程式码都顺利回来啰。
还原到 GitHub 也是没问题
git push --force --mirror https://github.com/jieshiun/Wpf_ASTM.git
Enumerating objects: 38, done.Counting objects: 100% (38/38), done.Delta compression using up to 8 threadsCompressing objects: 100% (37/37), done.Writing objects: 100% (38/38), 12.57 KiB | 559.00 KiB/s, done.Total 38 (delta 9), reused 0 (delta 0), pack-reused 0remote: Resolving deltas: 100% (9/9), done.To https://github.com/jieshiun/Wpf_ASTM.git * [new branch] ivan -> ivan * [new branch] main -> main * [new branch] master -> master
今天的分享就到这边,谢谢大家。
后续更新
如何在 Azure DevOps 备份多个储存库
参考文件
https://learn.microsoft.com/zh-tw/azure/devops/organizations/security/data-protection?view=azure-devopshttps://www.cloudfronts.com/azure/azure-devops-services/backup-azure-devops-git-repositoriehttps://learn.microsoft.com/zh-tw/azure/devops/pipelines/tasks/reference/azure-file-copy-v3?view=azure-pipelineshttps://charbelnemnom.com/how-to-backup-azure-devops-git-repositories