亚马逊AWS官方博客

基于 AWS CodeCommit 可规模化的敏捷开发实践

本文介绍的 AWS CodeCommit 可在 AWS 中国(光环新网运营的北京区域和西云数据运营的宁夏区域)和全球区使用。请查阅文档了解全球区详细的支持区域列表。

GithubGitlab 已经成为众多开发者非常熟悉的代码协作平台,大量企业正在通过它们参与开源项目或实施企业内部项目协作。目前被开发者广为熟知的 Github Pull Request 协作流程是利用 Git 的分布式源代码管理特性,同时很好的满足了开源代码仓库的权限控制以及多人参与代码协作的需求,因此被广泛采用。此外同样还有成熟的也被大型开源项目所采用的 Git 代码仓库多人协作开发方式,例如 Gerrit Code Review 。目前 Android、Eclipse Foundation 下面的各种项目都在使用 Gerrit 作为协作开发工具。Gerrit 通过管理同一个代码仓库中不同角色的用户可提交代码分支的权限来实现代码贡献、代码评审、持续集成以及协作开发等。

AWS 同样提供了托管的、基于 Git 协议、安全且高可用的代码服务 AWS CodeCommit。AWS CodeCommit 主要服务的是企业内部代码协作工作的场景,所以他并没有“喜欢”等社交功能以及代码仓库 fork 功能,是否 AWS CodeCommit 就无法实现 Github Pull Request 这样的协作工作流程呢?

答案是,AWS CodeCommit 完全可以通过基于 IAM 权限管理 以及 Pull Request(拉取请求) 功能来实现企业内部协作开发。AWS CodeCommit 是 AWS 提供的托管服务,天然同 AWS IAM 认证和授权管理做了很好的集成。企业管理员可以通过配置 IAM Policy 为同一个代码仓库中不同用户角色设置不同的权限。采用类似 Gerrit 的权限控制思路来打造基于 AWS CodeCommit 的协作开发流程。本文推荐的基于 AWS CodeCommit 协作流程更加适合企业内部项目协作,只需要管理开发者用户的代码仓库角色,无需让每个开发者额外创建代码仓库副本,减少维护不必要的代码仓库数量。同时 AWS CodeCommit 的拉取请求还可以集成众多的代码检查服务作为审批者来提高代码质量以及减少安全漏洞,例如 SonarQube 静态扫描,AWS re:Invent 2019 推出的基于 AI 算法的 AWS CodeGuru Reviewer

本文推荐的基于 AWS CodeCommit 的敏捷开发协作流程具备以下特性,

  • IAM 权限控制方面
    • 任意代码仓库包含至少两种用户角色,
      • 代码仓库开发协作者,参与项目的开发工作。
      • 代码仓库 拥有者维护者,具备代码审核权限及仓库的部分管理权限。仓库拥有者维护者 同时也是协作者
    • 代码仓库开发协作者拥有者维护者都有代码仓库读取权限,可以使用 git 命令拉取代码到本地。
    • 任意代码仓库协作者可以提交新的代码到有特定含义前缀的分支,例如,features/, bugs/。同时允许多名协作者协作工作在某一特定分支上。协作者可以创建新的拉取请求申请合并代码到主分支,例如 master 或者 mainline
    • 代码仓库拥有者维护者有权限合并拉取请求。
    • 拒绝任何人直接推送代码到仓库主分支,包括仓库拥有者维护者
  • 开发协作流程方面
    • 监听仓库拉取请求的创建和拉取请求源分支更新事件,自动触发该拉取请求对应分支的自动化编译、测试和代码检查任务。在所有的自动化任务通过后,自动为这个拉取请求的 批准 投票+1。反之若任何检查失败,则取消投票。
    • 为代码仓库设置拉取请求批准模板规则,至少需要收到拉取请求自动化编译测试任务和仓库拥有者维护者合计两票 批准 才允许拥有者维护者执行合并代码操作。
    • 监听代码仓库主分支,任意新提交将触发自动化发布。持续的将构件发布到构件仓库或者将服务最新版本在业务系统上做集成部署。

基于以上特性可以完整实现等同 Github、Github Pull Request、Github Action/Travis CI 集成的敏捷协作开发流程。

AWS CodeCommit 作为代码管理,集成同样是无服务器的构建服务 AWS CodeBuild 和持续集成服务 AWS CodePipeline 的协作流程如下图,

同时,以上整套基于 AWS CodeCommit 代码管理的敏捷协作工作流程可以利用 CloudFormation/AWS CDK 实现 AWS 资源编排,将企业研发流程所依赖的基础架构通过代码来管理!这样的好处是,企业内部即使有成百数千甚至更多的代码仓库都可以实现统一管理,新仓库的申请及相关资源的创建也可以通过提交基础架构代码的拉取请求,通过代码验证和被审批合并后,自动从 AWS 创建出符合企业管理规范的安全代码仓库。可以做为企业规模化管理研发资源的一种参考解决方案。

示例应用

我们为以上基于 AWS CodeCommit 的敏捷开发流程创建了一个完整示例,演示了如何快速的创建符合以上敏捷开发流程的 AWS CodeCommit 代码仓库及协作工程流程。接下来将为各位演示如何一步步将这套基于 AWS CodeCommit 的开发流程部署在自己的账户中。

0. 环境准备

1. 准备部署代码

使用任何您习惯的 Git 客户端工具/IDE克隆示例代码并签出 aws-toolkit-jetbrains 分支(这个分支针对后面使用的示例项目 aws-toolkit-jetbrains 做了针对性的构建配置),或者直接下载示例代码并解压到一个空文件夹。

2. 环境初始化

打开您操作系统的终端或命令提示符,进入到示例代码所在的目录,执行下面命令初始化环境以及安装相关依赖软件包,

npm run init

3. 部署示例应用

在成功初始化 AWS CDK 环境后及安装部署程序依赖后,执行下面的命令部署示例应用,

npm run deploy

由于示例应用会创建对应的 IAM 角色/策略,AWS CDK 部署应用前默认会要求用户对 IAM 相关的变更做出确认,您将会看到终端上有如下输出,

输入‘y’确认上面输出的 IAM 变更,AWS CDK 开始部署示例应用。经过数分钟后,看到如下图输出,表示示例应用栈已经成功部署在您的 AWS 账户中。

如上图最后为应用部署的输出,它提示部署中创建了两个 IAM 角色用于演示代码仓库的中的拥有者开发协作者

4. 检查部署结果

成功部署示例应用后,我们可以登录到 AWS 账户,访问对应区域的 AWS CodeCommit。将看到如下3个仓库已经被创建到我们的账户中了。

这里我们创建了3个代码仓库来演示在企业中为不同团队配置不同代码仓库的权限。如下图所示,我们通过仓库的标签功能为仓库MyApp1 设置了相应的业务属性,

之前创建的仓库拥有者协作者角色仅可以访问具有如下标签组合的代码仓库,

 {
   'app': 'my-app-1',
   'team': 'abc',
 }

5. 配置代码仓库拥有者和协作者用户访问权限

接下来让我们配置当前用户通过 AssumeRole 方式模拟为仓库的拥有者开发协作者
使用您熟悉的文本编辑工具打开 AWS CLI 配置文件,添加类似如下配置,

[profile codecommit-repo1-admin]
role_arn = arn:aws:iam::<your account id>:role/codecommitmodel/CodecommitDevopsModelStack-Repo1AdminRole0648F018-1SNXR23P4XVYZ
source_profile = default
region = cn-northwest-1
cli_pager=
[profile codecommit-repo1-collaborator]
role_arn = arn:aws:iam::<your account id>:role/codecommitmodel/CodecommitDevopsModelStac-Repo1CollaboratorRole1EB-GUKKK92TYHNR
source_profile = default
region = cn-northwest-1
cli_pager=
  • 将 repo1-admin 和 repo1-collaborator 其中的 role_arn 替换为部署成功后对应输出的 role arn
  • 如果在环境准备中配置的 AWS CLI 不是默认 profile,将 source_profile 的值替换为您当前使用的 profile 名称
  • 将 region 的值,同 source_profile 中配置的 region 值保持一致。例如,以上示例使用的 宁夏区域 cn-northwest-1

保存配置文件修改后,让我们打开一个新的终端命令提示符来测试以上配置。

❯ export AWS_DEFAULT_PROFILE=codecommit-repo1-admin # 配置 awscli 使用 repo1-admin 身份

❯ aws sts get-caller-identity # 查询当前用户身份,将得到类似如下输出
{
    "UserId": "AROAQP3VLCVWYYTPJL2GW:botocore-session-1587717914",
    "Account": "0123456789xx",
    "Arn": "arn:aws-cn:sts::0123456789xx:assumed-role/CodecommitDevopsModelStack-Repo1AdminRole0648F018-1SNXR23P4XVYZ/botocore-session-1587717914"
}

❯ aws codecommit list-repositories # 查询 repo1-admin 配置默认区域下 codecommit 代码仓库,得到类似如下输出
{
    "repositories": [
        {
            "repositoryName": "CodecommitDevopsModelStack-MyApp1",
            "repositoryId": "79151215-c555-4b83-b836-cbaf7cbbd959"
        },
        {
            "repositoryName": "CodecommitDevopsModelStack-MyApp2",
            "repositoryId": "44421652-d12e-413e-85e3-e0db894ab018"
        },
        {
            "repositoryName": "CodecommitDevopsModelStack-MyApp3",
            "repositoryId": "8d146b34-f659-4b17-98d8-85ebaa07283c"
        }
    ]
}

❯ aws codecommit get-repository --repository-name CodecommitDevopsModelStack-MyApp1 # 查询名称为 MyApp1 的仓库详细信息
{
    "repositoryMetadata": {
        "accountId": "0123456789xx",
        "repositoryId": "79151215-c555-4b83-b836-cbaf7cbbd959",
        "repositoryName": "CodecommitDevopsModelStack-MyApp1",
        "repositoryDescription": "Repo for App1.",
        "lastModifiedDate": "2020-04-24T15:52:52.824000+08:00",
        "creationDate": "2020-04-24T15:52:52.824000+08:00",
        "cloneUrlHttp": "https://git-codecommit---cn-northwest-1.amazonaws.com.rproxy.goskope.com.cn/v1/repos/CodecommitDevopsModelStack-MyApp1",
        "cloneUrlSsh": "ssh://git-codecommit---cn-northwest-1.amazonaws.com.rproxy.goskope.com.cn/v1/repos/CodecommitDevopsModelStack-MyApp1",
        "Arn": "arn:aws-cn:codecommit:cn-northwest-1:0123456789xx:CodecommitDevopsModelStack-MyApp1"
    }
}


❯ aws codecommit get-repository --repository-name CodecommitDevopsModelStack-MyApp2 # 让我们尝试着获取下没有权限的仓库信息,得到类似如下权限被拒绝的错误

An error occurred (AccessDeniedException) when calling the GetRepository operation: User: arn:aws-cn:sts::0123456789xx:assumed-role/CodecommitDevopsModelStack-Repo1AdminRole0648F018-1SNXR23P4XVYZ/botocore-session-1587717914 is not authorized to perform: codecommit:GetRepository on resource: arn:aws-cn:codecommit:cn-northwest-1:0123456789xx:CodecommitDevopsModelStack-MyApp2

当然您也可以为已经存在的 IAM 用户添加示例应用创建出来以 CodecommitDevopsModelStack-CodecommitCollaborationModel 开头的 IAM 策略来获取仓库拥有者或协作者权限。

6. 初始化代码仓库

在示例应用中的代码仓库 CodecommitDevopsModelStack-MyApp1 是新创建的,这时它是一个空的 Git 仓库,不包含任何代码。这里让我们用 AWS Toolkit for JetBrains 项目为例,假定它是我们一个在本地已经有过一些提交的代码仓库,让我们以仓库拥有者的身份将初始代码上传到 AWS CodeCommit 托管的仓库中。

请在您本地的终端命令提示符执行以下命令,

export AWS_DEFAULT_PROFILE=codecommit-repo1-admin # 配置 awscli 使用 repo1-admin 身份

git clone https://github.com/aws/aws-toolkit-jetbrains.git # 克隆 aws-toolkit-jetbrains 到本地,作为已有的初始代码

cd aws-toolkit-jetbrains

git remote add codecommit codecommit::cn-northwest-1://CodecommitDevopsModelStack-MyApp1 # 将 codecommit 上的仓库添加为一个新的远程仓库,且命名为 codecommit。请参照文档[配置git-remote-codecommit](https://docs.aws.amazon.com/zh_cn/codecommit/latest/userguide/setting-up-git-remote-codecommit.html),或使用https/ssh连接git仓库时,替换git仓库url为对应的协议。如遇到错误提示git-remote-codecommit不支持中国的区域,请重新安装git-remote-codecommit。

git push codecommit master:init  # 将已有的代码推送到 codecommit init临时分支

aws codecommit create-branch --repository-name CodecommitDevopsModelStack-MyApp1 --branch-name master --commit-id `git rev-parse master` # 基于最新的提交创建master分支

aws codecommit update-default-branch --repository-name CodecommitDevopsModelStack-MyApp1 --default-branch-name master # 设置master分支为默认分支

aws codecommit delete-branch --repository-name CodecommitDevopsModelStack-MyApp1 --branch-name init # 清除临时init分支

7. 开发协作者按照敏捷流程协作开发

我们模拟协作者为 aws-toolkit-jetbrains 实现了一个新的功能,希望将新功能代码合并到主干分支 master。

请在您本地的终端命令提示符执行以下命令,

export AWS_DEFAULT_PROFILE=codecommit-repo1-collaborator # 配置 awscli 使用 repo1-collaborator 身份

# 为新功能修改本地代码

git commit -m 'This is my new feature' -a

git push codecommit HEAD:refs/heads/features/my-feature # 将新功能代码推送到前缀为 features/ 的新分支

aws codecommit create-pull-request --title 'My feature of AWS toolkit for Jetbrains' --targets repositoryName=CodecommitDevopsModelStack-MyApp1,sourceReference=features/my-feature,destinationReference=master # 为新功能变更创建拉取请求

以上命令以代码仓库协作者的身份提交新功能代码到前缀为 features/ 的分支,并且创建拉取请求申请合并到主分支master。

在 AWS CodeComit 控制台(如下图),我们将看到由开发协作者创建的名为 My feature of AWS toolkit for Jetbrains 的拉取请求已经通过了拉取请求自动构建的审核,并且被标记为批准+1。

在代码仓库拥有者维护者通过人工代码审核后,执行批准操作后,拥有者维护者可以将该拉取请求合并到主分支上。AWS CodeCommit 控制台上的拉取请求审核工具支持代码对比,代码文件行内评论、对话,更多详细的使用介绍可以参阅此博客

这时我们访问主分支的持续集成部署构建项目,可以看到新的构建已经启动,开始拉取最新的主分支代码构建,然后将新的构件发布或者部署新版本服务同业务系统集成。

8. 环境清理

以上演示使用的都是 AWS 托管服务,没有前期费用和最小使用费用,仅按您实际使用的资源计费。AWS CodeCommit, AWS CodeBuild 服务都包含在 AWS 全球区 Free Tier 套餐中,具体免费用量您可以查询这里

同时,您也可以在本地环境执行以下命令清理示例应用创建的 AWS 云上资源。

npm run cleanup

小结

本文从实现机制,流程特性等方面介绍了基于 AWS CodeCommit 的敏捷开发工作流程,也通过示例应用演示了如何在敏捷工作流程下提交新的代码。同时,示例应用中代码仓库本身以及围绕该仓库的开发、部署流程搭建也是通过代码来管理的。利用基础服务即代码的思路,类似的流程易于应用到大规模研发管理的场景,帮助企业搭建可维护,安全的研发基础架构。

 

本篇作者

朱孟欣

AWS解决方案架构师。从事多年软件开发,负责过数个不同规模的创业团队产品技术研发。开源软件支持者,贡献者,曾是Eclipse Committer。