개발을 진행하고 배포 자동화를 위해 Docker Hub, Github Action으로 자동 배포를 구현해보려 한다.

1. Docker Hub 설정
Docker hub에선 크게 두 가지를 해야한다.
1.access token 생성




2. Repository 생성

개인 프로젝트로 진행하기에, private로 설정했다.

2. Actions secrets 설정
자동 배포를 위해서는 dockerhub username, token, ec2 정보등 Repository에 저장되어야 한다.

New repositroy secret을 눌러 등록해 준다.

3. EC2 서버 Docker 설치
Docker 설치
1. 패키지 리스트 최신으로 업데이트
sudo apt update
2. 도커 다운로드를 위해 필요한 https 관련 패키지 설치
sudo apt install apt-transport-https ca-certificates curl software-properties-common
3. 도커 레포지토리 접근을 위한 GPG Key 설정
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
4. 도커 레포지토리 등록
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
5. 방금 등록한 도커 레포지토리를 포함하여 패키지 리스트 다시 업데이트
sudo apt update
6. 도커 설치
sudo apt install docker-ce
7. 실행 확인
sudo systemctl status docker

docker-compose 설치
1. 도커 컴포즈 설치
sudo curl -L "https://github.com/docker/compose/releases/download/2.39.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
최신 버전 확인
https://github.com/docker/compose/releases
- 원하는 버전으로 설치할 경우 2.39.2 부분을 변경해주면 된다.
2. 권한 부여
sudo chmod +x /usr/local/bin/docker-compose
3. 심볼릭 링크 설정
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
4. 버전확인
docker compose version

4. workflow 작성
name: Build & Push to Docker Hub + Deploy to EC2
on:
push:
branches: [ "main" ] # main 브랜치에 push될 때 실행
workflow_dispatch: # 수동 실행도 가능
concurrency:
group: docker-push # 동일 그룹의 워크플로우가 실행되면 이전 것은 취소
cancel-in-progress: true
env:
IMAGE_NAME: mayhun28/fastapi-crud # Docker Hub에 올릴 이미지 이름 (username/repo)
jobs:
# Docker 이미지 빌드 & 푸시
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4 # 레포지토리 소스코드 가져오기
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 # Buildx 세팅 (멀티 플랫폼 빌드 가능)
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USER }} # GitHub Secrets에서 계정 가져오기
password: ${{ secrets.DOCKERHUB_TOKEN }} # 액세스 토큰 사용
- name: Build & Push (latest + sha)
uses: docker/build-push-action@v6
with:
context: . # 현재 디렉토리 기준
push: true # 빌드 후 푸시
tags: | # 두 개의 태그를 동시에 푸시
docker.io/${{ env.IMAGE_NAME }}:latest
docker.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha # GitHub Actions 캐시 활용
cache-to: type=gha,mode=max
- name: Verify pushed image
run: |
# 푸시된 이미지가 정상적으로 올라갔는지 확인
docker buildx imagetools inspect docker.io/${{ env.IMAGE_NAME }}:${{ github.sha }}
# EC2 서버에 배포
deploy-to-ec2:
runs-on: ubuntu-latest
needs: build-and-push # build-and-push job이 끝난 후 실행
steps:
- name: Checkout
uses: actions/checkout@v4 # 다시 소스코드 체크아웃 (docker-compose.yml 필요)
- name: Ensure app dir on EC2
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.EC2_HOST }} # EC2 호스트 IP/도메인
username: ${{ secrets.EC2_USER }} # EC2 접속 계정
key: ${{ secrets.EC2_SSH_KEY }} # SSH 개인키
script: |
set -e
mkdir -p "$HOME/app" # 배포할 디렉토리 생성
- name: Upload docker-compose.yml to EC2
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
source: "docker-compose.yml" # 로컬 파일
target: "/home/${{ secrets.EC2_USER }}/app" # EC2 경로
- name: Deploy on EC2 (pull & restart with SHA tag)
uses: appleboy/ssh-action@v1
env:
IMAGE_TAG: ${{ github.sha }} # GitHub SHA 해시를 태그로 사용
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
envs: IMAGE_TAG
script: |
set -euo pipefail
cd "$HOME/app"
# Docker Hub 로그인 (패스워드 안전하게 입력)
echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u "${{ secrets.DOCKERHUB_USER }}" --password-stdin
# 어떤 태그로 실행되는지 출력
echo "Using IMAGE_TAG=$IMAGE_TAG"
# 최신 이미지 pull 후 컨테이너 재시작
IMAGE_TAG="$IMAGE_TAG" docker compose up -d --pull always --no-build
5. 테스트
main branch에 push가 되면 자동으로 workflow가 동작하여, docker image 빌드를 하고, dockerhub에 업로드 하고, ec2서버에서 docker-compose.yml파일 업로드를 하고 이미지 기반으로 실행을 한다.

Reference
'WEB 개발' 카테고리의 다른 글
| [OAuth] OAuth2.0 이란? (0) | 2025.09.02 |
|---|---|
| [FastAPI] FileUpload, FileDownload (feat.BackgroundTasks) (0) | 2025.08.30 |
| [AWS] EC2 인스턴스 생성하기 (2) | 2025.08.25 |
| [FastAPI] 비밀번호 변경 구현하기(feat. Redis, SMTP) (2) | 2025.07.25 |
| [FastAPI] JWT 로그인 로그아웃 구현 (SQLAlchemy, RESTful API, JWT) (0) | 2025.06.02 |