EC2 + ECR + Docker를 활용한 CI/CD 구축 with Github Actions
우선 현재 서버의 경우 인프라가 아래처럼 구성되어 있다.
만약 서버에서 코드를 몇줄만 수정해도 아래 과정을 거쳐서 다시 배포해야 한다.
- 1. 코드 수정 후 도커 이미지 빌드
- 2. 도커 이미지를 ECR에 업로드
- 3. EC2 SSH 접속하여 업로드된 도커 이미지 다운로드
- 4. 도커 이미지 실행
변경 작업은 유지보수를 하면서 계속해서 일어나게 되는데 매우 비효율적으로 생각됬다.
그래서 repository에 push될 경우 github actions를 사용하여 위 과정을 자동화해서 배포가 되도록 구성했다.
우선 Github Actions의 경우 이전 클라이언트에서 CI/CD를 구축하면서 적어둔게 있어 URL로 대체했다.
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 권한을 부여해줘야한다.
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초 전에 실행된 컨테이너인것을 확인할 수 있다.