본문 바로가기

DevOps

[DevOps] CI/CD란?

  • CI (Continuous Integration)
    • 지속적인 통합
    • 여러 개발자들의 코드 베이스를 계속해서 통합하는 것
    • 자동으로 프로젝트에 코드가 Merge된다.

  • CD (Continuous Deployment)
    • 지속적인 배달
    • 코드베이스를 사용자가 사용 가능한 환경에서 배포하는 것을 자동화 하는 것
    • 자동으로 코드가 배포된다.

CI/CD의 필요성

  • 개발을 좀 더 수월하게 하기 위해서 필요하다.
  • 개발에 더욱 집중할 수 있다.
  • 반복된 행위를 없애서, 시간을 절약할 수 있다.

실습

* AWS와 Github Action을 사용해서 CI/CD 프로젝트 구축

 

1. EC2 설정

  • region을 서울로 선택한다.
  • 인스턴스 시작 버튼 클릭

  • Server 이름을 작성한다.
  • 사용 OS는 Ubuntu 20.04 LTS 버전을 사용한다.
  • Free Tier를 사용하기 위해 t2.micro 인스턴스를 선택한다.
  • 키 페어가 존재하면 해당 키 페어를 선택하고 없을 시 새로운 키 페어를 만들어서 선택한다.
  • 네트워크 설정 역시 기존의 보안 그룹이 존재하면 해당 보안 그룹을 선택하거나 없을 시 보안 그룹을 생성해서 설정한다.

  • 인스턴스가 생성되면, 우클릭 -> 인스턴스 설정 -> 태그 관리를 클릭한다.
  • 키 값을 입력한 뒤, 저장 버튼을 클릭한다.
  • 태그 값을 설정하는 이유는 추후 Code Deploy를 설정할 때 태그 그룹을 지정하는데 EC2 인스턴스와 매칭할 때 해당 태그를 사용해서 연결한다.

  • EC2 -> 보안 그룹 -> 해당 인스턴스의 보안 규칙을 누른 후 인바운드 규칙 편집 버튼을 클릭한다.
  • 내가 사용할 포트 번호에 대한 IP를 매칭해서 인바운드 규칙에 추가한다.
  • 현재 실습에 대해서는 0.0.0.0/0 IP를 추가한다.

 

* 이후 각자의 OS에 맞는 방법으로 EC2 인스턴스에 접속한다.

* EC2에 접속하면 해당 인스턴스는 빈 깡통이므로 다음과 같은 명령어를 입력해서 필요한 환경을 구성한다.

  • sudo apt update && sudo apt upgrade
  • 자바 설치
    • sudo apt install openjdk-11-jdk

  • Code Deploy Agent 설치
    • sudo apt install ruby-full -> Ubuntu Server용 CodeDeploy 에이전트 설치 가이드에 따른 설치
    • sudo apt install wget -> Ubuntu Server용 CodeDeploy 에이전트 설치 가이드에 따른 설치
    • cd /home/ubuntu
    • wget https://[bucket-name].s3.[region-identifier].amazonaws.com/latest/install
      = wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
      1. 아시아 태평양(서울):
        bucket-name: aws-codedeploy-ap-northeast-2
        region-identifier: ap-northeast-2
    • chmod +x ./install
    • sudo ./install auto > /tmp/logfile
    • sudo service codedeploy-agent status

* Pem 키 없이 AWS 인스턴스 접속하게 만들기

  • sudo vi /etc/ssh/sshd_config
  • /Pass 검색
  • PasswordAuthentication yes로 변경
  • sudo su -
  • passwd ubuntu
  • 비밀번호 입력
  • exit
  • sudo service ssh restart
  • ssh ubuntu@퍼블릭 IPv4 DNS
  • 비밀번호 입력 후 pem 키 없이 접속 가능

 

2. EC2 IAM 설정

  • aws에 IAM을 검색한다.
  • IAM에서 역할을 선택하고 역할 만들기를 클릭한다.

  • AWS 서비스, EC2를 선택하고 다음 버튼을 클릭한다.

  • CodeDeploy를 검색하고 AWSCodeDeployFullAccess 권한을 선택한다.
  • S3Full을 검색하고 AmazoneS3FullAccess 권한을 선택한 후, 다음 버튼을 클릭한다.
  • 다음 페이지에서 역할 이름을 설정하고 역할 생성 버튼을 클릭한다.

 

  • EC2로 돌아와서 인스턴스 우클릭 -> 보안 -> IAM 역할 수정을 선택한다.

 

  • 방금 전에 생성한 IAM 역할을 선택하고 IAM 역할 업데이트 버튼을 클릭한다.

 

3. RDS 설정

  • RDS 화면에서 데이터베이스 생성 버튼 클릭

 

  • 프리티어 사용을 위해 손쉬운 생성 -> MySQL -> 프리 티어를 선택한다.
  • DB 인스턴스 식별자를 입력한다.
  • DB에 접속할 때 사용할 마스터 계정 이름과 비밀번호를 입력한다.
  • 데이터 베이스 생성 버튼을 클릭한다.

 

4. S3 설정

  • AWS에서 S3를 검색하고 들어와 버킷 만들기를 클릭한다.

 

  • 버킷의 이름을 입력한다.
  • 모든 퍼블릭 엑세스 차단을 반드시 선택한다.
    • S3 버킷에는 전 세계 어디서에서 접속이 가능하기 때문에 해당 버킷에 자유롭게 등록/삭제 하는 것을 방지하기 위해서 선택한다.

 

* 이렇게 생성 S3는 프로젝트를 빌드했을 때, 생성되는 프로젝트 파일을 S3 버킷에 저장한다.

* EC2에서는 S3 버킷에 담긴 프로젝트 빌드 파일을 사용한다.

 

5. S3 IAM 설정

  • AWS IAM 페이지에서 사용자를 클릭한다.
  • 사용자 추가를 클릭한다.

 

  • 사용자 이름을 입력한다.
  • AWS 자격 증명 유형에서 엑세스 키를 선택하고 다음 버튼을 클릭한다.

 

  • 기존 정책 직접 연결을 선택한다.
  • S3Full을 입력하고 AmazonS3FullAccess 정책을 선택한다.
  • CodeDeployFull을 입력하고 AWSCodeDeployFullAccess 정책을 선택한 후 다음 버튼을 클릭하며 사용자를 생성한다.
  • 유저가 생성되면서 발급된 액세스 키와 비밀 액세스 키는 다시 확인할 수 없어서 다른 파일에 복사하여 저장한다.
  • 해당 키 값은 Github 프로젝트에서 시크릿 변수로 사용한다.

 

6.  Github Repository 설정

  • Github Repository를 생성한다.

 

  • Repository -> Setting -> Secrets -> Actions를 클릭한다.
  • New repository secret을 클릭한다.

 

  • 각각의 Key의 이름을 입력한다.
  • 각각의 Key Secret에 이전에 발급 받은 S3 유저의 액세스 키, 비밀 액세스 키, Region 값을 입력한다.
  • 총 3 개의 Key를 생성한다

 

7.  CodeDeploy  IAM 설정

  • AWS IAM 페이지에서 역할을 선택하고 역할 만들기 버튼을 클릭한다.

 

  • AWS 서비스를 선택하고 다른 AWS 서비스의 사용 사례에서 CodeDeploy를 입력하고 첫번 째 CodeDeploy를 선택한 후 다음 버튼을 클릭한다.

 

  • 역할 이름을 입력하고 역할 생성 버튼을 클릭한다.

 

8.  CodeDeploy  설정

  • CodeDeploy는 코드 배포 자동화 역할을 한다.

  • AWS CodeDeploy 페이지에서 애플리케이션을 클릭하고 애플리케이션 생성 버튼을 클릭한다.

 

  • 애플리케이션 이름을 입력한다.
  • 컴퓨팅 플랫폼으로 EC2/온프레미스를 선택하고 애플리케이션 생성 버튼을 클릭한다.

 

  • 생성된 애플리케이션에서 배포 그룹 생성 버튼을 클릭한다.

 

  • 배포 그룹 이름을 입력한다.
  • 이전에 생성한 CodeDeploy IAM 역할을 선택한다.
  • Amazon EC2 인스턴스를 선택하고 이전에 생성한 EC2 태그를 선택한다.
  • 로드 밸러서를 사용하지 않기 때문에 로드 밸런싱 활성화 옵션을 제거한다.
  • 배포 그룹 생성 버튼을 클릭한다.

 

** CodeDeploy와 EC2를 연동했기 때문에 EC2 내부에 존재하는 CodeDeploy Agent를 Restart 시켜주어야 한다.

* sudo service codedeploy-agent restart 
* Agent가 동작할 때마다 tail -F /var/log/aws/codedeploy-agent/codedeploy-agent.log 명령어로 Log를 확인할 수 있다.

 

9.  Github Action 설정

  • create File을 클릭한다.
  • 파일 생성 경로 : .github/workflows/deploy.yml
  • 파일 내용
name: CI-CD

on:
  push:
    branches:
      - main
      
env:
  S3_BUCKET_NAME: s3-ubuntu-test13
  CODE_DEPLOYMENT_APPLICATION_NAME: UBUNTU-CODE-DEPLOY
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: CODE-DEPLOY-GROUP
  
jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout
      uses: actions/checkout@v2
      
    - name: Set up JDK 11
      uses: actions/setup-java@v1
      with:
        java-version: 11
        
    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew
      shell: bash
      
    - name: Build with Gradle
      run: ./gralew clean build
      shell: bash
      
    - name: Make zip file
      run: zip -r ./$GITHUB_SHA .
      shell: bash
    
    - name: Gonfigure 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: ${{ secrets.AWS_REGION }}
        
    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip
      
    - name: Code Deploy
      run: |
        aws deploy create-deployment \
        --deployment-config-name CodeDeployDefault.AllAtOnce \
        --application-name ${{ env.CODE_DEPLOYMENT_APPLICATION_NAME }} \
        --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
        --s3-location bucket=$S3_BUCKET_NAME.bundleType=zip,key=$GITHUB_SHA.zip
  • main 브랜치에 Push -> 프로젝트 코드 빌드 -> aws s3에 zip으로 압축해서 upload -> 해당 파일을 CodeDeploy에 전달

 

* appspec.yml 파일 생성

  • appspec.yaml 파일은 CodeDeploy Agent가 사용하는 스크립트 파일
  • CodeDeploy에서 배포를 관리하는데 사용하는 YAML 파일이다.
  • 파일 내용
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/github_action
    overwrite: yes

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

hooks:
  ApplicationStart:
    - location: scripts/gh_deploy.sh
      timeout: 60
      runas: ubuntu
  • 프로젝트 파일 내 scripts/gh_deploy.sh 파일을 생성하면, 해당 sh 파일이 EC2 내에서 실행된다.
  • gh_deploy.sh 코드 내용
#!/bin/bash
PROJECT_NAME="github_action"
JAR_PATH="/home/ubuntu/github_action/build/libs/*-SNAPSHOT.jar"
DEPLOY_PATH=/home/ubuntu/$PROJECT_NAME/
DEPLOY_LOG_PATH="/home/ubuntu/$PROJECT_NAME/deploy.log" # Deploy Log 파일
DEPLOY_ERR_LOG_PATH="/home/ubuntu/$PROJECT_NAME/deploy_err.log" # Deploy Error Log 파일
APPLICATION_LOG_PATH="/home/ubuntu/$PROJECT_NAME/application.log" # Application Log 파일
BUILD_JAR=$(ls $JAR_PATH)
JAR_NAME=$(basename $BUILD_JAR)

echo "===== 배포 시작 : $(date +%c) =====" >> $DEPLOY_LOG_PATH

echo "> build 파일명: $JAR_NAME" >> $DEPLOY_LOG_PATH
echo "> build 파일 복사" >> %DEPLOY_LOG_PATH
cp $BUILD_JAR $DEPLOY_PATH

echo "> 현재 동작 중인 애플리케이션 pid 체크" >> $DEPLOY_LOG_PATH
CURRENT_PID=$(pgrep -f $JAR_NAME)

# shellcheck disable=SC2157
if [ -z CURRENT_PID ]
then
  echo "> 현재 동작 중인 애플리케이션이 존재하지 않는다." >> $DEPLOY_LOG_PATH
else
  echo "> 현재 동작 중인 애플리케이션이 존재한다." >> $DEPLOY_LOG_PATH
  echo "> 현재 동작중인 애플리케이션 강제 종료 진행" >> $DEPLOY_LOG_PATH
  echo "> kill -9 $CURRENT_PID" >> $DEPLOY_LOG_PATH
  kill -9 $CURRENT_PID
fi

DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo "> DEPLOY_JAR 배포" >> $DEPLOY_LOG_PATH
nohup java -jar -Dspring.profiles.active=prod $DEPLOY_JAR --server.port=8081 >> $APPLICATION_LOG_PATH 2> $DEPLOY_ERR_LOG_PATH & # & -> background exec

sleep 3

echo "> 배포 종료 : $(date +%c)" >> $DEPLOY_LOG_PATH

 

이와 같은 설정을 진행 한 뒤, main 브랜치에 push 작업을 진행하면, EC2 인스턴스에서 프로젝트가 구동되고 있는 것을 확인할 수 있다.