ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 9. 개발자 툴
    Technique/AWS 2021. 5. 6. 23:18
    반응형

    AWS 에서의 지속적인 애플리케이션 개발 지원 서비스

    애플리케이션은 한번 만들어 지면 끝이 아니다. 사용자의 목소리를 들으면서 새로운 기능을 추가하거나, 보고된 문제를 수정하거나 하는 것으로 지속적으로 애플리케이션의 가치를 높여가는 것이 중요하다.

    그러므로 소스 코드를 빌드 하거나, 유닛 테스트를 실행하는 등의 개발 프로세스의 자동화를 고려할 필요가 있다. 그러한 고민에서 등장한 것이 계속적 인터그레이션 (CI) 계속적 딜리버리 (CD) 이다. 이를 위한 환경, CI/CD 환경을 매니지드 서비스로서 제공하고 있는 것이 Code 시리즈이다.

    Code 시리즈의 요소와 각 서비스의 역할

    먼저 Code 시리즈에 대해서 간단히 알아볼 필요가 있다. Code 시리즈에는 다음 5가지 서비스가 있다.

    • Code Commit : 소스 코드를 관리하는 Git 저장소 서비스
    • Code Build : 소스 코드 빌드, 테스팅 서비스
    • Code Deploy : 빌드된 모듈 (아티펙트) 디프로이 서비스
    • Code Pipeline : 위 3가지 서비스를 묶어 일련의 개발 프로세스를 자동화 하는 서비스
    • Code Star : 위 4가지 서비스를 이용하여 CI/CD호나경을 자동으로 구축하는 서비스

    Code Star를 제외한 각 서비스의 관계를 그림으로 나타내면 아래와 같다.

    Code 시리즈의 이용 이미지

    Code Star
    CodeStar 는 Code 시리즈를 사용하여 CI/CD 환경을 자동적으로 만들어주는 서비스이다. CI/CD 환경 뿐만 아니라, 애플리케이션 실행환경도 자동적으로 구축해준다.
    예를 들어 아래와 같은 환경을 자동으로 구축해준다.
    - Elastic Beanstalk 로 환경을 구추갛여 그 위에  Ruby on Rails 프로젝트를 기동 시킨다.
    - Python 으로 작성한 프로그램을 Lambda 위에 동작시키는 서버레스 환경을 구축한다.
    - EC2 상의 PHP Laravel 프레임워크를 동작 시킨다.
    애플리케이션의 실행 환경과 CI/CD 환경을 간단히 준비 가능하기 떄문에, 빠르게 애플리케이션 개발을 시작할 수 있다. 특히 팀의 구성이 애플리케이션 엔지니어 중심으로 이뤄진 경우, AWS 의 베스트 프렉티스에 따라 인프라 호나경을 구축 가능한 이점을 들 수 있다. 우선 CodeStar로 Code 시리즈를 사용하여 각 서비스의 상세한 커스터마이즈 방법을 생각해 보는 것도 좋다.

    Code Commit

    CodeCommit는 소스 코드 관리를 위한 Git 저장소 서비스를 제공하는 Managed Service이다. 팀에서 애플리케이션을 개발해 나갈 때 소스 코드를 버전 관리하는 것은 이제 당연하지만, 특히 최근에는 Git을 이용하는 것이 사실상 표준이라 할 수 있다. Git의 저장소를 준비하는 경우 크게 다음과 같은 2가지 방식이 있다.

    1. 사전에 서버 상에 도입한다.
    2. SaaS를 이용한다.

    첫 방법은 자신이 준비한 서버상에 Git 저장소를 호스팅 하기 때문에 폐쇄적인 환경에서 Git을 사용할 수 있다 는 장점이 있다. 그러나 서버 보수나 소프트웨어 업데이트 등을 직접 해야 하기 때문에, 관리 공수가 소모되는 단점이 있다.

    SaaS를 이용하면 서버 유지 관리 작업에 공수가 걸리지 않기 때문에, 본래 원하는 개발 업무에 인적 자원을 할당할 수 있다. 세상에는 Git 레포지토리를 제공하는 SaaS가 몇가지 있으며, Code Commit 도 그 중 하나이다.

    Code Commit의 특징

    IAM유저를 이용한 권한 관리

    먼저 Code Commit의 특징은 IAM 사용자를 이용하여 권한 관리를 한다는 점을 들 수 있다. 예를 들어 HTTPS 방식으로 접근하는 경우에는 CLI 명령어를 이용하여 로컬 환경에 있는 IAM의 Credential 정보를 이용하여 Git 저장소에 접속할 수 있다.

     

    SSH 로 접속하는 경우에는 터미널 사엥서 비밀키와 공개키 페어를 작성하고, 공개키를 매니지먼트 콘솔에서 IAM사용자에게 결합함으로써 Git 저장소에 접속한다. 개발에 종사하는 멤버 전원의 IAM사용자를 보유하고 있다면, Git 레포지토리 용 유저 관리를 하지 않아도 되는 점이 이점이라 할 수 있다.

    다른 AWS 서비스와의 연계

    AWS의 서비스에서 Git 저장소를 운용하는 장점으로는 다른 AWS 서비스와 매끄럽게 연계할 수 있다는 점을 들 수 있다. 웹 설정화면을 보면 알 수 있듯, Git 저장소에서 어떤 이벤트가 발생했을 때, 트리거를 통해 SNS토픽을 호출할 수 있다. SNS 토픽을 통해 다른 AWS 서비스를 킥 할 수 있으며 이를 통해 다양한 연계가 가능하다.

    또한 뒤에서 해설할 Code Pipeline 이나 기타 Code 서비스와의 조합으로 CI/CD 환경을 간단히 구축할 수 있다. Code Commit 에 새로운 소스 코드를 Push 하면 자동으로 그것을 빌드하여 자동으로 유닛 테스트를 실행하며, 이후 자동으로 개발 환경에 데프로이 하는 등의 연계를 간단히 설정할 수 있다.

    Pull Request 기능의 제공

    팀에서 소프트웨어 개발을 하는 경우, 코드 레뷰에 의한 품질 담보가 매우 중요하다. 그 코드 리뷰를 지원하기 위해 Pull Request라는 기능이 있다.

    소스 코드의 어느 부분이 수정되었는지를 Diff 표시 하거나, 누군가 해당 수정을 승인하거나, 누군가 수정이 필요하다고 코멘트를 하거나 하는 등과 같은 커뮤니케이션을 지원한다. 현재에는 팀 개발시 반드시 필요한 기능인 이 Pull Request 기능은 Code Commit에는 2017년 11월 부터 업데이트 되어 지원되고 있다.

    Code Build

    Code Build 는 말 그대로 소스 코드의 컴파일, 빌드 환경을 제공하는 매니지드 서비스이다. 지속적인 개발 프로세스에는 최신 코드를 빌드하여 실행할 수 있는 형태로 만들기 까지의 흐름을 자동화 하는 경우가 많다. 이를 위해 빌드용 서버를 조달하고, Jenkins와 같은 소프트 웨어를 도입하여 빌드 환경을 만들어야 한다.

    그러나 그런 환경은 관리가 필요하지만, 빌드할 때 한번 밖에 사용하지 않는 환경을 위한 인프라 리소스를 지속적으로 확보해두어야 하는 것과 같은 과제가 남아 있다. 이 과제를 해결하기 위하여 SaaS 서비스가 여러가지 나타났는데, Code Build 도 이중 하나이다. 

    Code Build 의 특징

    빌드 환경을 간단히 구축 가능

    Code Build는 빌드 환경을 손쉽게 구축, 운용할 수 있는 매니지드 서비스이다. 관리 콘솔에서 몇 단계만 거치면 간단히 빌드 환경을 구축할 수 있다. 또한 Code Build 상에서 유닛 테스트를 실행할 수 있으며, 지속적인 품질 담보에도 기여한다. 빌드 환경의 런타임 으로서 Java 나 PHP, Python, Ruby, Node.js 등을 표준으로 서포트 하는 것 외에도 개인이 준비한 Docker 이미지를 이용할 수도 있다.

    빌드 대상 소스 코드를 취득하는 곳으로는 Code Commit은 물론이며, 외부 프로바이더인 Github 나 Bitbucket를 선택할 수도 있다. S3에서 취득하는 것도 가능하기 때문에, 소스 프로바이더로 대응하지 않는 저장소를 사용할 경우에는 S3에 전송하여 접근할 수 있다.

    빌드 정의는 buildspec.yml에 작성한다.

    Code Build 에서 제공되는 빌드 환경에서 무엇을 할 것인지는 설정 파일인  buildspec.yml에 정의한다. 이 설정 파일에는 다음의 내용이 포함되어 있다.

    • 빌드 환경의 기본 정보
    • 빌드, 유닛 테스트 실행 명령어
    • 빌드 전 후의 실행하고 싶은 처리
    • 빌드 후의 출력 정보

    참고용으로는 AWS 가 제공하고 있는 샘플 buildspec.yml 파일을 제공하기에 이것을 참고하는 것이 좋다.

    version: 0.2
    
    run-as: Linux-user-name
    
    env:
      shell: shell-tag
      variables:
        key: "value"
        key: "value"
      parameter-store:
        key: "value"
        key: "value"
      exported-variables:
        - variable
        - variable
      secrets-manager:
        key: secret-id:json-key:version-stage:version-id
      git-credential-helper: no | yes
    
    proxy:
      upload-artifacts: no | yes
      logs: no | yes
    
    batch:
      fast-fail: false | true
      # build-list:
      # build-matrix:
      # build-graph:
            
    phases:
      install:
        run-as: Linux-user-name
        on-failure: ABORT | CONTINUE
        runtime-versions:
          runtime: version
          runtime: version
        commands:
          - command
          - command
        finally:
          - command
          - command
      pre_build:
        run-as: Linux-user-name
        on-failure: ABORT | CONTINUE
        commands:
          - command
          - command
        finally:
          - command
          - command
      build:
        run-as: Linux-user-name
        on-failure: ABORT | CONTINUE
        commands:
          - command
          - command
        finally:
          - command
          - command
      post_build:
        run-as: Linux-user-name
        on-failure: ABORT | CONTINUE
        commands:
          - command
          - command
        finally:
          - command
          - command
    reports:
      report-group-name-or-arn:
        files:
          - location
          - location
        base-directory: location
        discard-paths: no | yes
        file-format: report-format
    artifacts:
      files:
        - location
        - location
      name: artifact-name
      discard-paths: no | yes
      base-directory: location
      exclude-paths: excluded paths
      enable-symlinks: no | yes
      s3-prefix: prefix
      secondary-artifacts:
        artifactIdentifier:
          files:
            - location
            - location
          name: secondary-artifact-name
          discard-paths: no | yes
          base-directory: location
        artifactIdentifier:
          files:
            - location
            - location
          discard-paths: no | yes
          base-directory: location
    cache:
      paths:
        - path
        - path

    요금과 종량 과금제

    신경이 쓰이는 것이 요금 체계인데, 빌드에 걸린 시간단위로 종량 과금이 발생하는 방식이다. Code Build 로 선택한 환경이 스펙에 따라 아래의 요금 체계에 따르고 있다.

    컴퓨팅 인스턴스 유형  메모리 vCPU 빌드당 Linux 요금 빌드당 Linux 요금
    general1.small 3 GB 2 0.005 USD 해당 사항 없음
    general1.medium 7 GB 4 0.01 USD 해당 사항 없음
    general1.large 15 GB 8 0.02 USD 해당 사항 없음
    general1.2xlarge 144 GiB 72 0.25 USD 해당 사항 없음
    gpu1.large 244 GiB 32 0.90 USD 해당 사항 없음

    종량 과금이므로 과제중 하나인 인프라 자원을 사용하지 않는 동안의 비용을 신경 쓰지 않아도 된다. 또한 애플리케이션이 성장함에 따라 빌드 부하가 높아지는 타이밍에 환경의 스펙을 높이는 것이 가능하다. 개발 시작 부터 높은 스펙의 자원을 준비하지 않아도 된다는 것도 코스트 메리트중 하나라 할 수 있다.

    Code Deploy

    Code Deploy는 이미 빌드된 모듈 (아티팩트)의 서버에 대한 디프로이를 자동화 하는 서비스이다. 운용중인 시스템에 새로운 모듈을 디프로이 하려면 다양한 방법을 강구해야 한다. 예를들어 여러 대의 웹 서버에 모듈을 디플로이 할 경우에는 한꺼번에 모든 서버에 디프로이 하는 것이 아니라, 조금씩 시스템을 정지시키지 않고, 디프로이하고 싶은 희망이 많다. 이 경우 로드밸런서에 물려 있는 서버를 조금씩 분리하여 디프로이하고 다시 로드 밸런서에서 연결하는 식의 방법이 필요하다. 

     

    또한 조금씩 디프로이 함으로써 시작한 것은 좋지만, 중간에 새로운 모듈에서 문제가 발견되었을 경우에 대비하여 롤백을 고려해야 한다. 이 작업에 대해서도 방식을 검토하거나, 복구용 스크립트를 준비하거나 등의 절차를 준비할 필요가 있다.

     

    Code Deploy에는 이런 디프로이 작업에서 발생하는 고민을 해결할 수 있는 기능들이 준비되어 있다. Code Deploy를 사용하여 디프로이를 위한 작업량을 줄일 수 있으며, 비즈니스와 직결되는 기능 개발에 좀 더 집중할 수 있다. 이땐 Code Deploy의 기능에 대해 알아보자.

    Code Deploy의 특징

    데프로이 서버를 선택 가능

    Code Deploy는 EC2나 Lambda그리고 온프레미스의 서버에 모듈을 디프로이 할 수 있다.  EC2 및 온프레미스 서버를 대상으로 하는 경우 대상 서버에 Code Deploy 에이전트를 설치할 필요가 있다. 디프로이시에 어떤 모듈을 어디에 배치할 것인가와 같은 설정은 appspec.yml에 정의한다.

    version: 0.0
    Resources:
      - TargetService:
          Type: AWS::ECS::Service
          Properties:
            TaskDefinition: "arn:aws:ecs:us-east-1:111222333444:task-definition/my-task-definition-family-name:1"
            LoadBalancerInfo:
              ContainerName: "SampleApplicationName"
              ContainerPort: 80
    # Optional properties
            PlatformVersion: "LATEST"
            NetworkConfiguration:
              AwsvpcConfiguration:
                Subnets: ["subnet-1234abcd","subnet-5678abcd"]
                SecurityGroups: ["sg-12345678"]
                AssignPublicIp: "ENABLED"
            CapacityProviderStrategy:
              - Base: 1
                CapacityProvider: "FARGATE_SPOT"
                Weight: 2
              - Base: 0
                CapacityProvider: "FARGATE"
                Weight: 1
    Hooks:
      - BeforeInstall: "LambdaFunctionToValidateBeforeInstall"
      - AfterInstall: "LambdaFunctionToValidateAfterInstall"
      - AfterAllowTestTraffic: "LambdaFunctionToValidateAfterTestTrafficStarts"
      - BeforeAllowTraffic: "LambdaFunctionToValidateBeforeAllowingProductionTraffic"
      - AfterAllowTraffic: "LambdaFunctionToValidateAfterAllowingProductionTraffic"

    디프로이처리의 앞뒤에 무언가 처리를 넣고 싶은 경우에는 해당 appspec.yml의 hooks 에리어에 정의하는 것으로 해결 할 수 있다. 

    데프로이 방식의 선택가능

    시스템의 서비스 수준에 따라서 무정지로 새로운 기능을 디프로이 하는 것이 요구되는 경우도 있다. 이런 요건에 대응할 수 있도록 Code Deploy에서는 몇가지 디프로이 방법을 준비하고 있다.

     

    그외 [정상적으로 가동하고 있는 호스트 수가 3개 이상을 유지한다] [정상적으로 가동하고 있는 호스트 수가 전체 25%이상을 유지한다] 와 같은 독자적인 디프로이 설정을 작성하는 것도 가능하다. 또한 [프로이 실패했을 때에 롤백한다] 기능을 유효하게 하는 것으로 디프로이에 실패했을 경우의 되돌림을 자동으로 실시할 수 있다.

    디프로이 방식 구체적인 동작
    AllAtOnce 관련된 서버 전체에 동시에 디프로이를 실시한다. 반영 시간이 가장 빠르지만, 시스템 전체적으로 다운타임이 발생한다.
    HalfAtATime 관련된 서버군의 반틈의 리소스에 대하여 디프로이를 행한다. 디프로이전에 대상의 서버를 로드 밸런서로 부터 분리하기 때무넹, 디프로이중에는 남은 반의 서버로 운용된다. 반틈의 리소스라고 해더라도 높은 부하가 걸리지 않도록 디프로이 설계를 하는 것이 중요하다.
    OneAtATime 관련된 서버

    데프로이 대상의 서버가 증감하는 경우의 대응

    데프로이 구조를 사전에 구축할 경우 서버 수가 증감 했을 때 대응이 필요하다. 특히 Auto Scailng을 준비해서 동적으로 서버수가 바뀌는 구성을 채택하고 있는 경우에는 이 설계의 난이도가 높아진다. Code Deploy는 Auto Scailng 그룹을 디프로이 대상으로 선택 가능하기 떄문에, 이 문제를 쉽게 해결할 수 있다.

    Code Pipeline

    지금까지 Code 시리즈로 Code Commit, Code Build, Code Deploy에 대해 알아보았다. 이들 관리 서비스를 이용함으로써, 소스 코드 관리, 빌드, 서버에 대한 디프로이 각각을 쉽게 작성할 수 있게 되었다. 하지만

    • 소스 코드가 변경 된 것을 감지하고 빌드
    • 빌드의 완료를 통해 검증 환경에 디프로이 한다.

    와 같은 앞선 작업이 끝난 것을 감지하고, 그 후속 작업을 실시하는 부분에 대해서는 아직 사람의 개입이 필요한 상태이다. 개발이 계속 되는 한, 이 일련의 작업을 몇번이나 반복하게 되므로, 사이클 전체를 자동화 하고 싶을때 이런 문제들이 아직 과제로 남아 있다. 이러한 요청에 대응할 수 있는 것이 Code Pipeline이다.

    Code Pipeline의 특징

    개발 프로세스 자동화

    Code Pipeline을 사용함으로 써

    • 소스코드의 Push
    • Push를 감지하고  → 소스 코드의 빌드
    • 빌드가 완료된 것을 감지하고 → 아티펙트의 디프로이

    라고 하는 자동화된 파이프라인을 작성할 수 있다. 이 파이프라인은 웹 페이지상에선 가시화 되므로, 현재 어떤 작업이 진행되고 있는지 한눈에 이해, 확인 할 수 있다.

     

    지금 까지 Code 시리즈를 사용하는 전제로 설명을 해 왔는데, 일부 프로세스를 AWS 이외의 서비스로 변경하여 이용할 수도 있다. 예를 들어 소스 코드 취득처를 Github 리포지토리로 설정하거나, 빌드나 테스팅 부분을 Jenkins 에게 맡길 수 있다. 개발 프로세스의 일부가 이미 있다면 부족한 부분을 Code 시리즈로 채운 다음 Code Pipeline으로 자동화하는 방법도 가능하다.

    승인 프로세스를 정의 하는 것도 가능

    Code Pipeline에서는 리리스 승인 프로세스를 파이프라인 중간에 끼울 수 있다. 예를 들어 개발팀 내에서의 테스트가 끝난 후, 리리스 승인자에게 UAT(User Acceptance Test : 유저 수락 테스트 )를 의뢰하는 Usecase가 있을 것이다. Code Pipeline에서는 다음과 같이 승인 (Approval) 프로세스를 정의할 수 있다.

    • 개발 환경에 출시할 때 까지는 자동으로 실행한다.
    • UAT 환경에 대한 리리스 직전에 승인자에게 메일을 송신하여 승인자가 승인할 때 까지 파이프라인의 처리를 정지한다.
    • 승인자가 승인한 타이밍에 UAT환경에 리리스를 실시한다.

     

     

    반응형

    댓글

Designed by Tistory.