首页 > 解决方案 > 为 AWS Cognito + API Gateway + Lambdas + DynamoDB + SNS 创建 CI 管道的最佳实践

问题描述

从 AWS 开始,并希望从一开始就做好。拥有完整 CI 管道的当前最先进的方法是什么?

我们的想法是将所有内容都放在公司的本地 git 存储库中,然后我们可以触发部署到不同的 AWS 阶段。一切都是我们的意思,所以我们可以自动化一切,并且完全无需 aws Web 界面即可生活。

我浏览了一些教程,他们似乎都以不同的方式做这件事,出现了 Apex、Amplify、CloudFormation、SAM 等工具,其中一些似乎很旧并且已被弃用。因此,我们试图弄清楚,当前的技术是什么,哪些不应该再使用。

哪个编辑器好?是否有任何支持直接从 IDE 使用的插件部署?

此外,如果有一个示例项目可以完成所有这些或大部分工作,那将是一个真正的帮助!

标签: amazon-web-servicescontinuous-integrationamazon-dynamodbaws-api-gateway

解决方案


我个人的“最新技术”如下:

  • 对于每个(mirco)服务,我在 AWS CodeCommit 中创建一个单独的 Git 存储库
  • 每个存储库都有自己的带有 AWS CodePipeline 的 CI/CD 管道。管道有以下阶段:
    • 来源 (AWS CodeCommit)
    • 构建 (AWS CodeBuild)
    • 部署暂存[*] (AWS CloudFormation)
    • 批准(手动批准)
    • 部署生产[*] (AWS CloudFormation)

整个基础设施和管道都是用 CloudFormation 编写的(在AWS SAM Syntax中),我强烈建议也这样做。这也将帮助您解决您的要求“ [...] 完全没有 aws Web 界面。

[*]:两个阶段都使用相同的(!)AWS CloudFormation 模板,我只是将不同的Environment参数传递到基础设施模板中,以便能够根据环境做出一些差异

我的大部分服务都是用 TypeScript 编写的,为了开发它,我使用WebStorm一个很酷的插件来帮助我编写 AWS CloudFormation 模板。


示例pipeline.yml

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  RepositoryName:
    Type: String
  ArtifactStoreBucket:
    Type: String

Resources:
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn: !GetAtt CodePipelineRole.Arn
      ArtifactStore:
        Location: !Ref ArtifactStoreBucket
        Type: S3
      Stages:
        - Name: Source
          Actions:
            - Name: CodeCommit
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              Configuration:
                RepositoryName: !Ref RepositoryName
                BranchName: master
              InputArtifacts: []
              OutputArtifacts:
                - Name: SourceOutput
              RunOrder: 1
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              Configuration:
                ProjectName: !Ref Build
              InputArtifacts:
                - Name: SourceOutput
              OutputArtifacts:
                - Name: BuildOutput
              RunOrder: 1
        - Name: Staging
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: CloudFormation
              Configuration:
                ActionMode: CREATE_UPDATE
                Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND
                StackName: !Sub ${AWS::StackName}-Infrastructure-Staging
                RoleArn: !GetAtt CloudFormationRole.Arn
                TemplatePath: BuildOutput::infrastructure-packaged.yml
                ParameterOverrides:
                  !Sub |
                  {
                    "Environment": "Staging"
                  }
              InputArtifacts:
                - Name: BuildOutput
              OutputArtifacts: []
              RunOrder: 1
        - Name: Approval
          Actions:
            - Name: Approval
              ActionTypeId:
                Category: Approval
                Owner: AWS
                Version: 1
                Provider: Manual
              InputArtifacts: []
              OutputArtifacts: []
              RunOrder: 1
        - Name: Production
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: CloudFormation
              Configuration:
                ActionMode: CREATE_UPDATE
                Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND
                StackName: !Sub ${AWS::StackName}-Infrastructure-Production
                RoleArn: !GetAtt CloudFormationRole.Arn
                TemplatePath: BuildOutput::infrastructure-packaged.yml
                ParameterOverrides:
                  !Sub |
                  {
                    "Environment": "Production"
                  }
              InputArtifacts:
                - Name: BuildOutput
              OutputArtifacts: []
              RunOrder: 1

  Build:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_MEDIUM
        Image: aws/codebuild/nodejs:10.14.1
        Type: LINUX_CONTAINER
      Name: !Sub ${AWS::StackName}-Build
      ServiceRole: !Ref CodeBuildRole
      Source:
        Type: CODEPIPELINE
        BuildSpec:
          !Sub |
          version: 0.2
          phases:
            build:
              commands:
                - npm install
                - npm run lint
                - npm run test:unit
                - npm run build
                - aws cloudformation package --s3-bucket ${ArtifactStoreBucket} --template-file ./infrastructure.yml --output-template-file infrastructure-packaged.yml
          artifacts:
            files:
              - infrastructure-packaged.yml

  BuildLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 14
      LogGroupName: !Sub /aws/codebuild/${Build}

  CodePipelineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: codepipeline.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: CodePipelineRolePolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - iam:PassRole
                Resource:
                  - !GetAtt CloudFormationRole.Arn
              - Effect: Allow
                Action:
                  - s3:*
                Resource:
                  - !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
              - Effect: Allow
                Action:
                  - codecommit:*
                Resource:
                  - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
              - Effect: Allow
                Action:
                  - codebuild:*
                Resource:
                  - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${AWS::StackName}-Build
              - Effect: Allow
                Action:
                  - cloudformation:*
                Resource:
                  - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}-Infrastructure-Staging/*
                  - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}-Infrastructure-Production/*

  CodeBuildRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: CodeBuildRolePolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - s3:*
                Resource:
                  - !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
              - Effect: Allow
                Action:
                  - codecommit:*
                Resource:
                  - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
              - Effect: Allow
                Action:
                  - logs:*
                Resource:
                  - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${AWS::StackName}-Build*

  CloudFormationRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AdministratorAccess

示例infrastructure.yml

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Parameters:
  Environment:
    Type: String
    AllowedValues:
      - Staging
      - Production

Resources:
  Api:
    Type: AWS::Serverless::Function
    Properties:
      Handler: api.handler
      CodeUri: .build
      Runtime: nodejs10.x
      MemorySize: 128
      Timeout: 10
      Events:
        ProxyApi:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: ANY
      Environment:
        Variables:
          ENVIRONMENT: !Ref Environment
      DeploymentPreference:
        Enabled: false

  ApiLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 14
      LogGroupName: !Sub /aws/lambda/${Api}

Outputs:
  ApiEndpoint:
    Value: !Sub https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${ServerlessRestApiProdStage}

推荐阅读