Skip to content

CodeDeploy

Seongbeen Kim edited this page May 24, 2021 · 2 revisions

1. CodeDeploy란?

1. CodeDeploy를 사용하는 이유

  • 안정적으로 변경사항을 운영환경으로 자동 배포하기 위해서
  • 소프트웨어 릴리즈 주기를 더 빠르게 하기 위해서
  • 작게, 자주 배포를 하게 하여 한 번의 배포에 들어가는 비용, 위험을 줄이기 위해서
  • Github, Jenkins, AWS CodePipeline 등과 통합하여 사용 가능
  • 각 배포 버전에 대한 상세한 보고서 제공, 가동 중지 시간 최소화 등 AWS에서 제공하는 유용한 기능들이 많기 때문

2. 설치

  • 환경
    • CI용, CD용 EC2(Amazon Linux 2 AMI) 2대
    • Nginx(1.18.0)
    • Jenkins 2021.5.14 기준 https://pkg.jenkins.io/redhat-stable/ 최신 stable 버전
    • JDK(openjdk version "11.0.11") java-11-amazon-corretto로 설치

1. 배포용 EC2가 CodeDeploy를 연동받을 수 있게 하는 역할 생성

  1. IAM - 역할

    aws iam role
  2. 역할 생성

    • EC2 선택 후, 다음 버튼 클릭
    aws iam role for ec2
  3. 정책 생성

    • AmazonEC2RoleforAWSCodeDeploy 정책 선택 후 다음 버튼 클릭

      aws s3 ec2 role

  4. 태그 추가(선택)

    • 원하는 키, 값 설정

      aws role tag

  5. 역할 검토

    • 3에서 선택한 정책이 제대로 포함되어 있는 지 확인 후 역할 만들기 버튼 클릭하여 생성

      aws role check
  6. 배포용 EC2 인스턴스에 생성한 IAM 연결

    • EC2 - 작업 - 보안 - IAM 역할 수정

    ec2 iam modification

    ec2 iam modification2

    • EC2 재부팅

2. CodeDeploy에서 배포용 EC2에 접근 가능하게 하는 역할 생성

  1. 역할 생성

    codedeploy role add

  2. 정책 생성

    • 옵션이 하나밖에 없으므로 다음으로 넘어가면 된다.

    codedeploy codedeploy role

  3. 태그 추가(선택)

    • 원하는 키, 값 입력

      codedeploy role tag

  4. 역할 검토

    • 2에서 선택한 정책이 제대로 포함되어 있는 지 확인 후 역할 만들기 버튼 클릭하여 생성

      codedeploy role check

3. CodeDeploy 서비스 생성

  1. CodeDeploy 검색 후 사진의 애플리케이션 생성 버튼 클릭

    codedeploy app create

  2. 애플리케이션 이름 입력 및 플랫폼 EC2/온프레미스로 설정 후 생성

    codedeploy app configuration

  3. 배포 그룹 생성

    deploy group create

  4. 배포 그룹 이름 및 서비스 역할

  5. 배포 유형

    • 배포 서버 1대이기 때문에 현재 위치 선택

      • 2대 이상일 경우 블루/그린 선택

      deploy type

  6. 환경 구성

    • Amazio EC2 인스턴스 체크 후, 배포 EC2용 태그의 키, 값을 입력해준다.

      • 배포 서버 1대에 대한 키, 값을 입력해주었으므로 1개의 일치하는 고유한 인스턴스 가 뜨는 것을 볼 수 있다.

      deploy environment

  7. 배포 설정

    • 한 번 배포 시 몇 대의 서버에 배포할 것인지를 결정하는데 배포 서버가 1개이기 때문에 전체 배포하는 AllAtOnce 선택, 로 드 밸런싱 활성화 체크 X

      deploy configuration

5. codedeploy-agent 설치 및 연결

  • 배포용 EC2 접속됐다는 가정하에 진행
  1. aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2 : aws-codedeploy codedeploy 설치 파일 다운로드

    codedeploy download

  2. chmod +x ./install : install 파일에 실행 권한 추가

  3. sudo ./install auto : install 파일로 codedeploy 설치

    • /usr/bin/env: ruby: No such file or directory 라고 출력된다면, sudo yum install -y ruby 를 통해 ruby 설치 후 재입력
  4. sudo service codedeploy-agent status : codedeploy-agent 서비스 상태 확인

    codedeploy-agent status

  5. mkdir ~/app/ && mkdir ~/app/jenkins && mkdir ~/app/jenkins/jar : app, jenkins, jar 폴더 생성

4. 프로젝트 연동

  1. 배포 EC2에서 sudo vim application-prod-db.yml : /home/ec2-user/app경로에 rds 연결을 위한 yml 파일 생성

    spring:
      config:
        activate:
          on-profile: prod-db
      jpa:
        hibernate:
          ddl-auto: none
          dialect: org.hibernate.dialect.MySQL8Dialect
          storage_engine: innodb
      datasource:
        url: jdbc:mysql://EC2주소:3306/DB명?useSSL=false&verifyServerCertificate=false
        username: username
        password: passeword
        driver-class-name: com.mysql.cj.jdbc.Driver
  2. 프로젝트에 kill_process.sh 생성

    #! /bin/bash
    
    echo "> 현재 구동중인 애플리케이션 pid 확인"
    
    CURRENT_PID=$(pgrep -fl kodesalon | grep java | awk '{print $1}';)
    
    echo "현재 구동중인 어플리케이션 pid: $CURRENT_PID"
    
    if [ -z "$CURRENT_PID" ]; then
        echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
    else
        echo "> kill -15 $CURRENT_PID"
        kill -15 $CURRENT_PID
        sleep 5
    fi
    • 기존에 동작하고 있던 서버를 종료하기 위해 필요한 셸 스크립트
    • CURRENT_PID=$(pgrep -fl kodesalon | grep java | awk '{print $1}';) : "kodesalon" 로 되어있는 java 프로세스를 찾은 뒤 ID만 뽑아내어 CURRENT_PID 에 넣어준다.
  3. 프로젝트에 deploy.sh 생성

    #!/bin/bash
    
    REPOSITORY=/home/ec2-user/app/jenkins
    
    echo "> Build 파일 복사"
    
    cp $REPOSITORY/build/libs/*.jar $REPOSITORY/jar/
    
    echo "> 새 어플리케이션 배포"
    
    JAR_NAME=$(ls -tr $REPOSITORY/jar/*.jar | tail -n 1)
    
    echo "> JAR Name: $JAR_NAME"
    
    echo "> $JAR_NAME 에 실행권한 추가"
    
    chmod +x $JAR_NAME
    
    echo "> $JAR_NAME 실행"
    
    nohup java -jar \
        -Dspring.config.location=classpath:/application.yml,/home/ec2-user/app/application-prod-db.yml \
    		-Dlogging.config=classpath:/logback-spring.xml \
        -Dspring.profiles.active=prod \
        $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
    • cp $REPOSITORY/build/libs/*.jar $REPOSITORY/jar/ : $REPOSITORY/build/libs/ 의 jar 파일을 $REPOSITORY/jar/ 로 복사한다.
    • JAR_NAME=$(ls -tr $REPOSITORY/jar/*.jar | tail -n 1) : $REPOSITORY/jar/ 의 jar 파일들을 최종 수정 시간 기준(-t) 역순(-r)으로 나열하고 뒤에서 부터(-n) 첫 번째인 파일의 이름이 JAR_NAME 에 대입된다. 즉, 가장 최신 수정된 jar 파일이 대입된다.
    • chmod +x $JAR_NAME : Jar 파일은 실행 권한이 없는 상태이기 때문에, nohup으로 실행할 수 있게 실행 권한을 부여한다.
    • nohup java -jar \ -Dspring.config.location=classpath:/application.yml,/home/ec2-user/app/application-prod-db.yml \ -Dlogging.config=classpath:/logback-spring.xml \ -Dspring.profiles.active=prod \ $JAR_NAME > $REPOSITORY/nohup.out 2>&1 & : 스프링 설정 파일 위치를 지정하는 Dspring.config.location 을 사용하여, 기본 옵션을 담고 있는 application.yml, rds DB 정보를 담고 있는 application-prod-db.yml 를 지정한다. 또한 log 설정을logback-spring.xml 으로 지정한다.(classpath:/ 는 jar 안에 있는 resources 디렉토리 기준으로 경로가 생성된다고 보면 된다. application-prod-db.yml 는 외부에 있기 때문에 절대 경로 지정)
      • nohup실행 시 CodeDeploy는 무한 대기합니다. 이 이슈를 해결하기 위해 nohub.out파일을 표준 입출력용으로 별도로 사용합니다. 이렇게 하지 않으면 nohup.out파일이 생기지 않고, CodeDeploy 로그에 표준 입출력이 출력됩니다. nohub이 끝나기 전까지 CodeDeploy도 끝나지 않으니 꼭 이렇게 해야합니다 in 스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 명령어에 대해서 간단히 설명하자면 jar 파일 실행 시 발생하는 에러를 표준 출력으로 redirection하여 nohup.out 에 저장시킨다고 보면 된다.
      • nohup으로 jar 파일을 실행시키는 이유는 터미널의 세션 연결이 끊어지더라도 지속적으로 동작 할 수 있게 해주기 위해서이다. 더 자세한 내용은 해당 링크 참조
      • 2>&1 : 표준 오류를 표준 출력으로 redirection한다는 의미이다. &1을 파일 경로로 대체하여 오류 로그를 보관할 수도 있다.
        • ex) 2>/tmp/exampleLog)
        • 0 : 표준 입력(stdin)
        • 1 : 표준 출력(stdout)
        • 2 : 표준 에러(stderr)
        • 표준출력과 표준에러를 분리해서 파일로 저장하고 싶을 때는 아래와 같은 형식을 사용할 수 있다.
          • ex) deploy.sh 1>output.log 2>error.log
      • & : 마지막 &은 백그라운드 작업으로 실행하게 한다.
  4. 프로젝트에 appspec.yml 파일 생성

    • AWS CodeDeploy 설정 파일로, 반드시 프로젝트 최상단에 위치해야 한다.
    version: 0.0
    os: linux
    files:
      - source: /
        destination: /home/ec2-user/app/jenkins
        overwrite: yes
    
    permissions:
      - object: /
        pattern: "**"
        owner: ec2-user
        group: ec2-user
    
    hooks:
      ApplicationStop:
        - location: scripts/kill_process.sh
      ApplicationStart:
        - location: scripts/deploy.sh
          timeout: 60
          runas: ec2-user
    • version : CodeDeploy 버전을 나타내는 것으로, 반드시 0.0으로 설정해야 한다.
    • os : 현재 배포 서버 EC2가 Linux이기 때문에 linux를 적는다.
    • files : 받은 파일을 EC2 어느 장소에 위치 시킬 것인지를 지정하는 곳이다.
      • source : S3 버킷에서 복사할 파일의 위치를 나타내며, / 는 전체 파일을 의미한다고 볼 수 있다.
      • destination : zip 파일을 복사해 압축을 풀 위치를 지정한다.
      • overwrite : 기존에 파일들이 존재할 경우 덮어쓸지를 결정하는 것으로, yes 라고 하여 덮어쓰게 만들었다.
    • permissions : CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 설정한다.
    • hooks : 배포 라이프 사이클에 따라서, 스크립트를 실행하는 곳
      • ApplicationStop : Repository로부터 Application을 다운받기 전 수행되는 라이프사이클 이벤트를 의미한다.
        • location : 실행시킬 스크립트 파일의 위치를 기술하는 곳으로, scripts/kill_process.sh 지정
      • ApplicationStart : ApplicationStop 이벤트에서 종료한 Application을 다시 시작하거나 할 때 사용하는 라이프 사이클 이벤트 입니다.
        • location : 실행시킬 스크립트 파일의 위치를 기술하는 곳으로, scripts/deploy.sh 지정
        • timeout : 60초 이상 수행되면 실패가 되게 설정
        • runas : deploy.sh 을 ec2-user 권한으로 실행하게 설정
  5. IntelliJ application.yml 수정

    spring:
      profiles:
        active: local
    
    ---
    ## 아래 코드 추가
    spring:
      group:
        prod:
          - prod-db
    
    ---
    
    spring:
      config:
        activate:
          on-profile: local
      datasource:
        url: jdbc:h2:mem:test_mem
        driver-class-name: org.h2.Driver
        username: sa
        password:
    • -Dspring.profiles.active = prod 로 실행 시킬 때, 운영 EC2 서버에 있는 application-prod-db 포함하게 설정

5. Jenkins CodeDeploy 연동

  1. Jenkins 관리 - 플러그인 관리

    • CodeDeploy 플러그인 설치
    jenkins codedeploy plugin
  2. 작업 생성

    • Freestyle project로 작업 생성

    jenkins deploy job

  3. 소스 코드 관리

  4. 빌드 유발

    • Github에 push가 되었을 때, Jenkins에 hook을 날려 자동 빌드할 수 있도록 Github hook trigger 선택

      jenkins deploy build trigger

  5. Build

    • 이전 빌드 결과물을 제거 후, 새로 빌드한 jar 파일 생성하기 위해 ./gradlew clean build 입력

    jenkins deploy build

  6. 빌드 후 조치

    • Deploy an application to AWS CodeDeploy 선택하여 아래와 같이 입력

      jenkins deploy after build

      • AWS CodeDeploy Application Name : CodeDeploy 애플리케이션 이름
      • AWS CodeDeploy Deployment Group : CodeDeploy 애플리케이션의 배포 그룹 이름
      • AWS Region : AP_NORTHEAST_2 (서울 Region)
      • S3 Bucket : S3 버킷 이름
      • Include Files : CodeDeploy가 배포 EC2로 옮길 파일들
        • jar 파일 + appspec.yml + scripts/deploy.sh + scripts/kill_process.sh 가 옮겨진다.

      jenkins deploy after build 2

  7. Github hook 설정

    • Github - Repository - Settings - Webhooks에 가서 http://젠킨스 EC2 서버:포트/github-webhook/ 로 입력해주고 아래와 같이 설정 후 생성해주면 된다.

      jenkins deploy webhook

      jenkins deploy webhook created

      • 위와 같이 초록색으로 체크표시가 나야 정상적으로 작동한다는 것을 알 수 있다.

3. 실행 시 결과

  • 지정한 브랜치에 Push시

1. Jenkins 빌드 자동 실행

jenkins deploy test

2. S3 버킷에 저장 확인

jenkins deploy test 2

3. CodeDeploy 배포 성공 확인

jenkins deploy test 3

4. 8080 포트에 java가 실행되는 것 확인

  • sudo netstat -tnlp 입력

    jenkins deploy test 4

5. 브라우저 확인

jenkins deploy test 5

6. CodeDeploy 로그 확인

  • vim /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log

    jenkins deploy test 6

    • Spring Boot 에러 확인은 sudo vim ~/app/jenkins/nohup.out 를 통해 확인하면 된다.

4. 무중단 배포 적용

  • Nginx 1대(80 포트, 443 포트), Spring Boot jar 2대(8081 포트, 8082 포트) 적용할 예정

1. Nginx 연동

  • Nginx는 웹 서버, 리버스 프록시, 캐싱, 로드 밸런싱, 미디어 스트리밍을 위한 오픈소스 소프트웨어로, 현재 Apache를 대체하는 가장 유명한 웹 서버이자 오픈소스다.
  • 외부의 요청을 받아 백엔드 서버로 요청을 전달하는 행위인 리버시 프록시를 사용하여 무중단 배포 환경을 구축한다.
  1. Nginx 설치

참조

CICD - Jenkins와 CodeDeploy를 이용한 CICD 구축하기 - 2 (구축)

Jenkins) AWS Codeploy와 S3, Github를 이용해 Jenkins CI 구축하기(1)

[Devops] Github Action을 사용한 Spring boot & gradle CI/CD 구축 - 2

[AWS] Spring Boot, Jenkins, CodeDeploy로 CI/CD 하기

CodeDeploy 란 무엇입니까? - AWS 공식 문서

AppSpec 'hooks' 섹션 - AWS 공식 문서

[Linux] nohup 세션이 끊겨도 계속 실행되도록 해보자

Clone this wiki locally