아무튼!

[AWS/CICD] 깃허브 액션과 AWS를 이용한 CI/CD 구축 본문

Study/Hands-On

[AWS/CICD] 깃허브 액션과 AWS를 이용한 CI/CD 구축

yucori 2024. 4. 15. 17:41
반응형

깃헙 액션과 AWS 서비스를 이용한 CI/CD 환경 구축(v2024.03 - mac m1)

목표 서비스 구조
목표 서비스 구조

⚙️ CI/CD 실습

 👉 해당 실습은 맨 아래에 링크해 놓은 영상을 참고하여 진행하였습니다.

 

초기 세팅

1. 간단한 스프링 프로젝트 작성 (해당 레포를(init 브랜치) 포크 혹은 클론하여 진행하시면 됩니다)

package com.cicdproject.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController{
	
	@GetMapping("/hello")
	public String helloWorld(){
		return "Hello World";
	}
}

 

  • gradle 파일 (24.04.01 00:55수정) - 버전 수정되었음
  • 간혹 오류가 발생하시는 경우 `JAVA_HOME` 환경변수를 확인해 주시길 바랍니다. 해당 실습은 자바 11버전을 기준으로 합니다
plugins {
	id 'org.springframework.boot' version '2.6.0'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'accc'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
	useJUnitPlatform()
}

 

2. Github Repository에 push

  • 자신의 github에 업로드하고 난 뒤 actions 탭으로 이동해 yml 작성을 시작합니다.

 

3. Workflow에 새 yml 설정

# This is a basic workflow to help you get started with Actions
name: Build and Deploy Spring Boot to AWS EC2

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-20.04
    env:
      working-directory: ../
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Java JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11

      - name: Grant execute permission for gradlew
        run: cd cicd && chmod +x ./gradlew
        shell: bash

      - name: Build with Gradle
        run: cd cicd && ./gradlew build
        shell: bash

 

4. 커밋한 후 workflow 동작 확인

  • jdk 설치, 빌드까지 잘 되는지 actions 실행 동작 확인

깃허브 액션

맨 위가 정상 작동하는 것! 아래는 실패하였을 때임😂

클라우드 세팅

1. S3 생성

  • code를 클라우드 환경으로 옮기기 위한 S3 저장소 생성
  • 추후에 iam을 이용하여 권한을 부여하기 때문에 모든 퍼블릭 액세스 차단을 유지하여 생성

✅ 코드를 S3 저장소에 업로드 하였을 때의 장점

1. 네트워크 대역폭 관리: 깃허브는 원격 저장소이며, 사용자들이 공유하는 네트워크 대역폭을 고려해야 합니다. 따라서 대용량 파일이 많은 경우 깃허브에서 다운로드하는 데 시간이 오래 걸릴 수 있지만 S3와 같은 객체 스토리지 서비스를 사용하면 다운로드 속도를 개선할 수 있습니다.
2. AWS의 전용 네트워크: AWS는 매우 빠르고 안정적인 네트워크 인프라를 가지고 있습니다. 따라서 AWS 내부에서 작업을 수행할 때는 일반 인터넷보다 빠를 수 있습니다. 이는 S3와 다른 AWS 서비스 간의 데이터 전송에도 적용됩니다.
3. AWS 서비스 간의 통합 및 최적화: 깃허브 액션을 사용하여 코드를 S3에 업로드하는 경우, AWS의 다른 서비스들과 통합하여 작업을 자동화하고 최적화할 수 있습니다. 예를 들어, 코드가 S3에 업로드되면 AWS Lambda를 사용하여 자동화된 작업을 실행하거나, AWS CloudFront를 통해 캐싱 및 배포를 최적화할 수 있습니다.

 

 

2. S3 IAM 사용자 생성

  • 생성한 사용자의 액세스 키 id와 비밀 액세스 키 저장해 두기!
    • aws [iam] -> [사용자 추가]에서 AmazonS3FullAccess와 AWSCodeDeployFullAccess 권한을 부여한 사용자를 생성

IAM 생성 - 1
IAM 생성 - 2

        각자의 IAM 관리 정책에 따라 화면은 좀 다르게 표시될 수 있습니다.
        그다음엔 방금 생성한 사용자의 [보안 자격 설정]에서 액세스 키를 발급받아야 합니다.

액세스 키 발급 - 1

        용도는 서드파티 선택

액세스 키 발급 - 2

        이후에 나오는 화면에서 액세스 ID, 키를 복사해 두거나 csv 파일을 다운로드하여서 저장해 둡니다.

액세스 키 다운 - 3

        이렇게 액세스 키가 활성화되어야 합니다
 
        다만 IAM USER의 키를 다운로드하여야 하며, AmazonS3FullAccess, AWSCodeDeployFullAccess 권한을 부여해주셔야 합니다!
 


3. Github Repository Secrets에 액세스 키 저장

  • 발급받은 IAM User의 비밀정보는 자신이 생성한 레포지토리의 [Settings] - [Secrets and variables] - [Actions] 에서 Repository secrets에 아래와 같은 이름으로 저장합니다.
    • AWS_ACCESS_KEY_ID
    • AWS_SECRET_ACCESS_KEY

 

4. EC2 생성 및 보안그룹 설정

  • 이제 실제 서버를 구동시킬 EC2 인스턴스를 생성합니다.
  • 80, 8080 포트를 열어줍니다.
  • ssh 사용을 위해 22번 포트도 열어줍니다.

 
    본 글은 Amazon Linux 2023 AMI, t2.micro를 기준으로 작성하였습니다.
 
    EC2 생성 시 인바운드 규칙을 아래와 같이 수정

인바운드 규칙

 

5. EC2 IAM 역할 생성

  • 해당 EC2에 S3, CodeDeploy에 접근할 권한을 부여해 줄 IAM 역할을 생성

EC2 IAM 역할 생성 - 1
EC2 IAM 역할 생성 - 2

 

6. EC2 IAM 역할 연결

  • EC2에 생성했던 IAM 역할을 부여합니다.

EC2 IAM 역할 연결

 

 

7. EC2 내에 프로그램 설치
    EC2 접속은 EC2 선택 후 [작업] - [연결]을 누른 후 ssh를 통해 접속합니다.
    접속은 이전에 받은 pem 키가 있는 디렉터리에서만 가능합니다.
 
    권한이 너무 오픈되어 있다는 Permission 0644 오류가 발생할 경우 아래의 커멘드를 입력하여 해결합니다.

chmod 400 <pem키 이름>.pem

 
    그다음 아래의 명령어를 차례로 입력하여 jdk 11을 설치하고 CodeDeploy agent도 설치합니다.

# aws corretto 다운로드
sudo curl -L https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.rpm -o jdk11.rpm

# jdk 11 설치
sudo yum localinstall jdk11.rpm

# java version 확인
java --version

# ruby 설치
sudo yum install ruby

# 서울 리전의 CodeDeploy 리소스 키트 파일 다운로드
cd /home/ec2-user
sudo wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

# 실행 권한 부여
chmod +x ./install

# 에이전트 설치
sudo ./install auto

# 에이전트 상태 확인
sudo service codedeploy-agent status

 
    install 부분에서 오류가 발생할 때에는 `sudo su - root`로 root로 접속하여 `cd/home/ec2-user`로 이동한 후 chmod부터 다시 시도합니다.
 
amazon linux2등 다른 버전에 대한 설명은 아래에서 추가로 확인 가능합니다.

 

아마존 리눅스 또는 RHEL용 CodeDeploy 에이전트 설치 - AWS CodeDeploy

앞의 명령에서 /home/ec2-user는 Amazon Linux 또는 RHEL Amazon EC2 인스턴스의 기본 사용자 이름을 나타냅니다. 사용자 지정 AMI를 사용하여 인스턴스를 만든 경우 AMI 소유자가 다른 기본 사용자 이름을 지

docs.aws.amazon.com

 

 

8. CodeDeploy IAM 생성

  • CodeDeploy를 위한 역할을 생성합니다.

CodeDeploy IAM 생성 - 1
CodeDeploy IAM 생성 - 2

 

9. CodeDeploy 애플리케이션 생성

  • [CodeDeploy] - [애플리케이션] - [애플리케이션 생성] 으로 이동하여 애플리케이션을 생성합니다.

애플리케이션 생성

 

 

10. CodeDeploy 배포그룹 생성

  • 생성한 애플리케이션 내에 배포 그룹을 생성합니다.
  • 역할은 이전에 CodeDeploy를 위해 생성한 역할을 선택
  • 배포는 현재 위치에
  • 환경 구성은 amazonEC2 인스턴스 선택
  • name은 생성한 EC2 선택
  • 배포 구성은 AllAtOnce 선택
  • 로드밸런서는 비활성화

배포그룹 생성 - 1
배포그룹 생성 - 2

설정 코드 작성

1. 처음 만들었던 deploy.yml 파일을 다음과 같이 수정

  • env 수정
    • PROJECT_NAME: 버킷에 저장할 프로젝트 폴더 이름
    • BUCKET_NAME: S3 생성 시 지정했던 이름
    • CODE_DEPLOY_APP_NAME: CodeDeploy의 앱 이름
    • DEPLOYMENT_GROUP_NAME: CodeDeploy의 배포그룹 이름
# This is a basic workflow to help you get started with Actions
name: Build and Deploy Spring Boot to AWS EC2

on:
  push:
    branches: [ main ]

env:
  PROJECT_NAME: cicd_project
  BUCKET_NAME: yucori-cicd-bucket
  CODE_DEPLOY_APP_NAME: cicdapp
  DEPLOYMENT_GROUP_NAME: cicdapp_deploy

jobs:
  build:
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        
      - name: Setup Java JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11

      - name: Grant execute permission for gradlew
        run: cd cicd && chmod +x ./gradlew
        shell: bash
      
      - name: Build with Gradle
        run: cd cicd && ./gradlew build
        shell: bash
        
      - name: Make Zip File
        run: zip -qq -r ./$GITHUB_SHA.zip .
        shell: bash
      
      - 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: ap-northeast-2
      
      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

      - name: Code Deploy
        run: aws deploy create-deployment --application-name $CODE_DEPLOY_APP_NAME --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name $DEPLOYMENT_GROUP_NAME --s3-location bucket=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip

 

 

2. 커밋 후 Actions 동작 확인

Actions 동작 확인

 

 

3. appspec.yml 작성

  • CodeDeploy의 동작을 설정하기 위해 appspec.yml을 작성합니다. 해당 파일은 소스 파일의 루트 경로에 위치시키면 됩니다.
version: 0.0
os: linux

files:
  - source: /
    destination: /home/ec2-user/cicdproject
permissions:
  - object: /home/ec2-user/cicdproject/
    owner: ec2-user
    group: ec2-user
hooks:
  AfterInstall:
    - location: cicd/scripts/deploy.sh
      timeout: 60
      runas: ec2-user
  • files.source: CodeDeploy agent가 다운로드한 코드에서 어느 경로를 다운로드할지 결정함( / -> 전체 파일을 받음)
  • file.destination: EC2 서버에서 어느 경로에 해당 코드를 저장할지 결정
  • hooks.AfterInstall: CodeDeploy 수명주기 중 하나인 AfterInstall 발생 시 코드에서 scripts 폴더 안에 있는 deploy.sh를 실행하라는 이벤트

 

4. 배포용 쉘 스크립트 작성

  • 코드의 scripts 디렉터리 안에 deploy.sh를 생성하고 아래와 같은 내용을 작성합니다.
  • 해당 파일은 빌드된 jar 파일을 실행하는데, 만약 실행이 이미 되어있다면 해당 이름의 process를 kill 하고 새 버전의 서버 프로세스를 실행시켜 줍니다.
#!/usr/bin/env bash

REPOSITORY=/home/ec2-user/cicdproject/cicd
cd $REPOSITORY

APP_NAME=cicdproject
JAR_NAME=$(ls $REPOSITORY/build/libs/ | grep 'SNAPSHOT.jar' | tail -n 1)
JAR_PATH=$REPOSITORY/build/libs/$JAR_NAME

CURRENT_PID=$(pgrep -f $APP_NAME)

if [ -z $CURRENT_PID ]
then
  echo "> 종료할것 없음."
else
  echo "> kill -9 $CURRENT_PID"
  kill -15 $CURRENT_PID
  sleep 5
fi

echo "> $JAR_PATH 배포"
nohup java -jar $JAR_PATH > /dev/null 2> /dev/null < /dev/null &

 

5. 작성한 내용 반영 후 api 확인

  • 포스트맨을 통해 서버가 정상적으로 실행됨을 확인할 수 있습니다.

CICD 반영 전 출력

 

6. CI/CD 동작 확인

  • API 코드의 내용을 변경하고 깃허브에 push 한다.
    • ex) 이전에 작성한 controller 파일의 return 부분의 문구를 수정하여 확인

CICD 반영 후 출력

 
 
 

실습 완료!🍀


<참조>
영상이 간결하면서도 설명이 잘 되어있어서 꼭 영상을 보며 따라 해보시기를 추천드립니다~

https://www.youtube.com/watch?v=UF2Giz9PE-E

 

GitHub - kbsat/cicdproject: CICD project

CICD project. Contribute to kbsat/cicdproject development by creating an account on GitHub.

github.com

 

반응형