[Docker] Docker & CI/CD 자동 배포 구축 매뉴얼

지원·2026년 1월 17일

DevOps

목록 보기
1/2
post-thumbnail

1. 사전 준비 (Prerequisites)

가장 먼저 준비되어야 할 계정과 서버입니다.

  • AWS EC2 인스턴스(Ubunutu): 서버가 생성되어 있고 SSH 접속이 가능해야 함. (인바운드 룰에 22 포트 등록해야함)
  • Docker Hub 계정: 이미지를 저장할 저장소(Access Token 발급 필수)
  • Github Repository: 프로젝트 소스 코드가 올라갈 곳.

2. 서버(EC2) 환경 설정 (최초 1회)

EC2 서버에 접속하여 배포에 필요한 환경을 만듭니다.

2-1. Docker 설치 및 권한 설정

# Install Docker
sudo apt update
sudo apt install docker.io -y

# ubuntu 유저에게 Docker 실행 권한 부여 (sudo 없이 쓰기 위해)
sudo usermod -aG docker ubuntu

# 설정 적용을 위해 쉘 로그아웃 하고 다시 SSH 접속
exit

2-2. 디렉토리 및 설정 파일 준비

Docker 컨테이너가 읽어야 할 보안 설정파일(properties or yml)은 서버에 직접 심어둡니다.
(보안상의 이유로 운영 설정파일은 github에 올리지 않기 때문에 직접 설정합니다.)

# 프로젝트 폴더 생성
mkdir -p ~/app/<project-name>

# 설정 파일 생성 및 내용 붙여넣기 (DB 비밀번호, JWT secret 등)
vi ~/app/<project-name>/src/main/resources/application-prod.properties

3. GitHub Secrets 설정

Github 저장소의 Settings > Secrets and variables > Actions에 아래 변수들을 등록합니다.

Secret 이름내용
DOCKER_USERNAMEDocker Hub 아이디(이메일 아님)
DOCKER_PASSWORDDocker Hub Access Token(비밀번호 대신 권장)
EC2_HOSTEC2 Public IP 주소(또는 도메인)
EC2_USERNAMEubuntu
EC2_SSH_KEYEC2접속용 .pem 키 내용 전체(-----BEGIN-----포함)

4. 프로젝트 파일 생성(local)

이제 프로젝트(IntelliJ 등)에서 3개의 파일을 만들거나 수정합니다.

4-1. Dockerfile (프로젝트 최상위 경로)

서버 환경을 이미지로 정의하는 파일입니다.

FROM eclipse-temurin:17-jdk

ARG JAR_FILE=build/libs/life-manager-1.0.0.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]

4-2. deploy.sh (프로젝트 최상위 경로)

서버에서 실제로 컨테이너를 갈아끼우는 스크립트입니다.

#!/bin/bash

# Docker 이미지 이름(본인 ID로 수정 필수)
DOCKER_APP_NAME="<your-docker-id>/<project-name>"

echo "===== Docker 배포 시작 ====="

# 기존 컨테이너가 있다면 중지 및 삭제
if ["$(docker ps -a -q -f name=<container-name>)"]; then
   echo "Stopping and removing existing container..."
   docker stop <container-name>
   docker rm <container-name>
fi

# 기존 이미지 삭제 (용량 확보, 에러 무시)
echo "Removing old image..."
docker rmi $DOCKER_APP_NAME:latest 2>/dev/null || true

# 새 이미지 다운로드
echo "Pulling new image..."
docker pull $DOCKER_APP_NAME:latest

# 새 컨테이너 실행(Volumne mount 포함)
echo "Running container..."
docker run -d -p 9000:9000 \
--name <container-name> \
-v /home/ubuntu/app/<project-name>/src/main/resources/application-prod.properties:/config/application-prod.properties \
$DOCKER_APP_NAME:latest

# 불필요한 이미지 정리
docker image prune -f

echo "===== Docker 배포 완료 ====="

4-3. .github/workflows/deploy.yml

GitHub Actions가 수행할 작업 지시입니다.

name: Deploy to EC2 with Docker

'on':
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: "17"
          distribution: "temurin"

      - name: Build with Gradle
        run: |
          chmod +x gradlew
          ./gradlew clean build -x test

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

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ secrets.DOCKER_USERNAME }}/<project-name>:latest

      - name: Deploy to EC2
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_SSH_KEY }}
          scripts: |
            cd /home/ubuntu/app/<project-name>
            git pull origin main

            chmod +x deploy.sh
            ./deploy.sh

5. 배포 실행 (Execution)

모든 준비가 끝났습니다.

  1. 로컬에서 코드를 수정합니다.
  2. git add, git commit, git push origin main을 입력합니다.
  3. GitHub Actions 탭에서 초록색 체크를 확인합니다.
  4. 서버가 자동으로 업데이트 됩니다.

💡 핵심 포인트 (Troubleshooting)

  • 설정 파일 연결: Docker는 격리된 환경이므로, EC2에 있는 application-prod.properties-v옵션으로 반드시 연결(마운트)해줘야 합니다.
  • 스크립트 갱신: deploy.yml의 script 부분에 git pull이 있어야, deploy.sh의 변경사항(포트 변경 등)이 서버에 반영됩니다.
  • 이미지 이름: deploy.shdeploy.yml에 적힌 이미지 태그(ID/repo:latest)가 정확히 일치해야 합니다.
profile
느려도 천천히라도 기록하는 백엔드 개발자👩🏻‍💻

0개의 댓글