지난 1편에 이어서 Github Actions에서 CI 후 AWS S3에 jar 파일을 올린 뒤 CodeDeploy로 해당 파일을 EC2에 배포하는 과정이 필요합니다. 이때 GitHub에서 S3, CodeDeploy에 접근 가능하도록 설정하는 과정 + main 브랜치에 push 했을 때 배포하는 파일/스크립트도 작성하는 과정에 대한 내용입니다.

 

배포하면서 가장 삽질을 많이 했던 부분이 .gitignore로 리포지토리에 올리지 않은 민감정보를 배포 한 애플리케이션에 옮기는 것이었다. 민감정보 유출을 막기 위해 git ignore를 한건데, 실행시에 필요하다니 이를 어떻게 해야하나 구글링도 정말 많이 하고, 이것저것 시도도 많이 했다. 그 결과 얻어냈던 과정이 아래 4번째 목차 "Github Actions Workflow(deploy.yml) 작성"에 최대한 자세하게 설명을 해두었으니 참고하면 될 것 같다.

 

 

0. 목차

1. GithubActions 에서 사용할 IAM 사용자 생성

2. appspec.yml 작성

3. 배포 스크립트(stop.sh, start.sh) 작성

4. Github Actions Workflow(deploy.yml) 작성

    4-1. application-prod.yml 파일을 Github Secrets에 추가하기

    4-2. AWS 민감  정보 Github Secrets 등록하기

5. Github Actions 사용해서 배포하기

 

1. GithubActions 에서 사용할 IAM 사용자 생성

Github Actions 워크 플로우에서 AWS에 접근하려면 권한이 필요합니다. 

그래서 이버에는 IAM 사용자를 생성해 Github Actions에서도 S3와 CodeDeploy에 접근할 수 있게 설정해보겠습니다. 

 

1.1 IAM 사용자 생성하기 

"IAM 페이지 -> 사용자 -> 사용자 추가" 의 과정을 거쳐 사용자를 생성합니다. 

 

 

1.2 IAM 사용자 이름 설정

사용자 이름을 설정합니다. 제가 참고한 블로그에서는 이 과정에 액세스 유형을 설정할 수 있지만, 제가 설정할 때는 업데이트가 된 것인지 별도로 액세스 유형을 설정할 수는 없었습니다. 그래서 따로 설정 해주었는데, 이는 바로 아래 <1.5 IAM 사용자의 액세스 키 생성하기> 항목에서 확인하실 수 있습니다. 

 

1.3 접근이 필요한 권한 추가 

권한 옵션은 직접 정책 연결로 설정한 뒤 AWSCodeDeployFullAccess, AmazonS3FullAccess 권한을 검색한 뒤 추가해 줍니다. 

 

 

1.4 IAM 사용자 이름 설정

IAM 사용자 이름만 설정한 뒤 넘어가면 됩니다. 

 

 

1.5 IAM 사용자의 액세스 키 생성하기

Github Actions에서도 AWS에 접근하기 위해서는 별도의 액세스 키를 발급받아야 합니다. 

"IAM 페이지 -> 사용자 -> 생성한 IAM 사용자 -> 보안 자격 증명 -> 액세스 키 만들기" 를 따라서 액세스 키 만들기를 시작합니다. 

 

 

1.5.1 액세스 키 모범 사례 및 대안 

사용사례는 CLI, 확인에 "위의 권장 사항을 이해했으며 액세스 키 생성을 계속하려고 합니다."에 체크한 뒤 다음으로 넘어갑니다.

 

 

1.5.2 발급된 액세스키/비밀 액세스 키 확인 

발급된 액세스키/비밀 액세스 키 확인한 뒤 따로 저장해 둡니다. 

 

 

 

2. appspec.yml

  • CodeDeploy에서 배포를 위해 참조하는 파일
  • 프로젝트의 어떤 파일들을 ec2 어떤 경로에 복사할지 설정 가능
  • 배포 프로세스 이후에 수행할 스크립트 지정해 자동으로 서버 띄울 수 있음
version: 0.0
os: linux

files:
  - source:  /
    destination: /home/ubuntu/app/deploy
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ubuntu
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ubuntu

 

files 섹션

배포 파일에 대한 설정

files:
  - source:  /
    destination: /home/ubuntu/app/deploy
    overwrite: yes
  • source: 인스턴스에 복사할 디렉터리 경로
  • destination: 인스턴스에서 파일이 복사되는 위치
  • overwrite: 복사할 위치에 파일이 있는 경우 대체

AppSpec '파일'섹션 참고 

 

permissions 섹션

위의 files에서 복사한 파일에 대한 권한 설정

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu
  • object: 권한이 지정되는 파일 또는 디렉터리
  • pattern (optional): 매칭되는 패턴에만 권한 부여
  • owner (optional): object 의 소유자
  • group (optional): object 의 그룹 이름

AppSpec '권한'섹션 참고 

 

hooks 섹션

배포 이후에 수행할 스크립트 지정. 적절한 hook을 찾아 실행할 스크립트 지정하면 된다. 

hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ubuntu
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ubuntu

위 코드에서는 파일 설치 -> AfterInstall에서 기존에 실행중이던 애플리케이션 종료 -> ApplicationStart에서 새로운 애플리케이션 실행 하는 과정이다.

  • location: hooks 에서 실행할 스크립트 위치
  • timeout (optional): 스크립트 실행에 허용되는 최대 시간이며, 넘으면 배포 실패로 간주됨
  • runas (optional): 스크립트를 실행하는 사용자

AppSpec '후크'섹션 참고 

 

3. 배포 스크립트(stop.sh, start.sh)

 

파일 위치

애플리케이션에서 /src와 같은 계층에 script 패키지를 생성 후 stop.sh, start.sh 쉘 스크립트 파일을 생성합니다. 각 파일의 내용은 아래와 같습니다. stop.sh는 기존에 실행중이던 애플리케이션을 중단 시키는 쉘 스크립트이고, start.sh는 새로 배포한 애플리케이션을 시작할 수 있게 해주는 쉘 스크립트입니다.

 

 

stop.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app/deploy"
JAR_FILE="accountbook-0.0.1-SNAPSHOT.jar"

DEPLOY_LOG="$PROJECT_ROOT/deploy-stop.log"

TIME_NOW=$(date +%c)

# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)

# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
  echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
  echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
  kill -15 $CURRENT_PID
fi

애플리케이션이 이미 떠있을 때 애플리케이션을 종료하는 스크립트이다. 

 

start.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app/deploy"
JAR_FILE="$PROJECT_ROOT/accountbook-0.0.1-SNAPSHOT.jar"

APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy-start.log"

TIME_NOW=$(date +%c)

# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE

# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &

CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG

애플리케이션을 실행하는 스크립트로, Github Actions workflow에서 이미 빌드를 마쳤기 때문에 JAR 파일만 복사한 후 실행한다. 

 

4. deploy.yml

deploy.yml 파일을 통해 다음과 같은 작업이 수행된다.

  • 프로젝트 빌드
  • /src/resources/application-prod.yml 생성
  • AWS S3 버킷에 푸시
  • CodeDeploy 수행

 

파일 위치

/src와 같은 레벨에 .github/workflows 패키지를 생성한 뒤 해당 위치에 deploy.yaml 파일을 생성합니다.

 

 

deploy.yml

name: Deploy to Amazon EC2

# 초기설정(1)
on:
  push:
    branches:
      - main

# 초기설정(2)
env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: accountbookserver-s3-bucket
  CODE_DEPLOY_APPLICATION_NAME: accountbookserver-codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: accountbookserver-deployment-group


permissions:
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-20.04
    environment: production

    steps:
      # (1) 기본 체크아웃
      - name: Checkout
        uses: actions/checkout@v3

      # (2) JDK 11 세팅
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          distribution: 'temurin'
          java-version: '11'

      # (3) Git Secret 을 활용한 application-xxx.yml 생성
      - name: Create spring properties
        run: |
          touch src/main/resources/application-prod.yml
          echo "$PROD_YML" > application-prod.yml.b64
          base64 -d -i application-prod.yml.b64 > src/main/resources/application-prod.yml
        env:
          PROD_YML: ${{ secrets.PROD_YML }}

      # (4) Gradle build(Test 제외)
      - name: Build with Gradle
        uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
        with:
          arguments: clean build -x test

      # (5) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      # (6) 빌드 결과물을 S3 버킷에 업로드
      - name: Upload to AWS S3
        run: |
          aws deploy push \
            --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
            --ignore-hidden-files \
            --s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
            --source . 

      # (7) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
      - name: Deploy to AWS EC2 from S3
        run: |
          aws deploy create-deployment \
            --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
            --deployment-config-name CodeDeployDefault.AllAtOnce \
            --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
            --s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip

 

# 초기설정 (1)

on:
  push:
    branches:
      - main

"branches :"에 설정한 브랜치에서 푸시를 할 경우 deploy.yaml을 실행하는 것을 의미합니다. 

 

# 초기설정 (2)

env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: accountbookserver-s3-bucket
  CODE_DEPLOY_APPLICATION_NAME: accountbookserver-codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: accountbookserver-deployment-group

deploy.yaml에서 사용할 이름들의 별칭을 지정할 수 있습니다. 예시로 { { env.AWS_REGION }} 형식으로 사용할 수 있습니다.

 

# 참고 : application.yml & application-prod.yml

애플리케이션을 실행함에 있어 db의 username, password와 같이 기밀 정보들이 필요하지만 이 정보들을 github에 그대로 올리게 된다면 보안적으로 좋지 않다(기밀정보를 가지고 해킹을 하거나 큰 청구비용이 나오게 하는 등). 그렇기에 보통 개발용 properties 파일과 배포용 properties 파일을 다르게 해서 실행해야 한다.  본 프로젝트에서는 처음부터 application.yml과 application-prod.yml을 따로 생성한 다음 application.yml은 개방해놓고, mode를 "prod"로 실행할 수 있게 설정을 해놓았다.

 

application.yml

spring-profiles-active : prod로 설정했다. 이러면 처음에는 application.yml을 실행했다가 application-prod.yml을 실행한다. 

server:
  port: 8080
  servlet:
    encoding:
      charset: UTF-8
      force: true
  tomcat:
    keep-alive-timeout: 100
    threads:
      max: 200
      min-spare: 10
    accept-count: 100

spring:
  profiles:
    active: prod

  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

  devtools:
    livereload:
      enabled: true
    restart:
      enabled: true
  thymeleaf:
    cache: false

logging:
  level:
    com:
      amazonaws:
        util:
          EC2MetadataUtils: error

 

 

실행된 애플리케이션의 profile을 보면 "prod"인 걸 확인할 수 있다.

 

# (3) gitignore 했던 설정파일(properties-prod.yml)을 Git Secret으로 생성하고 저장하기

      # (3) Git Secret 을 활용한 application-xxx.yml 생성
      - name: Create spring properties
        run: |
           # touch 명령어를 사용해 src/main/resources/application-prod.yml 파일을 생성한다.
          touch src/main/resources/application-prod.yml
          echo "$PROD_YML" > application-prod.yml.b64
           # base64 인코딩 파일(application-prod.yml.b64)을 디코딩하고(-d), ~/application-prod.yml로 입력 파일을 지정(-i)한다
          base64 -d -i application-prod.yml.b64 > src/main/resources/application-prod.yml
        env:
          PROD_YML: ${{ secrets.PROD_YML }}

위 코드는 github secret에 base64 인코딩 후 등록한 PROD_YML 파일을 배포한 애플리케이션 src/main/resources 위치에 application-prod.yml 이름으로 파일을 생성할 수 있게 하는 코드이다. 이 과정을 거치면 빌드할 때 없던 application-prod.yml이 배포한 애플리케이션에 생성되면서 필요한 기밀정보들을 사용할 수 있으므로 애플리케이션을 정상적으로 실행할 수 있게 된다.

 

 

properties-prod.yml의 내용을 github secrets에 등록하는 과정

  • properties 파일 Base64로 인코딩
  • 배포하려는 repository
  • Settings
  • 왼쪽 메뉴 Secrets and variables
  • Actions
  • New repository secret 버튼을 클릭 후 인코딩한 파일 저장

 

deploy.yaml에서는 ${{ secrets.xxx }}형식으로 secret 값을 지정할 수 있고, secret명은 deploy.yml 파일의 (3) 선언한 이름(PROD_YML)과 동일해야지 정상 적용됩니다.

 

 

# (5) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)

      # (5) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

(5) 단계에서는 Github Actions가 AWS IAM에 접근할 수 있게 Github Actions에 Access Key와 Secret Key 정보를 넘겨주어야 한다. 이 키값들은 비밀에 부쳐야 하므로 파일에 직접 입력해 놓기보다 github repository secrets에 따로 저장해야 한다.

 

 

구체적인 과정은 배포하려는 repository -> Settings -> 왼쪽 메뉴 Secrets and variables -> Actions 경로로 들어갑니다. New repository secret 버튼을 클릭해 해당 값을 저장하면 된다. ${{ secrets.xxx }} 형식으로 secret 값을 지정할 수 있다. deploy.yaml에서 설정한 AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY에 해당하는 키값을 동일한 이름으로 위의 사진처럼 github repository settings에 저장해야한다.

 

5. github actions 사용해서 배포하기

파일 수정을 마치고 main 브랜치로 push를 한 뒤 repository -> Actions 로 들어가면 배포가 진행되는 것을 확인할 수 있다. 배포가 성공하면 초록색 신호가, 실패하면 빨간색 신호와 함께 어느 단계에서 실패했는지 알 수 있다.

 

 

CodeDeploy 에서 배포 내역 확인

AWS CodeDeploy에 들어가면 배포가 성공한 것을 확인할 수 있다. 

 

EC2 서버에서 애플리케이션 실행 확인

ssh로 ec2 서버에 접속한 후, 배포한 위치인 /app/deploy로 이동해 빌드한 파일(accountbook-0.0.1-SNAPSHOT.jar)이 성공적으로 생성된 것을 확인할 수 있다.

 

-자바 실행 파일 확인

"ps -ef | grep java"는 java로 실행중인 프로세스를 확인하는 코드이다. 이걸 입력하면 빌드한 accountbook-0.0.1-SNAPSHOT.jar 가 실행되어 있음을 확인할 수 있다.

 

Postman으로 API 요청 및 응답 성공

해당 서버로의 요청 후 성공적으로 응답이 오는 것도 확인할 수 있다.

 

 

참고

https://bcp0109.tistory.com/363

 

지난 팀프로젝트에서 CI/CD를 구축했었는데, 마지막에 마무리를 잘 못한 것도 있고 프로세스 정리를 해야 머리에 남을 것 같아서 기록해보려 합니다.

 

CI/CD의 개념과 첫 설명에 대한 내용은 이전 블로그를 참고해주시면 되고, 1편에서는 AWS에서 CD를 위한 설정을 하는 단계로 진행해보겠습니다. 순서는 아래와 같습니다. 본 포스트는 이 포스트를 참고해 작성했습니다.

 

1. EC2 생성

2. 터미널로 EC2에 접속하기 

3. EC2에 Tag 추가(CodeDeploy에서 어떤 인스턴스에 실행할 지 구분하는 값)

4. IAM 역할 추가 후 EC2에 등록 (EC2 인스턴스에서 S3에 올려놓은 파일에 접근할 수 있게 권한을 추가하는 과정)

5. S3 버킷 생성

6. EC2 서버에 CodeDeploy Agent 설치

7. CodeDeploy 전용 IAM 역할 만들기

8. CodeDeploy 애플리케이션 생성

9. Github Actions에서 사용할 IAM 사용자 추가

 

1. EC2 생성

가장 먼저 프로젝트를 배포할 인스턴스를 만들어야 한다. EC2 인스턴스 생성 과정과 ssh로 접속하는 과정은 이 블로그를 참고했습니다. 

 

2. 터미널로 EC2에 접속하기

위 단계에서 생성한 EC2 인스턴스에 터미널로 접속 해보겠습니다. 

인스턴스 생성과정에서 만들었던 키페어를 원하는 위치에 저장한 뒤 해당 파일에 대한 권한을 설정합니다. 

 

2.1 키페어 파일에 접근권한을 먼저 설정해줍니다. 

chmod 400 {~/키페어 위치/키페어 이름.pem}

 

2.2 터미널로 ec2에 접속하기 

터미널에 다음과 같이 입력해 ec2에 접속을 합니다. 

ubuntu 환경에서 따라하시면 되고, 다른 환경이라면 공식 문서를 통해 진행하시면 될 것 같습니다. 

 

ssh -i {키페어 위치} ubuntu@{Public IPv4 주소}

 

위 명령어를 입력 후 아래와 같은 내용을 확인할 수 있습니다. 

아래와 같은 내용이 뜬다면 ec2 접속에 성공한 것입니다. 

 

3. EC2에 Tag 추가

여기에서 Tag는 CodeDeploy가 어떤 인스턴스에 배포할지 구분을 해야하는데, 그 인스턴스를 구분하기 위해 ec2에 설정하는 값을 의미합니다. 

 

3.1 EC2 설정에서 태그 관리 선택  

인스턴스 상세 정보에 들어가 오른쪽 상단의 "작업"을 누르고 "인스턴스 설정 > 태그 관리" 를 눌러 태그를 추가해줍니다. 

 

 

 

3.2 태그 추가 

원하는 이름을 key 항목에 추가한 뒤 저장을 눌러 인스턴스에 태그를 추가해줍니다.

 

 

3.2 태그 확인 

인스턴스 정보 하단에 AccountBookServer-tag-key 태그가 추가된 것을 확인할 수 있습니다.

 

 

 

 

4. IAM 역할 추가 후 EC2에 등록

EC2 인스턴스에서 S3에 올려놓은 파일에 접근할 수 있도록 권한을 추가해줘야 합니다. 

 

4.1 IAM 역할 관리 페이지로 이동

"IAM 페이지 -> 역할 -> 역할 만들기" 를 통해 역할을 만듭니다. 기존에 존재하는 역할은 신경쓰지 않으셔도 됩니다.

 

4.2 EC2 엔티티 선택 

IAM의 역할을 연결할 서비스를 선택합니다. 엔티티 유형은 AWS 서비스, 사용 사례는 EC2로 설정하시면 됩니다.

 

 

 

4.3 S3 접근 권한 추가 

EC2 인스턴스에서 S3에 접근할 수 있도록 AmazonS3FullAccess를 검색해 해당 권한을 추가해줍니다. 

 

 

4.4 이름 설정

마지막으로 역할에 원하는 이름을 설정한 뒤 생성을 완료합니다. 

4.3 과정에서 S3에 대한 접근을 추가했는데, 하단에 해당 권한이 추가된 것을 확인할 수 있습니다. 

 

 

 

4.5 EC2 인스턴스에서 IAM 연결 

IAM 역할을 생성했으니, 이 역할을 ec2 인스턴스에 연결해주는 과정이 필요합니다. 

"EC2 인스턴스 관리 페이지 -> 작업 -> 보안 -> IAM 역할 수정" 으로 이동합니다. 

 

 

 

4.6 EC2 인스턴스에서 IAM 연결 

이전에 만든 EC2 전용 IAM 역할을 선택한 뒤, 저장을 누르면 연결이 완료 됩니다. 

 

 

 

5. S3 버킷 생성

AWS S3 버킷이란 이미지 또는 zip 파일을 저장하기 위한 Storage Service 입니다.

CI로 테스트 및 빌드를 완료한 프로젝트 코드를 압축해서 S3에 저장한 후, EC2 서버에서 S3에 접근해서 압축한 파일을 가져오기 위해 사용합니다. 

 

5.1 S3 버킷 생성

"S3 메뉴 -> 버킷 만들기" 과정을 통해 버킷을 생성합니다.

 

 

5.2 일반 구성과 객체 소유권 설정 

원하는 버킷 이름과 region을 선택하고, ACL은 비활성화를 선택합니다. 

 

 

5.3 액세스, 버킷 버전, 암호화 비활성화 

나머지 설정은 기본값을 변경할 필요없이 그대로 두고 다음으로 넘어가면 됩니다. 

 

 

 

5.4 S3 버킷 생성 완료 

버킷 생성이 완료되면 아래와 같이 버킷을 확인할 수 있습니다. 

 

6. EC2 서버에 CodeDeploy Agent 설치

EC2가 Ubuntu 환경인 경우는 EC2에 접속한 뒤 아래의 명령어를 순서대로 작성하면 CodeDeploy Agent를 설치할 수 있습니다. 

EC2 환경이 Ubuntu가 아니거나, 버전이 다르다면 공식 문서를 확인해주세요.

 

$ sudo apt update
$ sudo apt install ruby-full
$ sudo apt install wget
$ cd /home/ubuntu
$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto > /tmp/logfile
$ sudo service codedeploy-agent status

 

정상적으로 설치가 된다면 sudo servie codedeploy-agent status 명령어를 쳤을 때 아래와 같은 결과가 나와야 합니다.

 

 

7. CodeDeploy 전용 IAM 역할 만들기

배포를 도와주는 CodeDeploy를 사용하기 위한 IAM 역할을 만들어 줍니다. 

 

7.1 IAM 메뉴에서 역할 선택 

"IAM 페이지 -> 역할 만들기" 과정으로 역할을 생성합니다. 

생성을 클릭한 뒤 나오는 페이지는 다음과 같으며, 엔티티 유형은 AWS 서비스, 사용 사례는 CodeDeploy 기본으로 선택합니다. 

 

 

7.2 CodeDeploy 권한 추가

AWSCodeDeployRole 권한을 추가해 줍니다. 

 

 

7.3 IAM 이름 설정

원하는 이름만 설정하고, 나머지는 기존에 설정된 그대로 진행하면 됩니다. 

이름을 생성한 뒤 오른쪽 하단에 "역할 생성"을 눌러 마무리 합니다. 

 

 

8. CodeDeploy 애플리케이션/배포그룹 생성

이제 우리가 사용할 CodeDeploy 앱을 생성합니다. 

 

8.1 CodeDeploy 애플리케이션 생성

"CodeDeploy 페이지 -> 배포 -> 애플리케이션 -> 애플리케이션 생성 버튼" 의 과정으로 애플리케이션을 생성하기 시작합니다. 

원하는 이름과 컴퓨팅 플랫폼을 "EC2/온프레미스"로 설정한 뒤 애플리케이션을 생성합니다. 

 

 

8.2 CodeDeploy 배포 그룹 생성

CodeDeploy 애플리케이션을 생서한 뒤 애플리케이션에서 사용하는 배포 그룹을 생성합니다. 

"CodeDeploy 페이지 -> 배포 -> 애플리케이션 -> 배포그룹 생성" 의 과정으로 진행하시면 됩니다. 

 

 

8.3 CodeDeploy 배포 그룹 생성

원하는 배포 그룹 이름, 역할, 유형을 설정합니다. 

서비스 역할은 위에서 만든 IAM을 선택하시면 됩니다. 

 

 

8.4 EC2 인스턴스 선택 

CodeDeploy 배포 그룹을 어떤 인스턴스에서 동작시킬 지 선택해야합니다. 

이전에 EC2에 설정한 태그를 선택해주시면 됩니다. 

 

 

8.5 나머지 설정 후 배포 그룹 생성 

AWS Systems Manger는 크게 중요하지 않은 것 같으니 한 번만으로 설택하고, 로드 밸런싱은 체크를 해제 합니다. 

설정을 완료한 뒤 배포 그룹 생성을 눌러 마무리합니다. 

 

 

여기까지 하면 EC2/S3/CodeDeploy 생성과 IAM 역할 생성 및 권한 설정을 위한 과정을 모두 마쳤습니다. 

다음 포스트에는 Github Actions에서도 S3와 CodeDeploy에 접근할 수 있게 접근 권한을 설정하는 것과 배포를 위한 코드를 추가하는 과정으로 진행할 예정입니다. 감사합니다. 

 

 

 

Reference

https://bcp0109.tistory.com/363

 

 

팀 프로젝트를 하면서 자동 배포 환경 설정은 거의 필수라고 생각해서 CI/CD를 무조건 해야한다고 생각했습니다. 

아무것도 모르는 상태에서 진행했기에 시간도 오래 걸리고, 미숙한 부분도 많았어서 이번에는 단계별로 이해하면서 공부를 해보려고 합니다. 기본적인 CI/CD 지식, AWS S3/CodeDeploy 설정, 스크립트 파일 작성 및 배포 순서로 진행할 예정입니다.

 

CI/CD 용어

우선, CI/CD의 용어 설명은 다음과 같습니다. 

CI(Continuous Integration)

지속적 통합으로 여러 개발자가 하나의 프로젝트를 같이 개발할 때 발생하는 불일치를 최소화 해주는 개념.

애플리케이션 변경 사항 반영 시 자동으로 빌드 및 테스트를 진행해 줘 잘못된 코드가 공유되는 걸 예방해줌

빌드 및 테스트를 자동으로 진행하여 여러 개발자들이 공유하는 코드의 신뢰성을 높이는 개념

CD(Continuous Deployment)

지속적 배포로 프로젝트의 변경 사항을 클라우드에 자동으로 배포하는 것을 의미 

배포 플로우를 자동화 누구나 동일한 플로우로 배포할 있게 해주는 개념 

 

어떤 점이 좋은지

그러면 CI/CD를 하면 어떤 점이 좋을지 알아보겠습니다. 

애플리케이션을 배포한 뒤에, 애플리케이션에 변경사항이 발생한다면 변경된 애플리케이션을 다시 빌드하고, 배포해야하는 과정을 거쳐야 한다. 만약 배포 과정을 매번 수동으로 진행한다면 어떻게 될까? 개발자는 변경사항이 있을 때마다 배포를 수동으로 해야하는 번거로움이 발생될 것이고, 클라이언트 측에서는 변경사항이 반영된 확인하기 위해 배포하는 시간을 기다려야하는 불편함이 발생할 있다. 그래서 코드를 main 브랜치에 merge 하면 알아서 통합 배포를 진행해준다면 더이상 개발자가 배포 과정에 일일히 신경쓸 필요가 없을 것이다. 

즉, 계속되는 코드 변경을 띄워진 서버에 빠르고 편리하게 반영하기 위해서 필요한 것이라고 이해했습니다. 

 

툴 선택 : Github Actions

그렇다면 어떤 툴을 이용해서 하는 것이 좋을지 고민 끝에 GitHub Actions를 이용하기로 했습니다. 

관련 툴로는 Travis CI, Jenkins도 있는데 GitHub Actions를 사용하기로 한 이유는 다음과 같습니다.

Github Actions가 Github와의 연계성이 좋고, public repository를 사용한 경우 무료였기에 비용적인 부담도 덜해서 선택했습니다. 

Jenkins 별도로 설정이 필요하다고 들었고, Travis CI 일정 리소스 이상 사용하면 과금이 되는 것으로 알고 있습니다. 

그래서 비교적 설정이 간단하고 부분적으로 무료인 Github Actions가 저의 상황과 잘 맞는다고 생각해 선택해서 설정을 진행했습니다. 

 

이제 Github Actions, AWS S3, AWS CodeDeploy를 이용해 테스트 및 배포를 할 텐데, 큰 흐름은 다음과 같습니다.

흐름을 간단하게 설명하면 다음과 같습니다.

소스 코드를 압축해 AWS 스토리지에 저장 후 서버에 전달해서 실행한다

 

AWS에서 공식적으로 가이드하는 방법으로 두가지가 있습니다.

  1. AWS S3에 있는 빌드 파일을 압축 -> CodeDeploy 활용 -> AWS EC2에 배포 
  2. AWS ECR에 도커 이미지 업로드 -> Task Definition 활용 -> AWS ECS 배포

GitHub 코드를 S3 업로드 , AWS EC2에서 끌어다 쓰는 것이 핵심이고, 이를 도와주는 것이 AWS CodeDeploy입니다.

EC2의 서버에 배포해야하므로 1번의 방식으로 진행합니다.

 

 

 

참고 블로그 : https://bcp0109.tistory.com/363

먼저 프로젝트에 mysql 연동한 다음 docker로 배포하려고 했다. 

참고한 블로그는 여기

근데 중간중간 이해가 가지 않는 부분은 따로 찾아봤다. 

 

이해가 가지 않았던 부분 

  • DockerFile이 아니라 Dockerfile로 루트 디렉토리에 만들어주기
  • vim Dockefile이 명령어(이게 블로그에 없어서 찾아봤다;)
  • 프로젝트 빌드는 intelliJ Gradle에서 buildJar하고, 거기서 나온 이름 사용하면 되고 (여기 때문에 마지막 못한 것 같다)
  • 또 무슨 permission denied 나왔는데, 그건 구글링해서 chmod 어쩌구 하면 해결된다 
  • 그리고 루트 디렉토리에 docker-compose.yml 생성하는 거 잊지말고 

위 과정 해결하면서 참고했던 블로그들 

https://woodcock.tistory.com/34

https://da2uns2.tistory.com/m/entry/Docker-%EB%8F%84%EC%BB%A4%EC%97%90-Spring-Boot-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0

https://yoo11052.tistory.com/123

https://ksr930.tistory.com/139

 

 

docker-compose까지 빌드해봤는데 

jar 파일을 찾을 수 없다면서 계속 오류가 났다 

[ec2-user@ip-000-00-00-00 local-server]$ docker-compose up --build -d
Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
Building spring
Sending build context to Docker daemon  278.7MB

Step 1/4 : FROM openjdk:11-jdk
 ---> 6927c2556235
Step 2/4 : ARG JAR_FILE=./build/libs/localdeploy-0.0.1-SNAPSHOT.jar
 ---> Using cache
 ---> 0614a623d85c
Step 3/4 : COPY ${JAR_FILE} app.jar
COPY failed: file not found in build context or excluded by .dockerignore: stat build/libs/localdeploy-0.0.1-SNAPSHOT.jar: file does not exist
ERROR: Service 'spring' failed to build

흠 아마 내가 빌드한 거를 잘 못한 것 같은데,, 구글링을 해도 이걸 어떻게 해야하는지 아직 못찾았다 

+ Recent posts