docker

도커와 CI/CD — 자동으로 빌드하고 배포하기

mirabo01 2025. 11. 12. 09:10

처음 도커를 쓸 땐 로컬 환경에서 “이미지를 빌드해서 컨테이너를 실행하는 것”만으로도 충분했습니다.
하지만 서비스가 커지고 팀 단위로 협업하게 되면,
누가 어떤 코드를 배포했는지 관리가 필요해집니다.

수동으로 docker build, docker push, docker pull을 반복하다 보면
인간이 가장 많이 실수하는 부분 — 버전 관리와 환경 일관성 — 에서 문제가 터지죠.

그래서 등장하는 게 CI/CD 파이프라인에 도커를 통합하는 방식입니다.


내가 처음 자동 배포를 시도했을 때

예전에 사이드 프로젝트를 EC2 위에서 운영할 때였습니다.
깃허브에 커밋하면 서버에 반영되도록 만들고 싶었죠.

처음엔 직접 스크립트를 짰습니다.

git pull origin main
docker build -t myapp .
docker stop myapp
docker rm myapp
docker run -d -p 80:80 myapp

이걸 deploy.sh로 만들어 놓고, 서버에서 직접 실행했습니다.
그런데 어느 순간,
배포할 때마다 사람이 들어가서 명령을 치는 게 너무 번거로웠습니다.

그때 GitHub Actions를 처음 도입했습니다.


GitHub Actions로 도커 빌드 자동화하기

GitHub Actions를 사용하면,
코드가 푸시될 때 자동으로 도커 이미지를 빌드하고
Docker Hub나 GHCR에 푸시하도록 설정할 수 있습니다.

.github/workflows/docker-deploy.yml 파일을 생성하고 아래처럼 작성합니다.

name: CI/CD with Docker

on:
  push:
    branches:
      - main

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

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

      - name: Login 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@v5
        with:
          context: .
          push: true
          tags: mydockerid/myapp:latest

이 파일을 커밋하면,
GitHub가 자동으로 코드를 받아서 이미지를 빌드하고
Docker Hub에 푸시합니다.

이걸 처음 성공시켰을 때 느꼈던 쾌감은 아직도 기억납니다.
서버에 로그인할 필요도 없이,
커밋 한 번으로 배포가 끝나니까요.


서버에서 자동으로 새 이미지 받아오기

다음 단계는 서버 쪽 자동화입니다.
Docker Hub에 새 이미지가 올라가면,
서버에서 자동으로 docker pull을 실행하도록 구성하는 거죠.

가장 간단한 방법은 GitHub Actions에 SSH 배포 단계를 추가하는 겁니다.

- name: Deploy to EC2
  uses: appleboy/ssh-action@v1.1.0
  with:
    host: ${{ secrets.EC2_HOST }}
    username: ubuntu
    key: ${{ secrets.EC2_SSH_KEY }}
    script: |
      docker pull mydockerid/myapp:latest
      docker stop myapp || true
      docker rm myapp || true
      docker run -d -p 80:80 mydockerid/myapp:latest

이렇게 하면 깃허브에 푸시 → 자동 빌드 → 자동 배포까지 전부 연결됩니다.

이게 바로 완전한 CI/CD 파이프라인의 기본 형태입니다.


Jenkins나 GitLab CI에서도 동일한 원리

회사에서 Jenkins나 GitLab CI를 쓰고 있다면 원리는 같습니다.
빌드 → 테스트 → 이미지 푸시 → 서버 배포 순서만 유지하면 됩니다.

예를 들어 Jenkins에서는 아래처럼 파이프라인을 구성합니다.

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh 'docker build -t myapp:latest .'
      }
    }
    stage('Push') {
      steps {
        sh 'docker push mydockerid/myapp:latest'
      }
    }
    stage('Deploy') {
      steps {
        sh '''
          ssh ubuntu@server '
            docker pull mydockerid/myapp:latest &&
            docker stop myapp || true &&
            docker rm myapp || true &&
            docker run -d -p 80:80 mydockerid/myapp:latest
          '
        '''
      }
    }
  }
}

도커 기반 배포의 좋은 점은,
CI/CD 툴이 바뀌어도 “빌드-푸시-실행” 패턴은 그대로 유지된다는 점입니다.


자동 배포를 도입하고 달라진 점

예전엔 개발자들이 “배포 담당자”를 기다렸습니다.
커밋하고 나면 “언제 배포돼요?”가 일상이었죠.

이제는 단 한 줄의 커밋 메시지만 보면 됩니다.
“✅ Deploy success (via Actions)”
CI/CD 시스템이 배포를 대신해주니까요.

덕분에 버그 수정, 핫픽스 반영 속도가 3배 이상 빨라졌고,
팀 내에서 배포 스트레스가 거의 사라졌습니다.


CI/CD 구축 시 기억해야 할 팁

  • latest 태그만 쓰지 말고, 커밋 SHA나 버전을 같이 써라.
  • Secrets는 절대 코드에 직접 쓰지 말고 GitHub Secrets, Jenkins Credentials로 관리하라.
  • 실패 시 Slack이나 Discord 알림을 연동하면 배포 상태를 실시간으로 확인할 수 있다.
  • 테스트가 통과된 코드만 배포하도록 자동 검증 단계를 꼭 추가하라.