목차

목차

2021-04-12

  • 실습 UI 업데이트
  • Nodejs 버전 8.0 → 14.x로 전환

2019-09-26

  • 서버리스 기반 간단하게 테스트 해볼 수 있는 CI/CD 배포 파이프라인 구축 실습

해당 실습 아키텍처는 Cloud9을 이용하여 Lambda 함수 코드와 SAM Template을 만들어 API를 하나 배포하는 실습을 진행합니다.

문서 URL: https://cdk.awsdemo.kr/devops301lab1

실습 소개

소스코드를 만들고 CodeCommit에 반영하면, CodePipeline에 의해서 CodeBuild로 코드를 가져와서 빌드하여 아티팩트를 생성합니다.
해당 아티팩트는 Cloudformation을 이용하여 배포를 하고, SAM Template에 기술되어져 있는 배포 방법으로 배포합니다.
이 과정을 CodeDeploy를 통해서 확인하고 롤백하는 방법을 살펴 봅니다.

아키텍처 다이어그램


개발환경 구성

개발통합환경은 AWS Cloud9을 이용합니다. 개발을 위해서 별도의 개발 서버를 할당 받거나 서버에 런타임 설정을 할 필요가 없습니다.
해당 실습은 Node.js 언어를 이용해서 Lambda 함수를 개발하며, 인프라는 SAM Template을 활용합니다.

리전 선택

  1. 이 애플리케이션은 Seoul 리전에서 개발합니다. AWS 관리 콘솔 우측 하단에 Seoul 를 선택합니다. 화면에 표시되는 언어는 English 를 기본으로 진행합니다.

AWS Cloud9 시작하기

  1. 서비스에서 AWS Cloud9으로 이동하여 새로운 AWS Cloud9 환경을 생성합니다. Create Environment 버튼을 클릭합니다.


  2. AWS Cloud9의 Name cdkenv  를 입력하고, 우측 하단의 Next step 버튼을 클릭합니다.


  3. 기본 설정에서 Instance Type을 t3.small  로 변경하고, 우측 하단의  Next step 버튼을 클릭합니다.


  4. Review에서 설정된 상태(EC2의 t3.small 타입)를 확인하고 하단의 Create environment 버튼을 클릭합니다.
  5. Cloud9 환경이 준비되는 것을 볼 수 있습니다. Cloud9이 가용해질 때까지 잠시 기다립니다. (약 1분 내외면 웹 상에서 개발을 할 수 있는 환경을 구축할 수 있습니다.)

리소스 생성

S3 버킷 생성

  1. 템플릿 및 아티팩트를 보관할 S3 버킷을 생성합니다. AWS 관리 콘솔에서 S3 서비스로 이동하고 Create bucket 버튼을 클릭합니다.


  2. 아래와 같은 이름을 가지는 버킷을 생성합니다. 숫자가 들어가는 부분은   본인 전화 번호로 대체  해서 입력합니다. 해당 버킷은  Seoul (ap-northeast-2)  Region에 만들어져야 합니다. 설정이 완료되면 우측 하단의  Create Bucket 버튼을 클릭합니다.

    aws301-devops- 01012345678


소스 리포지토리 생성

  1. AWS 관리 콘솔에서 CodeCommit 서비스로 이동하고,  Create repository 버튼을 클릭합니다.


  2. Repository name에  AWS301Repo 를 입력하고 Create 버튼을 클릭합니다.


  3. 생성된 Repository를 Clone 하기 위해서 주소를 복사합니다. Clone URL 콤보상자를 클릭하여 Clone HTTPS  를 선택합니다. 복사된 주소를 메모장에 기록해 둡니다.

    복사된 URL의 예)  https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/AWS301Repo


Cloud9에서 CodeCommit 설정

  1. Cloud9에서 CodeCommit 접근을 하기 위해서 Cloud9 하단의 Terminal에서 다음과 같은 설정을 수행하고 체크인 한 후 해당 디렉토리로 이동합니다.

    CodeCommit 접근 설정
    git config --global credential.helper '!aws codecommit credential-helper $@'
    git config --global credential.UseHttpPath true
    git clone https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/AWS301Repo
    cd ./AWS301Repo/

Lambda 소스 코드 생성

  1. 해당 폴더로 이동한 다음 index.js Lambda 소스 코드를 만들겠습니다. Terminal에서 vim으로 만드셔도 되고, Cloud 9의 IDE를 이용하여 만들 수도 있습니다. 여기서는 Cloud 9의 IDE를 이용해 보겠습니다. 좌측 상단에서 작업을 위한 폴더로 이동하여 파일을 생성합니다. 

  2. 파일 이름은 index.js 로 생성합니다. 그리고 더블 클릭을 통해서 파일을 열어 줍니다. 우측 탭에 해당 파일이 표시가 됩니다. (아무것도 없는 상태로 열립니다.)

     → 

  3. Cloud 9 편집창에서 다음의 코드를 복사하여 붙여 줍니다. (vim 에디터를 이용해서 소스코드를 붙이고 저장하셔도 됩니다.) 그리고 Mac의 경우 Command + S, Windows의 경우 Ctrl + S 단축키로 해당 파일을 저장합니다.

    index.js Lambda 코드
    "use strict";
    exports.handler = async (event) => {
        console.log("request: " + JSON.stringify(event));
        let message = {
            message: "Hello, AWS!"
        };
        let response = {
            statusCode: 200,
            body: JSON.stringify(message)
        };
        return response;
    };



    만약, vim 사용시 명령어

    1. vim이 실행되고, 최초 키보드에서 i  키를 클릭하면, 커서 위치에서 "Insert" 가능한 모드가 됩니다.
    2. 위 복사한 코드를 붙여 넣기 한 다음, esc 키를 누르고 편집 모드를 빠져 나옵니다.
    3. :wq 를 입력하고 Enter 키를 누르면 편집된 내용을 저장하고 종료 합니다.

    만약 실수를 했을 경우,  esc 키를 누르고 편집 모드를 빠져나와서 :q! 명령을 통해서 빠져 나온 다음 위 과정을 다시 실행하세요.


SAM 템플릿 작성

  1. Lambda 함수와 매핑될 API Gateway를 포함한 template.yml SAM 템플릿을 생성합니다. 파일의 편집이 끝나면, 항상 파일을 저장합니다.

    template.yml 파일
    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: AWS DevOps 301 Demo Application
    
    Resources:
      ApiAppFunction:
        Type: AWS::Serverless::Function
        Properties:
          Handler: index.handler
          Runtime: nodejs14.x
          Timeout: 5
          Events:
            RootHandler:
              Type: Api
              Properties:
                Path: /
                Method: GET


Lambda 함수 로컬 테스트

  1. Lambda 함수가 정상 동작하는지 테스트를 해 보겠습니다. Cloud 9에서 하단의 터미널 창에서 AWS301Repo 폴더로 이동하고, 다음과 같이 테스트 합니다.

    ec2-user:~/environment $ cd AWS301Repo/
    ec2-user:~/environment/AWS301Repo (master) $ sam local invoke



    창 하단에 정상적인 Response 가 나오는 것을 확인할 수 있습니다.


코드 변경 체크인

  1. Lambda 함수 파일과, SAM template 2개의 파일을 직접 만들었습니다. 해당 파일을 CodeCommit 리포지토리에 체크인 합니다.

    코드 체크인
    git add .
    git commit -am "Initial commit"
    git push origin master



  2. CodeCommit 서비스의 AWS301Repo에 해당 코드 체크인 여부를 확인합니다.


CodePipeline 생성

  1. 배포 파이프라인을 생성합니다. AWS 관리콘솔에서 CodePipeline 서비스로 이동하고 Create pipeline 버튼을 클릭합니다.


  2. Step 1에서 Pipeline name은 AWS301-Pipeline 을 Service role은 New service role  을 체크하고 Next 버튼을 클릭합니다.


  3. Step 2에서 Source provider는 AWS CodeCommit , Repository name은 AWS301Repo , Branch name은 master 로 선택하고 Next 버튼을 클릭합니다.

  4. Step 3에서 Build 환경을 구성합니다. Build provider는 AWS CodeBuild 를 선택하고, 하단의 Create project 버튼을 클릭합니다.


  5. Build를 위한 project를 생성합니다. Project name은 AWS301Build, Environment image는 Managed image 를 선택하고, OS는 Ubuntu 를 선택합니다. 나머지는 동일하게 선택하고, Additional configuration에서 Timeout을 5분으로 변경합니다. Buildspec 은 Insert build commands를 선택하고 Switch to editor를 클릭하여 아래의 buildspec 코드를 추가합니다.

    반드시 아래 버킷 이름은 시작할 때 생성한 S3 버킷 이름과 동일하게 변경하세요.

    buildspec yaml 파일
    version: 0.2
    phases:
      install:
        runtime-versions:
          nodejs: 14
      post_build:
        commands:
          - aws cloudformation package 
            --template-file template.yml 
            --s3-bucket aws301-devops-이부분을바꾸셔야합니다
            --output-template-file api-output.yml
            --region $AWS_DEFAULT_REGION
    artifacts:
      type: zip
      files:
        - template.yml
        - api-output.yml







  6. 성공적으로 Build project가 생성되면 자동으로 아래와 같이 구성됩니다. Next 버튼을 클릭합니다.


  7. Step 4의 배포 파이프라인은 추후 생성할 예정이므로 Skip deploy stage 버튼을 클릭합니다. 팝업 출력시 Skip 버튼을 클릭합니다.



  8. Step 5의 Review 화면에서 확인 후, Create pipeline 버튼을 클릭합니다.

CodePipeline 동작 확인

  1. CodePipeline이 Source에서 코드를 받아서 Build로 넘어가는 과정을 확인할 수 있습니다. 좌측 녹색은 완료, 파란색은 진행중, 붉은 색은 에러를 의미합니다. 



  2. 기다리면, Build 과정에서 에러가 발생하게 됩니다. 해당 에러가 발생하는 원인을 찾기 위해서 Details 를 클릭합니다.


  3. 좀 더 상세한 확인이 필요하기 때문에 Link to execution details 를 클릭합니다.


  4. Build logs를 확인한 결과 Code Build에서 만들어진 아티팩트를 S3 버킷에 업로드(PutObject) 수행하려는 순간 권한이 없어서 AccessDenied 에러가 발생한 것을 확인할 수 있습니다.
    즉, CodeBuild에게 부여되어 있는 Role에 S3로 접근할 수 있는 권한을 추가하면 됩니다.



  5. 정책을 추가하기 위해 AWS 관리 콘솔의 IAM 서비스로 이동하고, CodeBuild에 부여된 Role을 찾고, 기존 Policy에서 Edit policy 버튼을 클릭합니다.


  6. 아래와 같이 Add ARN을 통해 해당 버킷에 대한 정보를 입력합니다.

  7. ARN 정보는 다음과 같이 입력합니다. arn:aws:s3:::aws301-devops-01012345678/* 여기서 계정번호에 따라서 다르게 입력하셔야 합니다. Add 버튼을 클릭합니다.


  8. 다음과 같이 설정이 되었으면 Review policy 버튼을 클릭합니다.


  9. Save changes 버튼을 클릭하여 저장합니다.


  10. 다시 CodePipeline 재가동합니다. Pipeline에서 Build Stage의 우측 상단의 Retry 버튼을 클릭합니다.


  11. 아래와 같이 재기동 되는 걸 볼 수 있습니다.


  12. 정상적으로 구동되는 모습을 볼 수 있습니다.


배포를 위한 Role 생성

  1. CloudFormation을 통해서 배포를 하기 위해서는 Role이 필요합니다. IAM 서비스로 이동한 다음 Create Role 버튼을 클릭합니다.

이 Role은 CloudFormation이 사용할 것이므로 아래와 같이 AWS service 를 선택하고, CloudFormation 을 선택하고 Next: Permissions 버튼을 클릭합니다.

실습의 효율을 위해 AdministratorAccess 정책을 부여합니다. (실습을 위함입니다) Next: Tags 버튼을 클릭합니다. 다음 화면에서 Next: Review 를 클릭합니다.

Role Name에는  AWS301-DevOps-CloudFormation-Role 을 입력하고 Create role 버튼을 클릭합니다.

배포를 위한 파이프라인 수정

  1. 배포를 수행하도록 파이프라린을 수정합니다. Edit 버튼을 클릭합니다.


  2. 파이프라인 하단의 + Add Stage 버튼을 클릭합니다.


  3. 팝업에서 Stage name에는 Deploy 를 입력하고, Add stage 버튼을 클릭합니다.


  4. + Add action group 버튼을 클릭합니다.


  5. 팝업이 열리면, 아래와 같이 Action group을 추가합니다. Action name은 CreateChangeSet , Stack name은 AWS301-DevOps-prod 이며, 아직 생선 전이기 때문에 찾기에 활성화 되어 있지 않으므로 직접 복사해서 붙여 넣으세요.


  6. 바로 하단에 + Add action group 버튼을 클릭합니다.


  7. 아래와 같이 ExecuteChangeSet 을 하나 생성합니다.


  8. 배포 파이프 라인 생성 작업이 완료되었습니다. 상단의 Save 버튼을 클릭합니다.


  9. 팝업이 열리면, Save 버튼을 클릭합니다.


파이프라인 실행

  1. 파이프라인의 Release change 버튼을 클릭하여 파이프라인을 재실행합니다.


  2. 팝업이 열리면 Release 버튼을 클릭합니다.


  3. 다시 배포 파이프라인을 따라서 아래와 같이 배포가 진행되는 것을 볼 수 있습니다.
       

  4. 배포가 완료되면 CloudFormation을 통해서 API가 배포된 Endpoint URL을 확인하여 테스트 합니다. ExecuteChangeSet의 Details 버튼을 클릭하여 배포 결과물을 확인합니다.


API Gateway 접속 테스트

CloudFormation에 배포 결과물 확인

  1. 아래와 같이 CloudFormation에 배포 Stack이 추가된 것을 확인할 수 있습니다. Resources 탭을 클릭하고 하단의 ServerlessRestApi  로 기재된 우측의 파란색 링크를 클릭하여 새창을 엽니다.

API Gateway의 배포 URL 확인

  1. 배포되어 있는 API를 선택하고 Stages 탭으로 이동합니다. Prod 스테이지를 클릭하면 배포되어 있는 Invoke URL 을 확인할 수 있습니다. 해당 URL을 클릭합니다.


  2. 아래와 같이 메시지가 나오는 것을 확인할 수 있습니다.


Canary 배포 적용

코드 수정

Lambda 코드 수정

  1. Lambda 코드를 수정하여 새로운 버전의 API를 만들어 보겠습니다. Cloud9에서 index.js 파일을 열고 기존 "Hello, AWS!"를 " Hello, DevOps! "로 변경합니다. Ctrl + S 를 눌러 저장합니다.

SAM 템플릿 수정

  1. 아래와 같이 Canary 배포를 위한 코드를 넣고 Ctrl +s 를 눌러 저장합니다. 5분간 10퍼센트의 트래픽만 변경된 버전으로 흐릅니다.

    Canary 배포를 위한 SAM 템플릿 수정
    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: AWS DevOps 301 Demo Application
    
    Resources:
      ApiAppFunction:
        Type: AWS::Serverless::Function
        Properties:
          Handler: index.handler
          Runtime: nodejs14.x
          Timeout: 5
          AutoPublishAlias: live
          DeploymentPreference: 
            Enabled: true
            Type: Canary10Percent5Minutes
          Events:
            RootHandler:
              Type: Api
              Properties:
                Path: /
                Method: GET

변경된 코드 체크인

  1. 아래와 같이 변경된 코드를 체크인 합니다.

    변경된 코드 체크인
    git add .
    git commit -am "Canary deploy"
    git push origin master


CodePipeline에서 배포 상황 확인

코드가 체크인 되면 CodePipeline은 자동으로 CI/CD 작업을 수행합니다.


배포가 진행되는 동안 ExecuteChangeSet은 대기를 하게 됩니다. 이때, Canary 배포가 진행중이므로 아래로 내려가서 트래픽이 바뀌는지 테스트를 진행합니다.

CodeDeploy 서비스에서 확인

Canary 배포 확인

  1. Canary 배포가 정상적으로 되는지 확인합니다. 배포가 진행중이면 클릭합니다.


  2. 배포가 진행중인 것을 확인할 수 있습니다.


테스트

  1. Cloud9에서 정상적으로 API가 동작하는지 살펴 봅니다. 아래와 같은 명령을 수행합니다. API 주소는 본인이 배포된 URL로 변경합니다.

    for ((i=1;i<=100;i++)); do curl "https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod"; echo ; sleep 0.1; done



  2. 5분이 지나면, 배포가 모두 완료되고 트래픽은 새로운 버전으로 100% 전환됩니다.



  3. CodeDeploy가 배포되는 중에 Stop and roll back deployment 버튼을 클릭하여 배포가 중단되도록 테스트 해 보세요.


CleanUp

Code 서비스를 이용한 서버리스 서비스 CICD 배포 프로세스를 만들 수 있게 되었습니다.

이제 추가 비용 방지를 위해서 스택을 정리합니다.

  • Cloud9 인스턴스제거
  • CloudFormation에서 생성된 스택제거 (AWS301-DevOps-prod)
  • S3 버킷제거(aws301-devops-xxxxxxxxxxxx, codepipeline-ap-northeast-1-xxxxxxxxxxxx)
  • CodePipelinePipeline 제거 (AWS301-Pipeline)
  • CodeBuildProject 제거 (AWS301Build)
  • CodeCommitRepository 제거 (AWS301Repo)
  • IAM에서 Role 삭제 (AWSCodePipelineServiceRole-ap-northeast-1-AWS301-Pipeline, cwe-role-ap-northeast-1-AWS301-Pipeline, codebuild-AWS301Build-service-role, AWS301-DevOps-CloudFormation-Role)
  • Lambda, API Gateway은 CloudFormation 제거시 제거됩니다.




  • 레이블 없음