[CICD] GitHub Actions + Docker + ECR + EC2 배포

정석·2024년 10월 16일
2

💡 자동화 배포 아키텍처

위 아키텍처와 같이 GitHub에 push하면 GitHub Actions에서 CI/CD가 진행된다.

  1. GitHub Actions에서 프로젝트 빌드 및 Docker 이미지 생성
  2. ECR에 접속 후 이미지 push
  3. EC2에 접속하여 ECR에서 이미지 pull 후 Docker로 실행

배포 환경

  • AWS EC2 Ubuntu
  • JDK 17
  • RDS MySQL

1. EC2와 RDS 생성 및 환경 설정

EC2와 RDS 생성 과정은 생략함(프리티어로 설정)

인스턴스 생성이 완료되면 EC2 내부에 접속.

1) EC2 접속

ssh -i 생성된키.pem ubuntu@퍼블릭 IPv4 주소

생성된 인스턴스에 ubuntu 사용자로 접속한다.

2) aws-cli 설치

aws 명령어 사용을 위해 aws-cli 설치.

sudo snap install aws-cli --classic

3) Docker 설치

Docker를 설치하고 EC2 인스턴스에서 권한을 부여한다.

sudo apt install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

sudo apt update

sudo apt install docker-ce

설치가 완료되면 아래 명령어로 Docker가 제대로 설치되었는지 확인

docker --version

마지막으로 Docker 실행 권한을 인스턴스 사용자에게 부여한다.

sudo usermod -a -G docker ubuntu

2. ECR 생성 및 IAM 유저 생성

1) ECR 생성

AWS ECR(Elastic Container Registry)은 AWS에서 제공하는 Docker 이미지 저장소다.

ECR 메뉴에서 '레포지토리 생성'을 클릭한 후 이름을 설정하고 생성한다.

생성된 레포지토리를 클릭해 '푸시 명령 보기'를 통해 명령어를 확인할 수 있다.

2) IAM 유저 생성

IAM 메뉴로 들어가 '사용자 생성' 클릭 후, '직접 정책 연결'에서 AmazonEC2ContainerRegistryFullAccess 권한을 부여한다.

사용자 생성 후 액세스 키와 비밀 액세스 키를 발급받고, EC2에 접속하여 AWS CLI 설정을 진행하기 위해 아래 명령어를 입력하여 엑세스키와 시크릿키를 입력한다.

aws configure
  • Access Key와 Secret Key를 입력
  • Region Name은 ap-northeast-2 입력

3. GitHub Actions yml 파일 작성

GitHub에서 Actions 탭으로 들어가 set up a workflow를 클릭한 후 아래와 같은 YAML 파일을 작성.

1) Build and Push to ECR

먼저, main 브랜치에 push될 때 Docker 이미지를 빌드하고 Amazon ECR로 푸시하는 작업을 진행한다.

name: Build and Deploy to EC2

on:
  push:
    branches:
      - main

jobs:
  build:
    name: Build Docker image and push to ECR
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: '17'

      - name: Build with Gradle
        run: ./gradlew build -x test

      - 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: Log in to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Build, tag, and push image to Amazon ECR
        run: |
          REGION="ap-northeast-2"
          ECR_REPOSITORY="rednotice-ecr"
          IMAGE_TAG="latest"
          
          docker build -t $ECR_REPOSITORY:$IMAGE_TAG .
          docker tag $ECR_REPOSITORY:$IMAGE_TAG ${{ steps.login-ecr.outputs.registry }}/$ECR_REPOSITORY:$IMAGE_TAG
          docker push ${{ steps.login-ecr.outputs.registry }}/$ECR_REPOSITORY:$IMAGE_TAG
  • actions/checkout@v2을 사용해 코드 체크아웃 (프로젝트 코드를 깃액션으로 가져옴을 의미한다)
  • setup-java로 JDK 17 설치 후 ./gradlew build -x test로 Gradle 빌드 진행
  • aws-actions/configure-aws-credentials로 AWS 자격 증명 설정 후 ECR에 로그인 및 이미지 푸시

2) Deploy to EC2

EC2에 SSH로 접속해 Docker 이미지를 pull하고 컨테이너를 실행.

  deploy:
    name: Deploy to EC2
    runs-on: ubuntu-latest
    needs: build

    steps:
      - name: Execute remote SSH commands on EC2
        uses: appleboy/ssh-action@v0.1.6
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USER }}
          key: ${{ secrets.EC2_SSH_KEY }}
          port: 22
          script: |
            REGION="ap-northeast-2"
            ECR_REPOSITORY="rednotice-ecr"
            IMAGE_TAG="latest"
            AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID }}
            
            docker stop REDnotice || true
            docker rm REDnotice || true
            
            aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com
            docker pull $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$ECR_REPOSITORY:$IMAGE_TAG
            
            docker run -d --name REDnotice -p 8080:8080 \
              -e SPRING_PROFILES_ACTIVE=prod \
              -e SLACK_INCOMING_HOOK_URL=${{ secrets.SLACK_INCOMING_HOOK_URL }} \
              -e JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} \
              -e S3_ACCESS_KEY=${{ secrets.S3_ACCESS_KEY }} \
              -e S3_SECRET_KEY=${{ secrets.S3_SECRET_KEY }} \
              -e RDS_PASSWORD=${{ secrets.RDS_PASSWORD }} \
              $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$ECR_REPOSITORY:$IMAGE_TAG

이 단계에서는 EC2에 SSH로 접속해 기존 컨테이너를 중지 및 삭제 후, ECR에서 최신 이미지를 pull하여 Docker 컨테이너로 실행한다.


4. Dockerfile 작성

FROM openjdk:17-jdk-alpine
WORKDIR /app

COPY build/libs/*.jar REDnotice.jar

# 컨테이너 시작 시 실행할 명령어
ENTRYPOINT ["java", "-jar", "REDnotice.jar"]

5. GitHub Actions 시크릿 키 설정

GitHub Repository에서 Settings -> Secrets -> Actions에서 시크릿 키를 추가한다. 예시로 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, EC2_HOST 등을 설정.

시크릿 키는 다음과 같이 사용.

aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

이제 모든 설정이 완료되면, main 브랜치에 push하는 것만으로도 자동으로 빌드 및 배포가 진행된다.

0개의 댓글