ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CI/CD] Travis CI를 활용한 배포 자동화 (2)
    Programming/infra 2021. 6. 27. 19:23

    이전 글

    [CI/CD] Travis CI를 활용한 배포 자동화 (1)


    이전 글에서는 단순히 프로젝트를 빌드하는 과정까지만 진행하였다. spring boot 프로젝트의 경우 보통 빌드가 완료되면 내장 톰캣이 들어있는 jar 파일이 생성된다. 배포가 의미하는 것은 해당 jar 파일이 특정한 서버에서 운영되어야 한다. 이번에는 빌드가 완료된 jar 파일을 AWS에서 제공하는 파일 서버에 연동해보려 한다.


    Amazon S3 

    아마존 웹 서비스에서 제공하는 온라인 스토리지 웹 서비스이다. s3가 의미하는 것은 Simple Strorage Service의 각 단어의 맨 앞 글자 s 3개를 의미한다. 

     

    Travis 서버에서 생성된 jar 파일을 S3에 전달해야 한다. 이유는 실제 배포는 AWS의 CodeDeploy를 통해 이루어진다. 하지만 이런 CodeDeploy는 파일을 저장할 수 있는 기능을 가지고 있지 않다. 그렇기 때문에 배포에 필요한 파일을 별도 보관할 수 있는 공간이 필요한데 그것이 바로 S3이다.

     

    우선 Travis CI와 AWS S3을 연동해야 한다. 일반적으로 AWS 서비스는 Travis와 같은 외부 서비스가 접근할 수 없다. 접근 가능한 권한을 가진 key를 생성해서 사용해야 한다. AWS에서 이러한 인증 관련된 기능은 IAM(Identity and Access Management)에서 제공된다.


    IAM

    우선 AWS 로그인을 진행하고 IAM에 이동한다.

    사용자 추가를 눌러 생성할 사용자의 이름과 엑세스 유형을 선택한다.  

    권한 설정에서 기존 정책 직접 연결을 클릭하고 AmazonS3FullAccess와 AWSCodeDeployFullAccess 권한을 추가한다.

    선택 사항으로 적절히 태그를 추가해준다.

    마지막으로 검토한 후 사용자 만들기를 클릭한다.

    생성이 완료되면 엑세스 키 ID와 비밀 엑세스 키를 확인할 수 있다. 이 두 가지의 값이 Travis CI의 환경 변수로 등록되어 AWS의 접근을 허용하게 해주는 key 역할을 하게 된다.


    Travis CI

    이제 생성한 key를 활용해서 Travis CI에 설정해 주어야 한다.

    등록되어 있는 repository에 settings를 클릭한다. 

     

    Enviroment Variables에 아까 발급 받은 엑세스 키를 각각 등록 시켜준다. 이렇게 등록된 값들은 .travis.yml에서 자유롭게 사용할 수 있다.


    S3 버킷

    S3는 순수하게 파일 서버의 역할을 한다. 단순히 파일을 저장하고 접근하며 검색할 수 있다. 이제 이러한 S3에 Travis로 빌드된 파일을 저장하는 것을 진행하려 한다.

     

    우선 AWS의 로그인하고 S3를 검색하고 접속한다.

    버킷 만들기를 클릭한다.

    한 가지 중요한 것은 모든 퍼블릭 엑세스를 차단해야 한다. 나머지는 기호에 맞게 설정하고 버킷을 생성한다.

    버킷이 생성되면 이제 배포 파일을 전달하기 위한 설정을 해야 한다.

     

    .travis.yml

    # 언어와 jdk의 버전을 지정한다.
    language: java
    jdk:
      - openjdk11
    
    # 어느 브랜치가 push 될 때 수행할지 지정한다. 
    # 오직 main 브랜치가 push될 때 수행하도록 지정하였다.
    branches:
      only:
        - main
    
    # 빌드 전에 gradlew의 권한을 추가한다.
    before_install:
      - chmod +x gradlew
    
    # Travis CI 서버의 Home
    # gradle을 통하여 의존성을 받게 되면 이를 캐시하여 배포할 때 마다 다시 받지 않도록 설정한다.
    cache:
      directories:
        - '$HOME/.m2/repository'
        - '$HOME/.gradle'
    
    # main 브랜치에 push 되면 수행되는 명령어이다. 
    # 프로젝트 내에 권한이 추가된 gradlew를 활용하여 clean, build를 진행한다.
    script: "./gradlew clean build"
    
    ## 새롭게 추가된 부분
    before_deploy:
      # 현재 위치의 모든 파일을 springboot-test로 압축한다.
      - zip -r springboot-test * 
      # deploy 디렉토리를 Travis가 실행 중인 위치에 생성한다.
      - mkdir -p deploy
      # 생성한 .zip 파일을 deploy 아래로 이동한다.
      - mv springboot-test.zip deploy/springboot-test.zip
    
    # 외부 서비스와 연동할 행위들을 선언한다.
    deploy: 
      - provider: s3
        access_key_id: $AWS_ACCESS_KEY # Travis settings에 설정된 값
        secret_access_key: $AWS_SECRET_KEY # Travis settings에 설정된 값
        bucket: S3버킷이름 # S3 버킷
        region: ap-northeast-2
        skip_cleanup: true
        acl: private # zip 파일 접근을 private으로
        local_dir: deploy # before_deploy에서 생성한 디렉토리로 이동한다. 해당 위치의 파일만 이동시킨다.
        wait-until-deployed: true
        on:
          branch: main
    ## 새롭게 추가된 부분
    
    # CI 실행 완료 시 작성한 이메일로 알람
    notifications:
      email:
        recipients:
          - dev.hyeonic@gmail.com

    모든 설정이 완료되면 commit & push를 진행한다. 빌드가 성공적으로 이루어지면 S3에 생성된 파일을 확인할 수 있다. 


    CodeDeploy

    codeDeploy를 활용하여 ec2에 배포하기 위해서는 ec2가 codeDeploy를 연동 받을 수 있도록 IAM의 역할을 추가해줘야 한다.

     

    IAM의 사용자와 역할의 차이

    역할 - AWS 서비스에만 할당할 수 있는 권한. EC2, CodeDeploy 등이 이에 해당한다.

    사용자 - AWS 사용자 외에 사용할 수 있는 권한. 로컬 PC나 IDC 서버 등이 이에 해당한다.

     

    CodeDeploy의 경우 AWS 서비스인 ec2를 사용할 것이기 때문에 역할로 처리한다.

    역할 만들기를 클릭한다.

    AWS 서비스를 클릭한다.

    EC2를 클릭하고 다음: 권한을 클릭한다.

    EC2RoleForAWSCodeDeploy를 선택하고 넘어간다.

    기호에 맞게 태그를 추가한다.

    역할의 이름을 입력하고 생성한다.

     

    이제 생성한 역할을 ec2에 등록해야 한다. ec2 서비스에 생성된 인스턴스를 우클릭한다.

    보안 - IAM 역할 수정을 클릭한다.

    위에서 생성한 역할을 선택한다. 역할 수정 까지 완료되면 해당 인스턴스를 재부팅한다.

     

    이제 ec2에 접속해서 다음 명령어를 입력한다.

    aws s3 cp s3://asw-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2

    다운받은 파일에 실행 권한을 추가해준다.

    chmod +x ./install

    실행 권한이 추가된 것을 확인하였다. 해당 install 파일로 설치를 진행한다.

    sudo ./install auto

    codedeploy-agent 설치가 완료되면 정상적으로 실행되고 있는지 확인한다.

    지금까지는 ec2가 codedeploy에게 연동받을 수 있도록 설정을 진행하였다. 이제 codeDeploy에서 ec2에 접근하기 위한 설정과 권한을 추가해야 한다.

     

    codeDeploy도 AWS의 서비스이기 때문에 IAM 역할을 생성해줘야 한다.

    또는 서비스를 선택하여 해당 서비스의 사용 사례 확인에서 CodeDeploy를 선택한다.

    CodeDploy를 선택하고 다음으로 넘어간다.

    AWSCodeDeployRole을 클릭하여 다음으로 넘어간다.

    기호에 맞게 태그를 추가한다. 작성한 내용을 확인한 후 생성을 완료한다.

     

    이제 권한 설정이 완료되었다! CodeDeploy를 생성할 차례이다.


    CodeDeploy 생성

    AWS에서 CodeDeploy 서비스로 이동한다.

    애플리케이션 생성을 클릭한다.

    생성이 완료되면 배포 그룹을 생성한다.

    배포 그룹 생성을 위해 해당 버튼을 클릭한다.

    배포 그룹 이름을 입력하고 서비스 역할은 아까 생성한 역할을 선택한다. 

     

    배포 유형은 배포할 서비스가 2대 이상이면 블루/그린을 선택하고 아니라면 현재 위치를 선택한다.

    환경 구성에서 Amazon EC2 인스턴스를 클릭한다. 추가적으로 기호에 따라 태그를 작성한다.

     

    배포 구성을 선택하고 로드 밸런서 체크를 해제한다. 배포 그룹 생성을 클릭하면 배포 그룹 생성이 완료된다.


    Travis CI, S3, CodeDeploy 연동

    우선 ec2에 S3에서 넘겨줄 zip 파일을 저장할 디렉토리를 하나 생성한다. 

    mkdir ~/app/zip

    Travis CI의 필드가 완료되면 S3에 zip 파일이 전송되고, 이 zip 파일은 /home/ec2-user/app/zip 으로 복사되어 압출을 풀어야 한다. CodeDeploy에 대한 설정은 appspec.yml로 진행해야 한다. appspec.yml의 위치는 아래와 같다.

    appspec.yml

    version: 0.0 # CodeDeploy 버전을 명시한다.
    os: linux 
    files:
      - source:  / # 전체 파일을 나타낸다.
        destination: /home/ec2-user/app/zip/ # source로 지정된 전체 파일이 받을 위치이다.
        overwrite: yes # 기존 파일들이 있으면 덮어 쓸지를 결정한다.

     

    .travis.yml 파일에 CodeDeploy 관련 코드를 추가해야 한다.

    # 언어와 jdk의 버전을 지정한다.
    language: java
    jdk:
      - openjdk11
    
    # 어느 브랜치가 push 될 때 수행할지 지정한다. 
    # 오직 main 브랜치가 push될 때 수행하도록 지정하였다.
    branches:
      only:
        - main
    
    # 빌드 전에 gradlew의 권한을 추가한다.
    before_install:
      - chmod +x gradlew
    
    # Travis CI 서버의 Home
    # gradle을 통하여 의존성을 받게 되면 이를 캐시하여 배포할 때 마다 다시 받지 않도록 설정한다.
    cache:
      directories:
        - '$HOME/.m2/repository'
        - '$HOME/.gradle'
    
    # main 브랜치에 push 되면 수행되는 명령어이다. 
    # 프로젝트 내에 권한이 추가된 gradlew를 활용하여 clean, build를 진행한다.
    script: "./gradlew clean build"
    
    before_deploy:
      # 현재 위치의 모든 파일을 springboot-test로 압축한다.
      - zip -r springboot-test * 
      # deploy 디렉토리를 Travis가 실행 중인 위치에 생성한다.
      - mkdir -p deploy
      # 생성한 .zip 파일을 deploy 아래로 이동한다.
      - mv springboot-test.zip deploy/springboot-test.zip
    
    # 외부 서비스와 연동할 행위들을 선언한다.
    deploy: 
      - provider: s3
        access_key_id: $AWS_ACCESS_KEY # Travis settings에 설정된 값
        secret_access_key: $AWS_SECRET_KEY # Travis settings에 설정된 값
        bucket: S3버킷이름 # S3 버킷
        region: ap-northeast-2
        skip_cleanup: true
        acl: private # zip 파일 접근을 private으로
        local_dir: deploy # before_deploy에서 생성한 디렉토리로 이동한다. 해당 위치의 파일만 이동시킨다.
        wait-until-deployed: true
        on:
          branch: main
          
    ## 새롭게 추가된 부분
      - provider: codedeploy
        access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
        secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
        bucket: skhuedin-build # S3 버킷
        key: skhuedin.zip # 빌드 파일을 압축해서 전달
        bundle_type: zip # 압축 확장자
        application: skhuedin # 웹 콘솔에서 등록한 CodeDeploy 어플리케이션
        deployment_group: skhuedin-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
        region: ap-northeast-2
        wait-until-deployed: true
        on:
          branch: main
    ## 새롭게 추가된 부분
    
    # CI 실행 완료 시 작성한 이메일로 알람
    notifications:
      email:
        recipients:
          - dev.hyeonic@gmail.com

    이제 main branch로 push 하는 순간 Travis CI가 자동으로 실행된다. 완료되면 배포가 수행되는 것을 확인할 수 있다.

    ec2에 ~/app/zip으로 이동하면 해당 파일들이 있는 것을 확인할 수 있다.


    지금까지 Travis CI와 S3, CodeDeploy까지 연동을 완료하였다. 하지만 현재 배포 작업을 따로 진행되지 않기 때문에 직접 서버에 접근하여 해당  파일을 배포해야 한다. 해당 작업은 다음 시간에 마무리할 예정이다.


    References.

     

    [스프링 부트와 AWS로 혼자 구현하는 웹 서비스] 출간 후기

    (출판사: 프리렉, 쪽수: 416, 정가: 22,000원) 서적 링크 오프라인 서점에는 2019.12.04 (수) 부터 올라갈 예정입니다. 강남 교보문고나 광화문 교보문고는 주말에도 올라올 순 있겠지만, 혹시 모르니

    jojoldu.tistory.com

    댓글

Designed by Tistory.