当前位置:  开发笔记 > 编程语言 > 正文

CodePipeline:如何从GitHub引用嵌套的CloudFormation Stacks作为Source

如何解决《CodePipeline:如何从GitHub引用嵌套的CloudFormationStacks作为Source》经验,为你挑选了2个好方法。

我们的CloudFormation模板存储在GitHub中.在CodePipeline内部,我们使用GitHub作为源代码,但是当它们没有存储在S3上时,我们无法引用嵌套的CloudFormation Stacks.

当我们在CodePipeline中使用GitHub作为源代码时,我们如何引用CloudFormation嵌套堆栈?

如果无法做到这一点,我们如何在源阶段(来自GitHub)和CodePipeline中的Deploy Stage之间将CloudFormation模板从GitHub上传到S3?



1> wjordan..:

我可以想到两种方法来引用来自GitHub源的嵌套CloudFormation堆栈以进行CodePipeline部署:

1.预先提交Git钩子

添加在模板上运行的pre-commit客户端Git挂钩,将aws cloudformation package生成的模板与对Rit存储库的S3引用一起提交到源模板的更改.

这种方法的好处是您可以利用现有的模板重写逻辑aws cloudformation package,而不必修改现有的CodePipeline配置.

2. Lambda管道阶段

添加基于Lambda的管道阶段,该阶段从GitHub源工件中提取指定的嵌套堆栈模板文件,并将其上载到父堆栈模板中引用的S3中的指定位置.

这种方法的好处是管道将保持完全独立,不需要提交者进行任何额外的预处理步骤.

我已经发布了一个完整的参考示例实现wjordan/aws-codepipeline-nested-stack:

启动堆栈

AWSTemplateFormatVersion: 2010-09-09
Description: Infrastructure Continuous Delivery with CodePipeline and CloudFormation, with a project containing a nested stack.
Parameters:
  ArtifactBucket:
    Type: String
    Description: Name of existing S3 bucket for storing pipeline artifacts
  StackFilename:
    Type: String
    Default: cfn-template.yml
    Description: CloudFormation stack template filename in the Git repo
  GitHubOwner:
    Type: String
    Description: GitHub repository owner
  GitHubRepo:
    Type: String
    Default: aws-codepipeline-nested-stack
    Description: GitHub repository name
  GitHubBranch:
    Type: String
    Default: master
    Description: GitHub repository branch
  GitHubToken:
    Type: String
    Description: GitHub repository OAuth token
  NestedStackFilename:
    Type: String
    Description: GitHub filename (and S3 Object Key) for nested stack template.
    Default: nested.yml
Resources:
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn: !GetAtt [PipelineRole, Arn]
      ArtifactStore: 
        Type: S3
        Location: !Ref ArtifactBucket
      Stages:
      - Name: Source
        Actions:
        - Name: Source
          ActionTypeId:
            Category: Source
            Owner: ThirdParty
            Version: 1
            Provider: GitHub
          Configuration:
            Owner: !Ref GitHubOwner
            Repo: !Ref GitHubRepo
            Branch: !Ref GitHubBranch
            OAuthToken: !Ref GitHubToken
          OutputArtifacts: [Name: Template]
          RunOrder: 1
      - Name: Deploy
        Actions:
        - Name: S3Upload
          ActionTypeId:
            Category: Invoke
            Owner: AWS
            Provider: Lambda
            Version: 1
          InputArtifacts: [Name: Template]
          Configuration:
            FunctionName: !Ref S3UploadObject
            UserParameters: !Ref NestedStackFilename
          RunOrder: 1
        - Name: Deploy
          RunOrder: 2
          ActionTypeId:
            Category: Deploy
            Owner: AWS
            Version: 1
            Provider: CloudFormation
          InputArtifacts: [Name: Template]
          Configuration:
            ActionMode: REPLACE_ON_FAILURE
            RoleArn: !GetAtt [CFNRole, Arn]
            StackName: !Ref AWS::StackName
            TemplatePath: !Sub "Template::${StackFilename}"
            Capabilities: CAPABILITY_IAM
            ParameterOverrides: !Sub |
              {
                "ArtifactBucket": "${ArtifactBucket}",
                "StackFilename": "${StackFilename}",
                "GitHubOwner": "${GitHubOwner}",
                "GitHubRepo": "${GitHubRepo}",
                "GitHubBranch": "${GitHubBranch}",
                "GitHubToken": "${GitHubToken}",
                "NestedStackFilename": "${NestedStackFilename}"
              }
  CFNRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action: ['sts:AssumeRole']
          Effect: Allow
          Principal: {Service: [cloudformation.amazonaws.com]}
        Version: '2012-10-17'
      Path: /
      ManagedPolicyArns:
      # TODO grant least privilege to only allow managing your CloudFormation stack resources
      - "arn:aws:iam::aws:policy/AdministratorAccess"
  PipelineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action: ['sts:AssumeRole']
          Effect: Allow
          Principal: {Service: [codepipeline.amazonaws.com]}
        Version: '2012-10-17'
      Path: /
      Policies:
        - PolicyName: CodePipelineAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                - 's3:*'
                - 'cloudformation:*'
                - 'iam:PassRole'
                - 'lambda:*'
                Effect: Allow
                Resource: '*'
  Dummy:
    Type: AWS::CloudFormation::WaitConditionHandle
  NestedStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub "https://s3.amazonaws.com/${ArtifactBucket}/${NestedStackFilename}"
  S3UploadObject:
    Type: AWS::Lambda::Function
    Properties:
      Description: Extracts and uploads the specified InputArtifact file to S3.
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var exec = require('child_process').exec;
          var AWS = require('aws-sdk');
          var codePipeline = new AWS.CodePipeline();
          exports.handler = function(event, context, callback) {
            var job = event["CodePipeline.job"];
            var s3Download = new AWS.S3({
                credentials: job.data.artifactCredentials,
                signatureVersion: 'v4'
            });
            var s3Upload = new AWS.S3({
                signatureVersion: 'v4'
            });
            var jobId = job.id;
            function respond(e) {
              var params = {jobId: jobId};
              if (e) {
                params['failureDetails'] = {
                  message: JSON.stringify(e),
                  type: 'JobFailed',
                  externalExecutionId: context.invokeid
                };
                codePipeline.putJobFailureResult(params, (err, data) => callback(e));
              } else {
                codePipeline.putJobSuccessResult(params, (err, data) => callback(e));
              }
            }
            var filename = job.data.actionConfiguration.configuration.UserParameters;
            var location = job.data.inputArtifacts[0].location.s3Location;
            var bucket = location.bucketName;
            var key = location.objectKey;
            var tmpFile = '/tmp/file.zip';
            s3Download.getObject({Bucket: bucket, Key: key})
              .createReadStream()
              .pipe(require('fs').createWriteStream(tmpFile))
              .on('finish', ()=>{
                exec(`unzip -p ${!tmpFile} ${!filename}`, (err, stdout)=>{
                if (err) { respond(err); }
                s3Upload.putObject({Bucket: bucket, Key: filename, Body: stdout}, (err, data) => respond(err));
              });
            });
          };
      Timeout: 30
      Runtime: nodejs4.3
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
      - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      - "arn:aws:iam::aws:policy/AWSCodePipelineCustomActionAccess"
      Policies:
      - PolicyName: S3Policy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - 's3:PutObject'
                - 's3:PutObjectAcl'
              Resource: !Sub "arn:aws:s3:::${ArtifactBucket}/${NestedStackFilename}"



2> 小智..:

除了具有lambda阶段的解决方案之外,一种简单的方法是使用CodeBuild和AWS SAM.

在主CloudFormation模板中(我们称之为main.yaml),使用'Transform:AWS :: Serverless-2016-10-31'

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  NestedTemplate:
    AWS::CloudFormation::Stack
    Properties:
      TemplateUri: ./nested-template.yaml

请注意,您只需要将相对路径放到子模板而不是绝对s3 uri.

使用以下buildspecification.yaml添加CodeBuild阶段

version: 0.1
phases:
  build:
    commands:
      aws cloudformation package --template-file main.yaml --output-template-file transformed_main.yaml --s3-bucket my_bucket

artifacts:
  type: zip
  files:
    - transformed_main.yaml

构建命令'aws cloudformation package'会将nested-template.yaml上传到s3存储桶'my_bucket',并将绝对s3 uri注入转换后的模板.

在CloudFormation部署阶段,使用"创建更改集"和"执行更改集"来创建堆栈.请注意,"创建或更新堆栈"不适用于"转换:AWS :: Serverless-2016-10-31".

以下是您可能会发现有用的文档:

    http://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html

    http://docs.aws.amazon.com/lambda/latest/dg/automating-deployment.html

第二个文档展示了如何部署lambda函数,但引用嵌套堆栈本质上是相同的.

推荐阅读
手机用户2402851155
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有