IaaS/퍼블릭클라우드

(AWS) CodePipeline 이란?

armyost 2022. 1. 10. 12:56
728x90

CodePipeline이란 

  • 지속적 배포(Continuous delivery) 툴
  • 시각적으로 Work Flow를 정의하도록 하는 툴
  • 가능한 Source 는 Github, CodeCommit, AmazonS3 가 가능하다.
  • Build 는 CodeBuild, Jenkins, etc... 를 호출 할 수 있다. 3rd party 툴을 사용할수 도 있다.
  • Deploy는 AWS CodeDeploy, Beanstalk, CloudFormation, ECS 등..
  • 각각의 Stage는 순서별 혹은 병행적 Action을 정의할 수 있다. 
  • 수동 승인프로세스도 각 스테이지에 정의할 수 있다. 

CodePipeline을 정의하기 위한 CICD 기술스텍은 다음과 같다.

 

※ CodePipeline의 각 Stage는 Artifacts를 S3에 생성된다. 

S3에 저장되어 다음 스테이지에서 참조된다.


CodePipeline 사용법

1) [CodePipeline]-[Getting started]를 클릭하고 'Create Pipeline'을 선택한다. 

 

2) Service role에 기존에 생성한 Pipeline 권한이 없다면 'New Service Role'을 선택한다.

 

3) Advanced Setting 섹션을 Expand하고 Artifact store은 Default location을 선택한다. 

※ Default Location을 선택하게되면 새로운 저장소가 생성되는데 나중에는 너무 많아 관리가 힘들수 있다. 처음부터 중앙화하려면 Custom location을 사용하자

 

4) 버킷에 저장될때 암호화 되도록 키를 지정하자

 

5) Source Provider 는 지난 시간에 만든 CodeCommit을 사용토록 선택하자

 

6) 그러면 아래에 CodeCommit에 맞는 옵션이 나오는데, Amazon CloudWatch Event를 선택하면 CodeCommit 변경사항이 있을때 Trigger되도록 설정할 수 있다. 

※ AWS CodePipeline을 선택하면 주기적으로 체크한다. 

 

7) Build Provider를 선택하자 

 

8) Deploy는 Code Deploy를 선택하자

 

9) 생성을 완료하면 Pipeline이 시작된다. 

 


Stage 추가하기

1) 방금 생성한 Pipeline에서 Test Stage를 추가하고 싶다면 '+Add stage' 버튼을 누르고 '+Add action group'을 누른다. 

 

2) Edit Action 팝업에서 Action Provider를 클릭하며 'Test'로 내려가 'AWS CodeBuild'를 클릭하자. 

 

3) 'Source Artifact'는 이미 전 stage에서 결정했다. 

 

4) Project name은 같은 Source를 사용할 것이고 당시 사용했던 'grep' 구문으로 테스트를 하면 되어 이전에 만든 코드빌드 프로젝트를 선택한다.

 

5) Output Artifacts 는 'Test Result'를 입력한다. 

 

6) 입력이 끝나면 'Release Change'를 클릭하여 적용한다. 

 


운영환경에 배포하는 Stage 추가하기

 

1) 수정코자 하는 Pipeline에서 'Add stage'를 클릭하여 stage를 추가한다.

 

2) 그리고는 'Add Action Group'을 클릭하고 'Action Provider'를 'AWS CodeDeploy'를 선택한다. 

 

3) 'Input artifacts' 란에는 이전 단계의 결과물인 'TestResults'를 선택한다

 

4) 'Application Name'과 'Deployment Group'은 운영환경을 정의한 어플리케이션과 배포그룹을 선택하여 Action 생성을

완료한다.

 

5) 방금 추가한 Action Group위에 또하나의 Action Group을 정의하기 위해서 같은 Stage의 상위 'Add Action Group'을

클릭한다.

※ Action이 위아래에 배치될 경우 Sequential 순서를 뜻하며, 좌우로 배치된 Action은 Parallel 수행을 뜻한다.

 

6) 'Action Provider'에 'Manual Approval'을 선택한다.

 

7) SNS를 사용하려면 정의한 SNS를 활성화한다.

 

8) 웹페이지를 들어가 결과물을 보여주고 확인을 받고자한다면 URL을 입력한다.

 

9) 코멘트를 입력하여 Action 생성을 완료한다.

 


EventBridge를 적용해보자

 

1) [EventBridge]-[규칙]을 접속하자

 

2) [Create Rule]을 클릭하고 이벤트 패턴을 선택한다. 

※ 이벤트 패턴이란 특정 주기의 스케쥴이 아니라 이벤트 발생시 작동하는 방식을 뜻한다.

 

3) '대상' 부분에서 'SNS'혹은 'Lambda'를 선택하여 후속조치를 수행할 수 있다.

 


파이프라인에서 Lambda 함수를 사용하는 예는 다음과 같습니다.

  • AWS CloudFormation을 사용하여 파이프라인의 한 단계에서 리소스를 온 디맨드로 생성하고 다른 단계에서 삭제합니다.
  • 가동 중지 없이 애플리케이션 버전을 배포하려면AWS Elastic BeanstalkCNAME 값을 스왑하는 Lambda 함수를 사용합니다.
  • Amazon ECS Docker 인스턴스에 배포합니다.
  • AMI 스냅샷을 생성하여 빌드하거나 배포하기 전에 리소스를 백업합니다.
  • IRC 클라이언트에 메시지를 게시하는 등 타사 제품과의 통합을 파이프라인에 추가합니다.

※ 관련 Document

https://docs.aws.amazon.com/ko_kr/codepipeline/latest/userguide/actions-invoke-lambda-function.html

 

호출AWS LambdaCodePipeline의 파이프라인에서 함수 - AWS CodePipeline

파이프라인의 소스 공급자인 경우, 소스 파일을 .zip 하나로 압축하고 그 .zip을 소스 버킷에 업로드할 수 있습니다. 압축이 풀린 단일 파일을 업로드할 수도 있지만 .zip 파일을 예상하는 다운스트

docs.aws.amazon.com

 

Lambda를 사용하여 파이프라인을 작성해보겠습니다.

 

1) [Lambda]-[Functions] 선택

2) Runtime을 Nodejs로 선택합니다. 

3) Execution Role을 'Create a New role with basic Lambda permissions' 로 선택

4) 'Create Function' 버튼 클릭하여 생성합니다.

 

5) 방금 생성한 새로운 Execution Role에 필요한 내용을 커스텀 합니다.

아래 내용을 기초로하되 필요한 만큼 더 확장해도 됩니다.

{
  "Version": "2012-10-17", 
  "Statement": [
    {
      "Action": [ 
        "logs:*"
      ],
      "Effect": "Allow", 
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Action": [
        "codepipeline:PutJobSuccessResult",
        "codepipeline:PutJobFailureResult"
        ],
        "Effect": "Allow",
        "Resource": "*"
     }
  ]
}

 

6) Lambda의 코드를 작성한다. 그리고 저장한다.

※ 참고로 아래 코드는 Lambda함수가 성공여부에 따라 다른 이벤트를 실행시키는 예제이다. 

Parameter로 전달받은 URL에서 Http 프로토콜 200 OK 여부와 'Congraturation' 문구 포함여부를 확인합니다.

 

var assert = require('assert');
var AWS = require('aws-sdk');
var http = require('http');

exports.handler = function(event, context) {

    var codepipeline = new AWS.CodePipeline();
    
    // Retrieve the Job ID from the Lambda action
    var jobId = event["CodePipeline.job"].id;
    
    // Retrieve the value of UserParameters from the Lambda action configuration in CodePipeline, in this case a URL which will be
    // health checked by this function.
    var url = event["CodePipeline.job"].data.actionConfiguration.configuration.UserParameters; 
    
    // Notify CodePipeline of a successful job
    var putJobSuccess = function(message) {
        var params = {
            jobId: jobId
        };
        codepipeline.putJobSuccessResult(params, function(err, data) {
            if(err) {
                context.fail(err);      
            } else {
                context.succeed(message);      
            }
        });
    };
    
    // Notify CodePipeline of a failed job
    var putJobFailure = function(message) {
        var params = {
            jobId: jobId,
            failureDetails: {
                message: JSON.stringify(message),
                type: 'JobFailed',
                externalExecutionId: context.awsRequestId
            }
        };
        codepipeline.putJobFailureResult(params, function(err, data) {
            context.fail(message);      
        });
    };
    
    // Validate the URL passed in UserParameters
    if(!url || url.indexOf('http://') === -1) {
        putJobFailure('The UserParameters field must contain a valid URL address to test, including http:// or https://');  
        return;
    }
    
    // Helper function to make a HTTP GET request to the page.
    // The helper will test the response and succeed or fail the job accordingly 
    var getPage = function(url, callback) {
        var pageObject = {
            body: '',
            statusCode: 0,
            contains: function(search) {
                return this.body.indexOf(search) > -1;    
            }
        };
        http.get(url, function(response) {
            pageObject.body = '';
            pageObject.statusCode = response.statusCode;
            
            response.on('data', function (chunk) {
                pageObject.body += chunk;
            });
            
            response.on('end', function () {
                callback(pageObject);
            });
            
            response.resume(); 
        }).on('error', function(error) {
            // Fail the job if our request failed
            putJobFailure(error);    
        });           
    };
    
    getPage(url, function(returnedPage) {
        try {
            // Check if the HTTP response has a 200 status
            assert(returnedPage.statusCode === 200);
            // Check if the page contains the text "Congratulations"
            // You can change this to check for different text, or add other tests as required
            assert(returnedPage.contains('Congratulations'));  
            
            // Succeed the job
            putJobSuccess("Tests passed.");
        } catch (ex) {
            // If any of the assertions failed then fail the job
            putJobFailure(ex);    
        }
    });     
};

 

7) 수정할 CodePipeline의 상세페이지로 들어가 운영환경 배포 Stage 이전 Stage를 추가한다. Action Provider는 'AWS Lambda'를 선택한다. 

 

8) Input Artifact는 'Test Result'를 선택하고 User Parameter에 테스트할 웹페이지 주소를 입력한다.  이렇게 생성하면 완료