미소를뿌리는감자의 코딩

[CI/CD 구축] Github actions - ECR - EC2 + 도커 본문

프로젝트

[CI/CD 구축] Github actions - ECR - EC2 + 도커

미뿌감 2024. 7. 24. 21:12
728x90

1. 개요

이번에 새로 프로젝트를 진행하면서 CI/CD 구축을 맡게 되었다.

그러면서 여러 포스팅을 보면서 공부하게 되었다. 

하지만, Github actions에서 ECR로 이미지를 저장하고, 해당 이미지를 EC2에서 받아와서 프로그램을 실행하는 포스팅은 별로 없었다. 

이에 한번 잘 작성해 보려고 한다.

 

우선 아키텍쳐부터 확인하고 가자

 

  1. 프로젝트가 dev에 푸시
  2. github actions 작동
  3. 프로젝트를 도커 파일을 이용해서 이미지화
  4. 이미지를 ECR에 저장
  5. 저장된 이미지를 EC2에서 가지고 와서 실행

이런식으로 작동되게 될 것이다. RDS 또한 연결을 시켜서 Mysql 을 사용할 수 있도록 하였다.

 

2. aws EC2 생성하기

EC2 - 인스턴스 - 인스턴스 시작 을 누른다.

 

 

나는 ubuntu로 설정을 해주었다.

 

 

인스턴스 유형의 경우 프리 티어인 t2.micro를 선택해 주었다.

서버 상황에 따라 선택하면 될 것 같다.

 

키 페어의 경우 키페어가 없다면 '새 키페어 생성'을 눌러준다. 

 

키 페어 이름을 적어주고 RSA 와 .pem을 선택하고 키 페어 생성을 누른다.

 

 

그러면 키 페어가 다운로드 되는데, 다운로드 된 .pem 파일을 자신이 기억하는 곳에 저장해 둔다.

 

이후 나머지는 default로 두고 인스턴스 시작을 눌러준다.

 

후에 RDS 를 이용하기 위해 3306 포트를 열어줘야 한다.

실행하고자 하는 인스턴스를 누르고 보안을 클릭한다.

이후 인바운드 규칙의 보안 그룹을 눌러준다.

 

launch-wizard-6를 눌러준다. 이후 보안그룹 id를 눌러주고, 인바운드 규칙 편집을 눌러준다.

규칙 추가를 누르고 아래 규칙을 추가해 준다.

 

 

또한 이후에 url에 5000번 포트로 접근할 것이기 때문에, 5000번 포트도 열어주자.

또한 http로 접근할 것이기 때문에 이에 대한 보안도 넣어준다. https는 이번 포스트에서 다루지 않는다.

 

 

 

EC2에서 ECR에 접근하기 위한 권한도 부여해 주어야 한다.

 

 

역할 생성을 눌러준다.

사용 사례로는 EC2를 선택하고 다음을 눌러준다.

 

 

이를 선택해주고 다음을 눌러준다.

해당 역할을 설명해주는 역할 이름을 적어준다.

나의 경우 ec2-ecr-access로 설정해 주었다.

 

이후, ec2에 들어가서 IAM 역할 수정을 눌러준다.

 

이후 ec2-ecr-access 를 눌러주고 IAM 역할 업데이트를 눌러준다.

 

 

3. aws ECR 생성

서비스 중에 Elastic Container Registry로 들어가 준다.

리포지토리 - 리포지터리 생성을 눌러준다.

 

 

 

이렇게 리포지토리 이름을 적어주고,

 

바로 리포지토리 생성을 눌러준다.

 

 

그러면 이렇게 리포지토리가 생성되게 된다.

여기서 생성된 URI가 추후에 필요하게 된다.

 

4. RDS 생성

필자의 경우 Mysql을 연결에서 사용할 것이기 때문에, RDS를 생성하여 주었다.

만약에 데이터베이스 연결이 필요 없다면 이 부분을 건너 뛰어도 될 것 같다.

 

우선 연결시키려는 ec2와 같은 보안그룹을 RDS가 가지고 있어야 하기 때문에,

EC2의 보안 그룹부터 확인해보자.

 

인스턴스 - 현재 실행하고자 하는 인스턴스 ID를 눌러준다.

 

 

서브넷 ID의 경우엔, 한번 더 클릭해서 들어가면 vpc-로 시작하는 값을 확인할 수 있다.

해당 값을 추후에 rds 구성 시, 선택하여 주어야 한다.

 

 

 

이 화면에서 VPC ID, 서브넷 ID, 보안 그룹을 확인하고 이제 RDS를 생성하러 가볼 것이다.

 

RDS - 데이터베이스 - 데이터베이스 생성을 눌러준다.

 

기존 로컬에서 MySQL을 사용했었기 때문에, MySQL을 선택해 준다.

 

 

 

템플릿의 경우 프리 티어를 선택해 줄 것이다.

 

 

이런식으로 설정해 주었다. 비밀번호의 경우 자체 관리를 선택하고 원하는 비밀번호를 작성해 주었다.

 

EC2에서 확인했던 VPC ID, 서브넷 ID, 보안 그룹을 이제 넣어줄 차례이다.

 

서브넷 값의 경우엔, 앞에서 말했듯이 해당 아이디를 클릭해서 들어가서 확인하면, vpc-로 시작하는 값을 확인할 수 있다.

 

 

 

이후 다른 것들은 그대로 두고, 데이터베이스 생성을 눌러준다.

데이터베이스의 경우 생성하는 데, 시간이 좀 걸린다.

 

5.IAM 생성

사용자 생성을 통해, ECR과 EC2에 접근 권한을 부여해주어야 한다.

IAM - 사용자 - 사용자 생성 을 눌러준다.

 

 

사용자 이름을 적고 다음을 누른다.

이후 직접 정책 연결을 눌러준다.

권한 정책에서 아래 정책들을 검색하고 추가해 준다.

 

이후 사용자 생성을 눌러 사용자를 생성한다.

생성된 사용자를 눌러 보안 자격 증명에 들어간다. 

 

이후 아래에 있는 액세스 키 만들기를 누른다.

 

 

기타를 누르고 넘어가고, 

설명 태그 값은 원하는 대로 적는다. 

 

이후 액세스 키 만들기를 누른다.

 

.csv 파일 다운로드가 나오는데 이를 눌러서 따로 저장해 준다.

이는 다시 재발급이 안되니 꼭! 잊어버리지 않아야 한다.

6. application.properties 수정

application.properties 수정을 통해 rds의 database에 연결할 수 있도록 할 것이다.

spring.datasource.url=jdbc:mysql://localhost:3306/lv3
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

 

이전 글의 경우 위와 같이 mysql 을 local로 연결했었다.

하지만, 해당 값을 rds database url과 비밀번호로 수정해 주어야 한다.

url의 경우엔, 데이터베이스의 연결 및 보안에서 엔드포인트 및 포트를 확인해 준다.

 

해당 엔드포인트를 복사해서 아래와 같이 url 부분에 적어준다.

jdbc:mysql://과 3306포트 번호를 넣는 것을 잊지 말아야 한다.

또한 추후에 database이름으로 test를 사용할 것이기 때문에 /test를 작성해 주었다.

spring.datasource.url=jdbc:mysql://database-1.0000000.ap-northeast-2.rds.amazonaws.com:3306/test
spring.datasource.username=admin
spring.datasource.password=password

 

위에서 username을 admin으로 설정해 주었었기에 admin으로 설정해 주었다. 비밀번호의 경우엔 아까 설정했던 비밀번호를 적어준다. 

 

7. .github/workflows/aws.yml 파일 생성

이제 deploy가 되면, 실행되게 될 yml 파일을 적어줄 것이다.

github에서 addfile을 통해 파일을 추가해 준다.

 

 

우선 전체적은 yml 파일은 아래와 같다.

아래에서 말하는 repository는 생성한 repository 이름을 넣어줘야 한다.

name: Deploy to EC2 using Docker and ECR

on:
  push:
    branches:
      - dev

jobs:
  deploy:
    runs-on: ubuntu-latest

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

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

    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew
      

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

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v2
      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: Login to Amazon ECR
      run: aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.ECR_URI }}

    - name: Build Docker image
      run: docker build -t repository .

    - name: Tag Docker image
      run: docker tag repository:latest ${{ secrets.ECR_URI }}:latest

    - name: Delete latest image from ECR
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          aws ecr batch-delete-image --repository-name repository --image-ids imageTag=latest

    - name: Push Docker image to ECR
      run: docker push ${{ secrets.ECR_URI }}:latest

    - name: Login to ECR on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          aws ecr get-login-password --region ap-northeast-2 | sudo docker login --username AWS --password-stdin ${{ secrets.ECR_URI }}

    - name: Stop running containers on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          sudo docker ps -q | xargs -r sudo docker stop

    - name: Remove all containers on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          sudo docker ps -asq | xargs -r sudo docker rm

    - name: Delete images on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          sudo docker images -q | xargs -r sudo docker rmi

    - name: Prune unused Docker resources on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          sudo docker system prune -af

    - name: Pull Docker image from ECR on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          sudo docker pull ${{ secrets.ECR_URI }}:latest

    - name: Run Docker container on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          sudo docker stop hdev_server || true
          sudo docker rm hdev_server || true
          sudo docker run -d --env-file /root/.env -p 5000:8080 ${{ secrets.ECR_URI }}:latest

 

하나씩 알아보자, 

 

on:
  push:
    branches:
      - dev

dev에 push가 되면 github actions가 작동한다는 것을 명시해 주고 있다.

 

jobs:
  deploy:
    runs-on: ubuntu-latest

ec2를 아까 ubuntu를 선택하였기에, ubuntu-latest에서 작동한다고 명시한다.

 

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

나의 경우엔, java 17로 프로젝트를 구성하였기에 java17을 사용해 줄 것이라고 명시한다.

 

    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew
      

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

프로젝트 run이 가능하도록 gradlew에 권한을 부여하고 build를 한다.

 

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}

다음으로는 앞에서 발급했던 IAM의 access key id와 secret access key를 넣어줘야 한다.

 

이는 보안적으로 중요한 값이므로 노출이 되지 않도록 따로 settings에 값을 넣어준다.

settings를 누르고, 

 

여기로 들어온다.

이후 New repository secret을 누르고, 

 

 

SECRET_ACCESS_KEY 도 동일하게 넣어준다.

 

AWS_REGION의 경우 서울은 ap-northeast-2 이다.

 

이렇게 생성되게 된다.

 

 - name: Login to Amazon ECR
      run: aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.ECR_URI }}

 

ECR에 로그인 하기 위한 코드로, ECR URI 또한 secret으로 넣어준다.

 

    - name: Build Docker image
      run: docker build -t repository .

    - name: Tag Docker image
      run: docker tag repository:latest ${{ secrets.ECR_URI }}:latest

 

이미지를 빌드하고 latest라고 태그도 붙여준다.

 

    - name: Delete latest image from ECR
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          aws ecr batch-delete-image --repository-name repository --image-ids imageTag=latest

ECR에 저장되어 있던 이전 이미지들을 지우고 새로운 이미지를 올려준다.

EC2와 관련된 값들을 secrets에 넣어줄 차례이다.

 

EC2_PUBLIC_IP = 인스턴스의 퍼블릭 IPv4 주소이며, 

EC2_USERNAME = ubuntu

EC2_SSH_KEY = .pem 파일이다.

 

.pem 파일의 내용을 복사해서 붙여야 하는데, 

 

이는 터미널에서 아래와 같은 명령어로 복사할 수 있다.

 

.pem 파일이 저장되어 있는 곳에 들어가서 cat hi.pem을 입력해준다.

 

이렇게 값이 나오게 된다.

해당 값을 ----BEGIN 부터 ~~~PRIVATE KEY ----- 까지 복사해서 붙여줘야 한다.

 

 - name: Push Docker image to ECR
      run: docker push ${{ secrets.ECR_URI }}:latest

    - name: Login to ECR on EC2
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_PUBLIC_IP }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_KEY }}
        script: |
          aws ecr get-login-password --region ap-northeast-2 | sudo docker login --username AWS --password-stdin ${{ secrets.ECR_URI }}

 

도커 이미지를 ECR에 올리고, EC2에서 ECR에 접근한다.

 

이후 후에 코드들은 EC2에서 이전 이미지들을 지우고 새로 올리고, 도커를 실행하는 과정이다.

 

8. 도커 파일 생성

이미지를 만들기 위해 참고할 Dockerfile을 생성해 주어야 한다.

이는 루트에다가 파일을 생성해 주어야 한다.

FROM openjdk:17
WORKDIR /app
COPY build/libs/*.jar /app/app.jar
EXPOSE 8080
ENV SPRING_PROFILES_ACTIVE=dev
CMD ["java", "-jar", "app.jar"]

 

해당 값들을 넣고 생성해 주었다. 

 

 

아직 EC2에 설정을 마저하지 않았기에, gihub에서 Actions에 들어가면 deploy가 실패하는 것을 확인할 수 있다.

 

9. EC2에 접근 후 설치하기

chmod 400 hi.pem

pem 파일에 권한을 주고, 

 

퍼블릭 IPv4DNS를 통해 접근해 준다.

ssh -i "hi.pem" ubuntu@ec2-13-124-77-8.ap-northeast-2.compute.amazonaws.com

 

aws-cli를 설치 해 준다.

sudo apt-get update 
sudo apt-get install -y unzip
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

 

 

이후 rds에 접근하기 위한 mysql을 설치해 줄 것이다.

sudo apt-get install mysql-client -y
mysql -h <RDS_ENDPOINT> -P 3306 -u <DB_USERNAME> -p

<RDS_ENDPOINT> 와 <DB_USERNAME>에는 해당하는 값을 넣어준다.

username으로는 나는 admin을 설정해 줬었다.

 

이후 설정했던 비밀번호를 입력한다.

 

들어간 후에는 show databases;를 통해서 생성되어 있는 database들을 확인할 수 있다.

 

아까 전에 application.properties에서 /test로 데이터베이스를 만들거라고 명시했었기 때문에, 

create database test;

 

를 입력해 준다.

exit;

이를 통해 mysql에서 나갈 수 있다.

 

이제 docker를 설치해 준다.

sudo apt-get install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker

 

환경 변수를 설정해 주기 위해

 

root 가 저장되어 있는 폴더까지 cd ..를 해준다.

 

이후, 

sudo vim /root/.env

 

 

하고 해당 환경 변수를 작성해 준 후, (맥의 경우 a 를 누르면 작성이 가능해 진다.) 

esc를 누르고 :wq!를 입력한다.

 

10. 성공 확인

github에서 다시 Re-run all jobs를 한다.

 

이후 성공이 되면 ec2 터미널로 들어가서 아래 명령어를 작성해 본다.

sudo docker ps
sudo docker ps -a

 

-a를 붙이면 꺼진 컨테이너도 확인할 수 있다.

만약 에러가 나게 되면 바로 꺼지기 때문에, sudo docker ps 를 통해서 확인이 안된다면 sudo docker ps -a를 통해 확인하면 된다.

 

 

이후, 해당 컨테이너 아이디를 넣은 아래 명령어로 로그를 확인해 볼 수 있다.

sudo docker logs 54e8b6d5ea50

 

11. url 접근하기

http://ec2-00000000.ap-northeast-2.compute.amazonaws.com:5000/

이제 해당 명령어로 사이트에 접근할 수 있다.

 

.yml 파일을 구성하는 데에 있어 아래 블로그를 참고하였습니다.

 

https://iamiet.tistory.com/entry/EC2-ECR-Docker%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-CICD-%EA%B5%AC%EC%B6%95-with-Github-Actions

 

EC2 + ECR + Docker를 활용한 CI/CD 구축 with Github Actions

우선 현재 서버의 경우 인프라가 아래처럼 구성되어 있다. 만약 서버에서 코드를 몇줄만 수정해도 아래 과정을 거쳐서 다시 배포해야 한다. 1. 코드 수정 후 도커 이미지 빌드 2. 도커 이미지를 EC

iamiet.tistory.com

 

728x90