Docker + GitHub Actions CI/CD 파이프라인 구축하기 - 코드픽 블로그
Docker + GitHub Actions CI/CD 파이프라인 구축하기
기술 가이드

Docker + GitHub Actions CI/CD 파이프라인 구축하기

2026년 2월 28일 43 views by 코드벤터

Docker + GitHub Actions CI/CD 파이프라인 구축하기

코드를 main 브랜치에 푸시하는 순간, 자동으로 Docker 이미지가 빌드되고 서버에 배포된다면 어떨까요? GitHub Actions와 Docker를 결합하면 이 모든 과정을 무료로, 그리고 간단하게 구현할 수 있습니다. 이 글에서는 처음부터 끝까지 실전 CI/CD 파이프라인을 구축하는 방법을 소개합니다.


CI/CD란 무엇인가?

**CI(Continuous Integration)**는 코드 변경 사항을 자동으로 빌드하고 테스트하는 과정이고, **CD(Continuous Deployment)**는 테스트를 통과한 코드를 자동으로 배포하는 과정입니다. 이 두 가지를 합치면 개발자가 코드를 올리는 것만으로 전체 배포 흐름이 돌아가는 자동화 시스템이 완성됩니다.


전체 흐름 한눈에 보기

단계도구역할
코드 푸시Git / GitHub트리거 발생
빌드 & 테스트GitHub Actions이미지 생성 및 검증
이미지 저장Docker Hub / GHCR컨테이너 레지스트리
배포SSH + Docker실서버 컨테이너 업데이트

Step 1: 애플리케이션과 Dockerfile 준비

먼저 간단한 Python Flask 앱과 Dockerfile을 만들겠습니다.

python
# app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello from CI/CD Pipeline!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
dockerfile
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["python", "app.py"]

멀티 스테이지 빌드를 활용하면 최종 이미지 크기를 크게 줄일 수 있습니다.

dockerfile
# Dockerfile (멀티 스테이지)
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 5000
CMD ["python", "app.py"]

Step 2: GitHub Secrets 설정

워크플로에서 사용할 민감한 정보는 절대 코드에 직접 넣으면 안 됩니다. GitHub 저장소의 Settings > Secrets and variables > Actions에서 아래 항목을 추가합니다.

code
DOCKER_USERNAME    → Docker Hub 사용자명
DOCKER_PASSWORD    → Docker Hub 액세스 토큰
SSH_HOST           → 배포 서버 IP
SSH_USERNAME       → 서버 접속 계정 (예: ubuntu)
SSH_PRIVATE_KEY    → PEM 형식 개인키

Step 3: GitHub Actions 워크플로 작성

.github/workflows/ci-cd.yml 파일을 생성합니다.

yaml
name: Docker CI/CD Pipeline

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read

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

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

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ secrets.DOCKER_USERNAME }}/my-flask-app
          tags: |
            type=sha,format=short
            type=raw,value=latest,enable=${{ github.ref == refs/heads/main }}

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

      - name: Build and push Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    runs-on: ubuntu-latest
    needs: build-and-push
    environment: production

    steps:
      - name: Deploy to server via SSH
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull ${{ secrets.DOCKER_USERNAME }}/my-flask-app:latest
            docker stop flask-app || true
            docker rm flask-app || true
            docker run -d \
              --name flask-app \
              --restart unless-stopped \
              -p 5000:5000 \
              ${{ secrets.DOCKER_USERNAME }}/my-flask-app:latest
            echo "Deployment complete!"

Step 4: 배포 전 테스트 자동화

배포 전에 유닛 테스트를 실행하는 job을 추가하는 것이 중요합니다.

yaml
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: pip install -r requirements.txt pytest

      - name: Run tests
        run: pytest tests/ -v

build-and-push job에 needs: test를 추가해 테스트가 통과해야만 빌드가 실행되도록 합니다.

yaml
  build-and-push:
    runs-on: ubuntu-latest
    needs: test

Step 5: .dockerignore 설정

빌드 컨텍스트에서 불필요한 파일을 제외하면 이미지 크기와 빌드 시간이 줄어듭니다.

text
.git
.github
__pycache__
*.pyc
.env
.venv
node_modules
tests/
README.md

워크플로 주요 설정 요약

설정 항목권장 값이유
runs-onubuntu-latest최신 안정 환경
cache-from/cache-totype=gha빌드 속도 향상
이미지 태그sha + latest버전 추적 및 롤백 용이
액션 버전 고정@v4, @v3 등공급망 보안
Secrets 관리GitHub Secrets민감 정보 보호

자주 발생하는 오류와 해결법

오류 1: docker permission denied
서버에서 sudo usermod -aG docker $USER 실행 후 재접속하면 해결됩니다.

오류 2: SSH 연결 타임아웃
GitHub Actions IP 대역을 서버 방화벽에서 허용하거나 포트 22를 개방해두어야 합니다.

오류 3: 레이어 캐시 미적용
docker/setup-buildx-action이 먼저 실행되었는지, cache-from 설정이 올바른지 확인하세요.


마무리

Docker + GitHub Actions 조합은 복잡한 CI/CD 인프라 없이도 전문적인 자동화 배포 환경을 구성할 수 있게 해줍니다. 코드 푸시 한 번으로 테스트, 빌드, 배포가 자동으로 완료되는 파이프라인은 개발 생산성을 크게 높여줍니다.

코드벤터는 실무에서 바로 활용할 수 있는 DevOps 지식과 개발 자동화 노하우를 꾸준히 정리해 공유합니다. Kubernetes 배포나 멀티 환경 파이프라인이 궁금하다면 코드픽(codepick.kr)의 다음 글도 기대해주세요.

개발 의뢰 상담

AI 서비스나 플랫폼 개발을
고민 중이신가요?

CodePick에서는
기획 → 개발 → 운영까지 함께합니다.
아이디어만 있어도 상담 가능합니다.

CodeVenter 개발팀이 직접 담당 · 1~2 영업일 내 회신

✓ 스타트업 MVP 개발✓ AI 서비스 개발✓ 웹 플랫폼 개발✓ 기업 시스템 구축✓ 모바일 앱 개발

AI Development Studio

코드픽 by 코드벤터

  • 대표: 윤승환 · 사업자등록번호: 121-57-64983
  • 대구광역시 중구 국채보상로 586, 16층 · info@codeventer.com

© 2025 코드벤터. All rights reserved.