이 문서에서는 Github Actions와 Docker를 활용하여 EC2 인스턴스에 자동 배포하는 CI/CD 파이프라인을 구축하는 방법을 안내합니다.

develop 브랜치로의 푸시 이벤트가 발생하면 Github Actions가 실행됩니다.지금 진행하는 프로젝트에서 당장 무중단 배포를 고려하지 않아도 되었고 최대한 빠르게 작업해야 했기 때문에 사용할 수 있는 기술들을 조합해서 간단하게 할 수 있는 방법을 찾아봤습니다.
배포 파이프라인 구축에 앞서 사전에 확인하고 준비해야 하는 내용들입니다.
Docker Hub 계정
Docker 이미지를 빌드하고 푸시하기 위해서는 Docker Hub 계정이 필요합니다. [Docker Hub 웹사이트]
적절한 접근 권한을 가진 AWS 계정
AWS 서비스를 사용하기 위해 적절한 접근 권한을 가진 계정이 필요합니다. AWS IAM을 사용하여 역할 및 사용자를 생성하고 액세스 키 ID와 시크릿 액세스 키를 발급받으세요.
EC2에 접근하기 위해 권한 정책에 AmazonEC2FullAccess가 포함되어 있어야합니다.

Bastion 호스트와 프라이빗 EC2 인스턴스 설정
배포 작업을 위해 Bastion Host와 프라이빗 EC2 인스턴스가 설정되어 있어야 합니다. Bastion Host를 통해 프라이빗 서브넷에 있는 EC2 인스턴스에 접근하게 됩니다.
Bastion 호스트에서 key 설정
원격 명령 실행을 위해 Bastion Host에 EC2 인스턴스에 접속 가능한 개인 키 파일이 위치해야 합니다. 이 개인 키 파일을 이용하여 Bastion Host를 통해 EC2 인스턴스에 SSH 연결합니다.
# Git Actions의 원격 명령 실행 step 예시
- name: Deploy to EC2 via Bastion
uses: appleboy/ssh-action@master
with:
key: ${{ secrets.BASTION_SSH_PRIVATE_KEY }}
host: ${{ secrets.BASTION_HOST }}
username: ubuntu
script: |
cp $HOME/keys/bastion-host-key ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no ubuntu@${{ secrets.EC2_HOST }} 'bash /home/ubuntu/docker-compose/deploy-dev.sh'
rm ~/.ssh/id_rsa
Bastion 호스트의 보안그룹 설정
Bastion Host에 SSH로 접근하기 위해 보안그룹의 인바운드 규칙이 설정되어 있어야 합니다. 하지만 Github Actions의 IP를 미리 확인할 수 없기 때문에 Github Actions로 배포 시 발급되는 IP를 보안그룹의 인바운드 규칙에 추가할 수 있는 AWS CLI 명령어를 사용합니다.
# Git Actions의 보안그룹 설정 step 예시
- name: Add Github Actions IP to Security group
run: |
aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
도커 컴포즈 설정
앱을 배포할 EC2 인스턴스에는 도커 컴포즈 파일이 설정되어 있어야 합니다. 도커 컴포즈를 통해 앱의 서비스와 환경 변수 등을 정의합니다.
위의 사전 준비 사항을 완료하면 Github Actions와 Docker를 활용하여 EC2에 배포할 수 있는 준비가 완료됩니다. 이제 아래의 워크플로우 설정 및 각 단계의 역할에 대해 알아보겠습니다.
Github Actions 워크플로우는
.github/workflows/폴더에 정의됩니다. 아래는 전체 워크플로우 코드와 주요 단계의 역할에 대한 설명입니다
name: CD - push docker hub (dev)
on:
push:
branches:
- develop
jobs:
deploy:
name: deploy
runs-on: ubuntu-20.04
steps:
# 1. 코드 체크아웃
- uses: actions/checkout@v2
- name: CHECK ROOT PATH
run: ls -a
# 2. deployId 생성 및 수정
- name: GENERATE deployId
run: echo deployId=$(uuidgen) > ./deployId.env
- name: PRINT CURRENT deployId
run: cat deployId.env
- name: CONCAT deployId TO .env
run: cp .env.dev .env-src.dev && cat deployId.env .env-src.dev > .env.dev
- name: CHANGE .env FOR DEV MODE
run: cp .env.dev .env
# 3. 도커 빌드 및 푸시
- name: DOCKER VERSION CHECK
run: docker --version
- name: DOCKER LOGIN
run: export CR_PAT=${{ secrets.PCK_KEY }} && echo $CR_PAT | docker login -u user --password-stdin
- name: DOCKERIZING, PUSH
run: sh dockerizing-dev.sh
# 4. IP 보안그룹에 추가
- name: Get Github Actions IP
id: ip
uses: haythem/public-ip@v1.2
- 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: eu-central-1
- name: Add Github Actions IP to Security group
run: |
aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
# 5. Bastion Host를 통한 ssh 원격 명령어 실행 및 배포
- name: Deploy to EC2 via Bastion
uses: appleboy/ssh-action@master
with:
key: ${{ secrets.BASTION_SSH_PRIVATE_KEY }}
host: ${{ secrets.BASTION_HOST }}
username: ubuntu
script: |
cp $HOME/keys/bastion-host-key ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no ubuntu@${{ secrets.EC2_HOST }} 'bash /home/ubuntu/docker-compose/deploy-dev.sh'
rm ~/.ssh/id_rsa
# 6. IP 보안 그룹에서 제거
- name: Remove Github Actions IP From Security Group
run: |
aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
.env 설정 파일이 이에 맞게 수정됩니다.Github Actions와 Docker를 활용하여 EC2에 자동 배포하는 CI/CD 파이프라인을 구축하는 방법을 알아봤습니다. 모두 성공적인 배포 프로세스를 구축하실수 있으시기를 응원합니다.