Github Actions와 Docker를 활용한 EC2 자동 배포 파이프라인 구축

김지욱·2023년 9월 4일

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

전체 플로우 요약

  1. develop 브랜치로의 푸시 이벤트가 발생하면 Github Actions가 실행됩니다.
  2. 도커 이미지가 빌드 되고 Docker Hub에 푸시 합니다.
  3. SSH를 사용하여 배포할 EC2 인스턴스에서 배포 스크립트를 실행합니다.
  4. 도커 이미지를 받아와서 앱을 실행합니다.

이렇게 구성한 이유

지금 진행하는 프로젝트에서 당장 무중단 배포를 고려하지 않아도 되었고 최대한 빠르게 작업해야 했기 때문에 사용할 수 있는 기술들을 조합해서 간단하게 할 수 있는 방법을 찾아봤습니다.

사전 준비 사항

배포 파이프라인 구축에 앞서 사전에 확인하고 준비해야 하는 내용들입니다.

  1. Docker Hub 계정
    Docker 이미지를 빌드하고 푸시하기 위해서는 Docker Hub 계정이 필요합니다. [Docker Hub 웹사이트]

  2. 적절한 접근 권한을 가진 AWS 계정

    AWS 서비스를 사용하기 위해 적절한 접근 권한을 가진 계정이 필요합니다. AWS IAM을 사용하여 역할 및 사용자를 생성하고 액세스 키 ID와 시크릿 액세스 키를 발급받으세요.
    EC2에 접근하기 위해 권한 정책에 AmazonEC2FullAccess가 포함되어 있어야합니다.

  3. Bastion 호스트와 프라이빗 EC2 인스턴스 설정

    배포 작업을 위해 Bastion Host와 프라이빗 EC2 인스턴스가 설정되어 있어야 합니다. Bastion Host를 통해 프라이빗 서브넷에 있는 EC2 인스턴스에 접근하게 됩니다.

  4. 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
  5. 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
  6. 도커 컴포즈 설정

    앱을 배포할 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
  1. 코드 체크아웃: 레포지토리가 Github Actions 실행 환경으로 클론 됩니다.
  2. deployId 생성 및 수정: 고유한 배포 ID가 생성되고 .env 설정 파일이 이에 맞게 수정됩니다.
  3. 도커 빌드 및 푸시: Docker 이미지가 빌드 되고 태그가 지정되며 Docker Hub에 푸시 됩니다.
  4. IP 보안 그룹에 추가: 실행 환경의 공용 IP 주소를 가져와 Bastion Host의 보안 그룹에 추가합니다.
  5. Bastion Host를 통한 ssh 원격 명령어 실행 및 배포: SSH를 사용하여 Bastion 호스트에 연결하고 프라이빗 EC2 인스턴스에서 배포 스크립트를 실행합니다.
  6. IP 보안 그룹에서 제거: 배포 이후에 실행 환경의 IP 주소는 보안 그룹에서 제거됩니다.

Github Actions와 Docker를 활용하여 EC2에 자동 배포하는 CI/CD 파이프라인을 구축하는 방법을 알아봤습니다. 모두 성공적인 배포 프로세스를 구축하실수 있으시기를 응원합니다.

참고

0개의 댓글