군붕이의 메모장

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

클라우드/AWS

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

초보군붕이 2023. 4. 20. 15:00
반응형

우선 현재 서버의 경우 인프라가 아래처럼 구성되어 있다.

 

서버 인프라 구성

 

만약 서버에서 코드를 몇줄만 수정해도 아래 과정을 거쳐서 다시 배포해야 한다.

  • 1. 코드 수정 후 도커 이미지 빌드
  • 2. 도커 이미지를 ECR에 업로드
  • 3. EC2 SSH 접속하여 업로드된 도커 이미지 다운로드
  • 4. 도커 이미지 실행

변경 작업은 유지보수를 하면서 계속해서 일어나게 되는데 매우 비효율적으로 생각됬다.

그래서 repository에 push될 경우 github actions를 사용하여 위 과정을 자동화해서 배포가 되도록 구성했다.

 

우선 Github Actions의 경우 이전 클라이언트에서 CI/CD를 구축하면서 적어둔게 있어 URL로 대체했다.

https://iamiet.tistory.com/entry/S3%EB%A1%9C-%EB%B0%B0%ED%8F%AC%ED%95%9C-React%EC%97%90-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-with-Github-Actions

 

S3로 배포한 React에 CI/CD 구축하기 with Github Actions

우선 현재 클라이언트의 경우 인프라가 아래처럼 구성되어 있다. 만약 클라이언트에서 코드를 몇줄만 수정해도 아래 과정을 거쳐서 다시 배포해야 한다. 1. 리액트 프로젝트 빌드 2. S3에 업로드

iamiet.tistory.com

 

 

● Workflow 작성하기

깃 체크아웃

우선 제일먼저 코드를 사용할 수 있도록 깃 체크아웃을 해준다.

- name: 코드 체크아웃
  id: checkout-code
  uses: actions/checkout@v3

 

AWS IAM 사용자 설정

클라이언트와 동일하게 Github Actions Agent에서 ECR에 이미지를 업로드하기 위해 AWS CLI를 사용한다.

  - name: AWS IAM 사용자 설정
    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 }}

또한 ECR에 접근하기 위해 IAM 유저에 AmazonEC2ContainerRegistryFullAccess 권한을 부여해줘야한다.

IAM 권한

 

 

ECR에 로그인

Docker를 사용해서 빌드한 Image를 ECR에 업로드하기 위해서는 ECR에 먼저 로그인을 해줘야한다.

aws-actions에서 제공해주는 amazon-ecr-login을 사용해준다.

  - name: ECR에 로그인
    uses: aws-actions/amazon-ecr-login@v1

 

aws-actions/amazon-ecr-login : https://github.com/aws-actions/amazon-ecr-login

 

GitHub - aws-actions/amazon-ecr-login: Logs into Amazon ECR with the local Docker client.

Logs into Amazon ECR with the local Docker client. - GitHub - aws-actions/amazon-ecr-login: Logs into Amazon ECR with the local Docker client.

github.com

 

 

Docker 이미지 빌드

일반적으로 사용하는 명령어와 크게 다를게 없다. Agent 환경에서 빌드를 시켜주면 된다

  - name: 도커 이미지 빌드
    run: |
      docker build -t hdev_server .

 

 

기존 ECR Repository에 업로드 되어있는 Image 삭제

ECR의 경우 업로드된 이미지에 크기에 비례해서 요금이 부과된다.

개발을 진행할수록 계속 이미지가 쌓이게 되는데 방치하게되면 많은 요금이 부과되기 때문에 이전 이미지는 삭제처리를 해줘야한다.

 

appleboy/ssh-action을 사용해서 ec2에 ssh 접근이 가능하다.

 

+ 추가로 key의 경우 openssh key 형태를 사용해야 한다.

  - name: 기존 ECR에 업로드된 lastest 태그 이미지 삭제
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        aws ecr batch-delete-image --profile ${{ secrets.IAM_PROFILE_USERNAME }} --repository-name hellodeveloper --image-ids imageTag=latest

 

 

 

EC2에서 ECR에 로그인하기

ECR로그인 진행시 발급되는 토큰은 유효시간이 1시간이라 계속해서 발급해줘야 한다.

그리 오래걸리지 않는 작업이 재발급 해주면 된다.

  - name: EC2에서 ECR에 로그인하기
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        aws ecr get-login-password --profile ${{ secrets.IAM_PROFILE_USERNAME }} --region ${{ secrets.AWS_REGION }} | sudo docker login --username AWS --password-stdin ${{ secrets.ECR_URI }}

 

 

EC2에서 실행중인 Docker Container 종료하기

기존 실행중인 컨테이너/이미지를 삭제해줘야 새롭게 실행할 환경과 충돌되지 않는다.

아래 명령어로 실행중인 Docker Container의 목록을 가져와서 만약 실행중인 컨테이너가 있으면 종료시켜준다.

  - name: 기존 EC2에서 실행중인 컨테이너 종료
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        sudo docker ps -q | xargs -r docker stop

 

 

EC2에 존재하는 모든 Container 삭제하기

기존에 실행중인 컨테이너 종료가 완료되면 종료된 컨테이너들도 다 삭제처리를 해준다.

EC2의 저장공간은 무한하지 않기때문에 자원을 아껴야한다

  - name: 기존 EC2에 존재하는 모든 컨테이너 삭제
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        sudo docker ps -asq | xargs -r docker rm

 

 

EC2에 존재하는 모든 Docker Image 삭제

추후 ECR에서 가져올 이미지들은 용량이 생각보다 크다. 이게 저장공간에 계속 쌓이게되면 용량부족이 발생할수도 있다.

  - name: 기존 EC2에 저장되어있는 이미지 삭제
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        sudo docker images -q | xargs -r docker rmi

 

 

Docker에서 사용하지 않는 자원 삭제처리

위 과정에서 사용하지 않을 예정인 자원들은 삭제처리하긴 했지만, 여전히 일부 자원이 남아있을수도 있다.

아래 명령어로 남아있는 자원을 모두 삭제해준다.

  - name: EC2에서 도커에서 사용하지 않는 자원 삭제처리
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        sudo docker system prune -af

 

 

Github Actions Agent에서 업로드한 Docker 이미지 가져오기

이제 기존에 빌드이후에 업로드한 Docker 이미지를 ECR에서 가져오면 된다.

  - name: EC2에서 도커 이미지를 가져오기
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_IP }}
      username: ${{ secrets.EC2_USERNAME }}
      key: ${{ secrets.EC2_SSH_KEY }}
      script: |
        sudo docker pull ${{ secrets.ECR_URI }}

 

 

가져온 Docker 이미지를 실행하기

마지막으로 ECR에서 가져온 Docker 이미지를 실행시키면 배포가 끝난다.

  - name: ECR에서 불러온 이미지를 도커에서 실행
    uses: appleboy/ssh-action@master
    with:
      host: ${{ secrets.EC2_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:5000 ${{ secrets.ECR_URI }}

 

 

● 테스트

작업이 열심히 돌아가는 모습..

 

성공..!

 

48초 전에 실행된 컨테이너인것을 확인할 수 있다.

 

 

● 최종구성도

반응형