GitHub Actions와 Docker로/배포를 자동화하는 방법 (2025년)

안녕하세요! 2025년, 개발 환경은 그 어느 때보다 빠르게 변화하고 있습니다. 특히 GitHub Actions와 Docker를 활용한 배포 자동화는 현대 소프트웨어 개발의 핵심 트렌드로 자리 잡았죠. 이 포스트에서는 GitHub Actions를 이용해 Docker 컨테이너를 자동으로 빌드하고 배포하는 실용적인 스크립트 예제를 공유하며, 여러분의 개발 워크플로우를 한 단계 업그레이드할 수 있는 방법을 자세히 안내해 드릴게요. 복잡한 배포 과정을 자동화하여 시간을 절약하고 오류를 줄이는 마법 같은 경험을 지금 바로 시작해 보세요!

개발의 속도가 점점 더 중요해지는 요즘, 수동 배포는 시간 낭비이자 휴먼 에러의 주범이 될 수 있습니다. 저 역시 매번 서버에 접속해 빌드하고 배포하는 과정이 번거롭게 느껴졌어요. 그러다 GitHub Actions와 Docker 컨테이너를 조합한 자동화 시스템을 구축한 후, 개발 라이프가 완전히 달라졌답니다. 이제 코드 푸시 한 번으로 모든 배포 과정이 자동으로 처리되니, 개발에만 온전히 집중할 수 있게 되었죠.

이 글에서는 GitHub Actions를 활용해 Docker 이미지를 빌드하고, Docker Hub에 푸시한 다음, 최종적으로 원격 서버에 SSH로 접속하여 컨테이너를 배포하는 과정을 단계별로 상세하게 설명해 드릴 거예요. 여러분도 이 가이드를 통해 자신만의 강력한 CI/CD 파이프라인을 구축할 수 있을 겁니다.

GitHub Actions를 활용한 Docker 컨테이너 배포 자동화 과정을 시각적으로 표현한 그림. 코드 저장소에서 컨테이너 배포 서버로 매끄럽게 연결되는 모습.

⚙️ GitHub Actions와 Docker, 왜 함께 사용해야 할까요?

현대의 소프트웨어 개발에서 CI/CD(연속 통합/연속 배포)는 선택이 아닌 필수입니다. CI/CD를 통해 개발자는 코드 변경 사항을 더 자주 통합하고, 테스트하며, 배포할 수 있게 되죠. 이는 소프트웨어의 품질을 높이고 시장 출시 시간을 단축시키는 데 결정적인 역할을 합니다.

  • GitHub Actions의 장점: GitHub에 내장된 CI/CD 도구로, 별도의 서버를 구축할 필요 없이 코드 변경에 반응하여 다양한 자동화 작업을 수행할 수 있습니다. 무료 사용량이 넉넉하고, 워크플로우 설정이 직관적이라 빠르게 도입할 수 있다는 장점이 있어요.
  • Docker의 이점: 애플리케이션과 그 모든 종속성을 컨테이너라는 격리된 환경에 패키징하여, 어느 환경에서든 일관된 실행을 보장합니다. '내 컴퓨터에서는 되는데 서버에서는 안 돼요'라는 변명을 사라지게 만들죠!

이 둘을 함께 사용하면, 코드를 GitHub에 푸시하는 순간부터 Docker 이미지가 빌드되고, 컨테이너 레지스트리에 푸시되며, 최종적으로 운영 서버에 배포되는 전체 과정을 매끄럽게 자동화할 수 있습니다. 정말 편리하지 않나요?

📝 배포 자동화를 위한 기본적인 준비 사항

워크플로우 스크립트를 작성하기 전에 몇 가지 준비해야 할 것들이 있습니다.

  1. GitHub 레포지토리: 당연히 소스 코드가 GitHub에 있어야겠죠?
  2. Dockerfile: 여러분의 애플리케이션을 Docker 컨테이너로 만들기 위한 `Dockerfile`이 프로젝트 루트에 준비되어 있어야 합니다. 간단한 Node.js 앱을 예로 들어볼게요.
# Dockerfile 예제
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
  1. Docker Hub 계정: 빌드된 이미지를 저장할 컨테이너 레지스트리가 필요합니다. 여기서는 Docker Hub를 사용하지만, AWS ECR, Google GCR 등 다른 레지스트리도 유사하게 적용할 수 있습니다.
  2. GitHub Secrets 설정: 보안을 위해 민감한 정보(Docker Hub 사용자 이름, 토큰, SSH 프라이빗 키 등)는 GitHub Secrets에 저장해야 합니다. 레포지토리 설정에서 Settings > Secrets and variables > Actions > New repository secret 으로 이동하여 다음 정보를 추가해 주세요.
    • DOCKER_USERNAME: Docker Hub 사용자 이름
    • DOCKER_TOKEN: Docker Hub Access Token (Settings > Security > New Access Token에서 생성)
    • SSH_PRIVATE_KEY: 원격 배포 서버에 접속할 프라이빗 키
    • DEPLOY_HOST: 배포할 서버의 IP 주소 또는 도메인
    • DEPLOY_USER: 배포 서버 접속 사용자 이름

🚀 실제 GitHub Actions 워크플로우 스크립트 예제

이제 가장 중요한 워크플로우 스크립트 예제를 살펴볼 시간입니다. GitHub 레포지토리의 `.github/workflows/deploy.yml` 경로에 아래 내용을 추가해 주세요. 파일 이름은 자유롭게 지정할 수 있습니다.

# .github/workflows/deploy.yml
name: CI/CD with Docker

on:
  push:
    branches:
      - main # main 브랜치에 푸시될 때 워크플로우 실행

env:
  DOCKER_IMAGE_NAME: my-node-app # Docker Hub에 올릴 이미지 이름
  DOCKER_TAG: latest # 이미지 태그
  DOCKER_REPO: ${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker BuildX
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.DOCKER_REPO }}:${{ env.DOCKER_TAG }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Deploy to remote server via SSH
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script:
            - docker pull ${{ env.DOCKER_REPO }}:${{ env.DOCKER_TAG }}
            - docker stop ${{ env.DOCKER_IMAGE_NAME }} || true
            - docker rm ${{ env.DOCKER_IMAGE_NAME }} || true
            - docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -p 3000:3000 ${{ env.DOCKER_REPO }}:${{ env.DOCKER_TAG }}
            - docker image prune -f
소스 코드가 Docker 이미지로 빌드되어 컨테이너 레지스트리에 푸시되는 CI/CD 파이프라인의 시각화.

🔍 워크플로우 분석 및 이해하기

작성된 워크플로우 스크립트가 어떤 역할을 하는지 자세히 살펴볼까요?

  • name: 워크플로우의 이름입니다. GitHub Actions UI에서 이 이름으로 표시됩니다.
  • on: 워크플로우가 언제 실행될지를 정의합니다. 여기서는 main 브랜치에 코드가 푸시될 때마다 실행되도록 설정했습니다.
  • env: 워크플로우 전반에 걸쳐 사용될 환경 변수를 정의합니다. 이미지 이름, 태그 등을 이곳에서 관리하면 편리합니다.
  • jobs: 워크플로우의 주요 작업 단위를 정의합니다. 여기서는 build-and-deploy라는 하나의 잡(Job)이 있습니다.
  • runs-on: 잡이 실행될 가상 환경을 지정합니다. ubuntu-latest는 최신 우분투 환경에서 실행됨을 의미합니다.
  • steps: 잡 내부에서 순차적으로 실행될 개별 작업들입니다. 각 uses는 미리 정의된 GitHub Actions 마켓플레이스 액션을 사용하고, name은 해당 단계의 설명을 나타냅니다.
    • Checkout code: 레포지토리 코드를 워커(Runner)로 가져옵니다.
    • Set up Docker BuildX: Docker 빌드를 위한 환경을 설정합니다. 빌드 속도를 높이는 데 도움이 됩니다.
    • Login to Docker Hub: Docker Hub에 로그인하여 이미지를 푸시할 준비를 합니다.
    • Build and push Docker image: 프로젝트 루트의 Dockerfile을 사용하여 이미지를 빌드하고 Docker Hub에 푸시합니다. cache-from, cache-to를 통해 빌드 캐시를 활용하여 다음 빌드 시간을 단축할 수 있습니다.
    • Deploy to remote server via SSH: appleboy/ssh-action을 사용하여 원격 서버에 SSH로 접속하고, 미리 정의된 배포 스크립트를 실행합니다. 스크립트 내용은 다음과 같습니다.
      • docker pull ...: 최신 Docker 이미지를 서버로 가져옵니다.
      • docker stop ...: 현재 실행 중인 컨테이너를 중지합니다. (없으면 오류 무시)
      • docker rm ...: 중지된 컨테이너를 삭제합니다. (없으면 오류 무시)
      • docker run -d ...: 최신 이미지를 사용하여 새로운 컨테이너를 백그라운드에서 실행합니다.
      • docker image prune -f: 사용하지 않는 Docker 이미지를 정리하여 디스크 공간을 확보합니다.

🔒 배포 서버 설정 (SSH 접속)

appleboy/ssh-action을 통해 원격 서버에 접속하려면, 서버에 SSH 키 기반 인증이 설정되어 있어야 합니다. GitHub Secrets에 등록한 SSH_PRIVATE_KEY에 해당하는 공개 키(Public Key)를 배포 서버의 ~/.ssh/authorized_keys 파일에 추가해야 합니다.

💡 팁: ssh-keygen -t rsa -b 4096 -C "your_email@example.com" 명령어로 SSH 키 쌍을 생성할 수 있습니다. 이때 생성되는 id_rsa 파일의 내용을 SSH_PRIVATE_KEY에, id_rsa.pub 파일의 내용을 서버의 authorized_keys에 추가하면 됩니다.

또한, 배포 서버에 Docker가 설치되어 있고, DEPLOY_USER가 Docker 명령을 실행할 권한이 있는지 확인해야 합니다. 일반적으로 사용자를 docker 그룹에 추가하면 됩니다. (예: sudo usermod -aG docker your_username 후 재로그인)

GitHub Actions 러너가 SSH를 통해 원격 서버에 접속하여 Docker 컨테이너를 배포하는 보안 연결 과정.
⚠️ 경고: SSH_PRIVATE_KEY는 절대로 외부에 노출되어서는 안 됩니다. GitHub Secrets에 저장하는 것이 가장 안전한 방법이며, 개인 컴퓨터에도 철저히 보호해야 합니다. 또한, 배포 서버의 방화벽 설정(예: UFW)을 통해 SSH 포트(기본 22번)와 애플리케이션 포트(예: 3000번)만 허용하는 것이 보안에 좋습니다.

✨ 마치며: 당신의 개발 워크플로우를 혁신하세요!

이제 여러분은 GitHub Actions와 Docker를 활용하여 코드를 푸시하는 것만으로 애플리케이션을 자동으로 배포할 수 있는 강력한 시스템을 구축하는 방법을 알게 되었습니다. 수동 배포의 번거로움과 위험에서 벗어나, 더욱 효율적이고 안정적인 개발 프로세스를 경험하게 될 거예요.

2025년의 개발 환경은 자동화 없이는 상상하기 어렵습니다. 이 스크립트 예제를 시작점으로 삼아, 여러분의 프로젝트에 맞게 워크플로우를 더욱 커스터마이징하고 개선해 나가 보세요. 예를 들어, 테스트 자동화 단계를 추가하거나, 배포 성공/실패 시 Slack 알림을 보내는 기능 등을 추가할 수 있습니다. 이 작은 변화가 여러분의 개발 생산성에 엄청난 차이를 가져올 거라 확신해요!

💡 핵심 요약
  • GitHub Actions와 Docker 조합은 CI/CD의 강력한 자동화 도구입니다. 코드 푸시부터 배포까지 전 과정을 자동화하여 개발 효율을 극대화할 수 있어요.
  • Dockerfile 및 GitHub Secrets 설정이 필수적입니다. Dockerfile로 앱을 컨테이너화하고, 민감 정보는 Secrets에 안전하게 보관하세요.
  • YAML 워크플로우 스크립트는 빌드, 푸시, 배포 단계를 정의합니다. 각 단계별로 필요한 액션을 조합하여 파이프라인을 구축할 수 있습니다.
  • SSH 키 기반 인증과 서버 권한 설정은 보안과 배포 안정성을 위해 중요합니다. 올바른 서버 설정을 통해 안전한 자동 배포를 구현하세요.
이 핵심 요약은 GitHub Actions를 활용한 Docker 컨테이너 배포 자동화의 가장 중요한 포인트를 담고 있습니다. 여러분의 프로젝트에 바로 적용해 보세요!

❓ 자주 묻는 질문 (FAQ)

Q1: GitHub Actions는 무료로 사용할 수 있나요?

네, GitHub Actions는 공개 레포지토리의 경우 무제한으로 무료로 사용할 수 있으며, 프라이빗 레포지토리의 경우에도 매월 일정 시간(Free 플랜의 경우 2,000분)이 무료로 제공됩니다. 이 시간을 초과하면 사용량에 따라 요금이 부과되지만, 개인 프로젝트나 소규모 팀에서는 충분히 무료로 활용 가능합니다.

Q2: Docker Hub 대신 다른 컨테이너 레지스트리도 사용할 수 있나요?

물론입니다! AWS ECR(Elastic Container Registry), Google Container Registry(GCR), GitLab Container Registry 등 다양한 컨테이너 레지스트리를 사용할 수 있습니다. `docker/login-action`과 `docker/build-push-action`의 `registry` 및 `username`, `password` (또는 해당 레지스트리의 인증 방식) 설정을 변경하여 쉽게 연동할 수 있습니다. 대부분의 주요 클라우드 서비스는 자체 레지스트리를 제공하며, GitHub Packages도 좋은 선택지입니다.

Q3: 배포 실패 시 어떻게 알 수 있나요?

GitHub Actions는 워크플로우 실행 결과에 대해 이메일 알림을 기본적으로 제공합니다. 또한, 워크플로우에 Slack이나 Microsoft Teams, Discord 등으로 알림을 보내는 액션(예: `slackapi/slack-github-action`)을 추가하여 실시간으로 배포 상태를 받아볼 수 있습니다. 실패 시에는 로그를 자세히 확인하여 문제의 원인을 파악하고 디버깅할 수 있습니다.

댓글