Spring Boot 앱의 Docker 컨테이너화

요약

Docker로 Spring Boot 앱 컨테이너화 2026: 개발부터 배포까지 뚝딱!

2026년 최신 개발 트렌드에 맞춰, Docker를 활용하여 Spring Boot 애플리케이션을 컨테이너화하고, 개발 환경 구축부터 실제 운영 배포까지의 전 과정을 상세히 분석합니다. 컨테이너 기반 개발의 핵심 원리와 효율적인 배포 전략을 권퓨터와 함께 탐구해 보세요.

핵심 키워드: Docker, Spring Boot, 컨테이너화, 백엔드 배포, CI/CD

이 글의 순서

1. 왜 Docker와 Spring Boot 컨테이너화가 중요한가요?

2. Spring Boot 앱 컨테이너화 단계별 가이드

3. 컨테이너화 과정에서 마주치는 흔한 문제와 해결책

4. Docker Compose를 활용한 개발/배포 환경 구축

5. 자주 묻는 질문 (FAQ)

도입

1. 왜 Docker와 Spring Boot 컨테이너화가 중요한가요?

현대 소프트웨어 개발 환경에서 컨테이너 기술은 더 이상 선택 사항이 아닌 필수적인 요소로 자리매김했습니다. 특히 자바 기반의 엔터프라이즈 애플리케이션 개발에 널리 사용되는 Spring BootDocker의 조합은 개발 생산성과 배포 안정성을 극대화하는 강력한 시너지를 발휘합니다. 2026년 현재, 클라우드 네이티브 환경으로의 전환이 가속화되면서 이러한 컨테이너 기반 개발 및 배포 전략은 더욱 중요해지고 있습니다.

1.1. 컨테이너화, 개발 생태계의 혁신

컨테이너는 애플리케이션과 그 실행에 필요한 모든 환경(코드, 런타임, 시스템 도구, 라이브러리, 설정 파일 등)을 하나의 경량화된 독립적인 패키지로 묶어주는 기술입니다. 이를 통해 개발자는 “제 컴퓨터에서는 잘 작동하는데요?”라는 고질적인 환경 의존성 문제를 근본적으로 해결하고, 개발, 테스트, 운영 환경 간의 완벽한 일관성을 보장받을 수 있습니다.

컨테이너 기술의 핵심적인 장점은 다음과 같습니다:

컨테이너화의 주요 장점

✔️ 환경 일관성: 모든 환경에서 동일한 컨테이너 이미지를 사용하므로, 예측 불가능한 환경 차이로 인한 버그 발생률이 현저히 줄어듭니다.

✔️ 빠른 배포 및 확장성: 컨테이너 이미지를 통해 애플리케이션을 수 초 내에 빠르게 배포하고, 트래픽 증가에 따라 손쉽게 컨테이너 수를 늘려 확장할 수 있습니다.

✔️ 격리 및 보안: 각 컨테이너는 독립된 환경에서 실행되므로, 한 컨테이너의 문제가 다른 컨테이너나 호스트 시스템에 미치는 영향을 최소화하고 보안 취약점 전파를 방지합니다.

✔️ 효율적인 자원 활용: 가상 머신(VM)과 달리 호스트 OS의 커널을 공유하여 오버헤드가 적고, 더 가볍고 효율적으로 시스템 자원을 사용합니다.

1.2. Spring Boot와 Docker의 시너지 효과

Spring Boot는 ‘Convention over Configuration’ 철학을 기반으로 개발자가 최소한의 설정으로 빠르게 애플리케이션을 개발하고 실행할 수 있도록 지원합니다. 특히 내장형 웹 서버(Tomcat, Jetty, Undertow 등)를 포함하여 독립적으로 실행 가능한 JAR 파일을 생성하는 능력은 Docker 컨테이너의 완벽한 후보가 됩니다.

Spring Boot 애플리케이션을 Docker 컨테이너에 담는다는 것은, Spring Boot가 제공하는 “Just Run” 경험을 “Just Docker Run”으로 확장하는 것과 같습니다. 개발자는 로컬 환경에서 Docker 컨테이너를 빌드하고 테스트하며, 이 동일한 컨테이너 이미지를 변경 없이 테스트 환경, 스테이징 환경, 그리고 최종 운영 환경에까지 배포할 수 있습니다. 이는 개발 워크플로우를 극도로 단순화하고 배포 오류를 최소화하며, 전반적인 개발 주기를 단축하는 데 크게 기여합니다.

2026년, Spring Boot와 Docker는 개발 환경의 일관성, 배포의 민첩성, 그리고 운영의 안정성을 동시에 제공하는 최적의 조합으로 평가받고 있습니다. 이는 마이크로서비스 아키텍처와 클라우드 네이티브 환경으로의 전환을 가속화하는 핵심 동력이며, 모든 백엔드 개발자가 반드시 숙지해야 할 기술 스택입니다.

Spring Boot 애플리케이션과 Docker 컨테이너 연동 클라우드 아키텍처 다이어그램
Spring Boot 애플리케이션과 Docker 컨테이너 연동 클라우드 아키텍처 다이어그램

그림 1. Spring Boot와 Docker 컨테이너 연동 아키텍처 예시

핵심 내용

2. Spring Boot 앱 컨테이너화 단계별 가이드

2.1. Docker 설치 및 기본 환경 설정

Spring Boot 애플리케이션을 Docker 컨테이너에 올리기 위한 첫 단계는 로컬 개발 환경에 Docker를 설치하는 것입니다. 2026년 현재, Docker Desktop은 Windows, macOS, Linux 환경 모두에서 가장 편리하고 통합된 Docker 환경을 제공합니다. 이는 Docker 엔진, Docker Compose, Kubernetes 등 핵심 도구를 포함하고 있어 컨테이너 기반 개발을 위한 올인원 솔루션으로 손색이 없습니다.

Docker Desktop 설치 방법

Docker 공식 웹사이트(docker.com/products/docker-desktop)에서 각 운영체제에 맞는 설치 파일을 다운로드하여 실행합니다. 설치 마법사의 지시에 따라 진행하면 되며, 일반적으로 별다른 설정 없이 기본값으로 설치하는 것이 권장됩니다. 설치 완료 후에는 Docker Desktop 애플리케이션을 실행하여 Docker 엔진이 백그라운드에서 정상적으로 구동되는지 확인해야 합니다. 트레이 아이콘이나 시스템 모니터를 통해 Docker 아이콘이 초록색으로 표시되는지 확인하세요.

설치 후, 터미널(명령 프롬프트 또는 PowerShell)을 열어 다음 명령어를 실행하여 Docker가 제대로 설치되고 버전 정보가 출력되는지 확인할 수 있습니다. 2026년 기준, Docker Engine 25.x 이상, Docker Compose v2.x 이상이 설치되어 있어야 최신 기능을 활용할 수 있습니다.

이 명령어는 각각 Docker 엔진과 Docker Compose의 버전 정보를 출력하여, 두 도구가 시스템에 정상적으로 설치되고 접근 가능한지 확인하는 데 사용됩니다. 버전 정보가 성공적으로 출력된다면 다음 단계로 진행할 준비가 된 것입니다.

docker --version
docker compose version

만약 버전 정보가 출력되지 않거나 오류 메시지가 나타난다면, Docker Desktop이 제대로 실행되었는지, 환경 변수 PATH에 Docker 실행 파일 경로가 올바르게 추가되었는지 확인해야 합니다. 대부분의 경우 Docker Desktop을 재시작하거나 시스템을 재부팅하면 해결됩니다.

Docker Desktop은 단순히 Docker 엔진만을 제공하는 것이 아니라, Kubernetes, Docker Compose, Docker CLI 등 컨테이너 생태계의 핵심 도구들을 하나의 패키지로 제공하여 개발자의 편의성을 극대화합니다. 특히 개발 환경에서 복잡한 마이크로서비스 아키텍처를 시뮬레이션하거나 학습하는 데 매우 유용하므로, 설치 후 Docker Desktop 설정에서 이 기능들을 확인해 보세요.

2.2. Spring Boot 프로젝트 준비

Spring Boot 애플리케이션을 Docker 컨테이너에 올리기 위해서는 먼저 실행 가능한 JAR 파일 또는 WAR 파일을 생성해야 합니다. Spring Boot는 기본적으로 Fat JAR (또는 Executable JAR) 형태로 패키징되어 모든 의존성을 포함하므로, 컨테이너화에 매우 적합합니다. 이 JAR 파일은 JVM만 설치된 환경이라면 어디서든 java -jar 명령어로 바로 실행될 수 있습니다.

Gradle 빌드 설정 (build.gradle)

대부분의 Spring Boot 프로젝트는 Gradle이나 Maven을 통해 빌드됩니다. 여기서는 2026년 현재 가장 널리 사용되는 Gradle을 기준으로 설명합니다. 프로젝트 루트 디렉토리에 있는 build.gradle 파일에 spring-boot-gradle-plugin이 제대로 적용되어 있는지 확인해야 합니다. 이 플러그인이 바로 실행 가능한 JAR 파일(Fat JAR)을 생성하는 핵심 역할을 합니다.

이 Gradle 빌드 스크립트는 Spring Boot 애플리케이션을 실행 가능한 JAR 파일로 패키징하기 위한 필수 설정을 담고 있습니다. org.springframework.boot 플러그인을 사용하여 bootJar 태스크를 활성화하고, JAR 파일명과 메인 클래스를 명시적으로 지정합니다. jar { enabled = false }는 일반 JAR 파일 생성을 비활성화하여 bootJar만 생성되도록 합니다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.5' // 2026년 기준 최신 안정 버전
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.kwonputer'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17' // Java 17 LTS 버전 사용

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // 데이터베이스 연동이 필요하다면 아래 의존성 추가 (예: H2 데이터베이스)
    // runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

jar {
    enabled = false // 일반 jar 생성 비활성화. bootJar만 사용
}

bootJar {
    archiveFileName = "${project.name}.jar" // 생성될 JAR 파일명 지정 (예: kwonputer.jar)
    manifest {
        attributes 'Main-Class': 'com.kwonputer.KwonputerApplication' // 애플리케이션의 메인 클래스 지정
    }
}

위 설정이 완료되었다면, 프로젝트 루트 디렉토리에서 터미널을 열고 다음 명령어를 실행하여 실행 가능한 JAR 파일을 빌드할 수 있습니다.

이 명령어는 Gradle Wrapper를 사용하여 Spring Boot 애플리케이션을 빌드하고 실행 가능한 JAR 파일을 생성합니다. clean 태스크는 이전 빌드 결과물(예: build/libs 디렉토리)을 삭제하여 깨끗한 상태에서 빌드를 시작하게 합니다. bootJar 태스크는 Spring Boot 플러그인에 의해 정의된 태스크로, 모든 의존성을 포함하는 단일 실행 가능한 JAR 파일을 생성합니다.

./gradlew clean bootJar

빌드가 성공하면 build/libs 디렉토리 안에 프로젝트명.jar 형태의 실행 가능한 JAR 파일이 생성됩니다. 예를 들어, 프로젝트 이름이 kwonputer라면 kwonputer.jar 파일이 생성될 것입니다. 이 파일이 바로 Docker 컨테이너에 담을 우리의 Spring Boot 애플리케이션의 핵심입니다.

Spring Boot의 Executable JAR는 모든 의존성을 포함하고 있어, 별도의 웹 서버(예: Tomcat 설치) 없이 java -jar 명령어로 바로 실행 가능합니다. 이 자체 포함(self-contained) 특성은 Docker 컨테이너의 이미지 크기를 줄이고, 빌드 과정을 단순화하며, 런타임 환경의 복잡성을 제거하는 데 크게 기여합니다.

2.3. Dockerfile 작성 심층 분석

Dockerfile은 Docker 이미지를 빌드하기 위한 일련의 명령어들을 담고 있는 스크립트 파일입니다. Spring Boot 애플리케이션을 위한 Dockerfile은 단순히 JAR 파일을 복사하는 것을 넘어, 효율적인 이미지 크기 관리, 빠른 빌드 속도, 그리고 보안 강화를 목표로 해야 합니다. 특히 멀티스테이지 빌드(Multi-stage build)는 이 모든 목표를 달성하는 데 가장 효과적인 방법입니다.

멀티스테이지 빌드를 활용한 Dockerfile

멀티스테이지 빌드는 Docker 이미지 빌드 프로세스를 여러 단계로 나누어, 최종 이미지에는 애플리케이션 실행에 필요한 최소한의 요소만 포함되도록 하는 기법입니다. 이는 빌드 환경(JDK, Gradle/Maven 등)과 런타임 환경(JRE만 포함된 경량 이미지)을 분리함으로써 이미지 크기를 대폭 줄이고 보안을 강화하는 데 매우 효과적입니다.

Spring Boot 애플리케이션을 위한 Docker 멀티스테이지 빌드 흐름도 및 최적화
Spring Boot 애플리케이션을 위한 Docker 멀티스테이지 빌드 흐름도 및 최적화

그림 2. Docker 멀티스테이지 빌드 흐름도

아래 Dockerfile은 멀티스테이지 빌드를 사용하여 Spring Boot 앱을 컨테이너화합니다. 첫 번째 builder 스테이지는 openjdk:17-jdk-slim 이미지를 기반으로 애플리케이션을 빌드하고 JAR 파일을 생성합니다. 두 번째 runner 스테이지에서는 훨씬 더 경량화된 openjdk:17-jre-slim 런타임 이미지를 기반으로, 빌드된 JAR 파일만을 복사하여 최종 이미지를 만듭니다. 이 과정에서 빌드 도구나 소스 코드는 최종 이미지에 포함되지 않아 효율적입니다.

# 1. 빌드 스테이지 (Builder Stage)
# openjdk:17-jdk-slim 이미지를 사용하여 빌드 환경을 구성합니다.
# slim 버전은 불필요한 패키지를 제거하여 이미지 크기를 최적화합니다.
FROM openjdk:17-jdk-slim AS builder
WORKDIR /app
# Gradle Wrapper 관련 파일들을 복사합니다.
COPY gradlew .
COPY gradle gradle
# 프로젝트 빌드 파일들을 복사합니다.
COPY build.gradle .
COPY settings.gradle .
# 애플리케이션 소스 코드를 복사합니다.
COPY src src

# Gradle Wrapper 실행 권한을 부여하고, Spring Boot 애플리케이션을 빌드합니다.
# 이 과정에서 최종 실행 가능한 JAR 파일이 생성됩니다.
RUN chmod +x gradlew
RUN ./gradlew bootJar

# 2. 런타임 스테이지 (Runner Stage)
# openjdk:17-jre-slim 이미지를 사용하여 런타임 환경을 구성합니다.
# jre-slim은 JDK보다 훨씬 가벼워 최종 이미지 크기를 최소화합니다.
FROM openjdk:17-jre-slim
WORKDIR /app

# 빌드 스테이지에서 생성된 JAR 파일을 최종 이미지로 복사합니다.
# --from=builder 옵션으로 이전 스테이지의 결과물만 가져옵니다.
COPY --from=builder /app/build/libs/*.jar app.jar

# Spring Boot 애플리케이션의 기본 포트인 8080을 외부에 노출합니다.
EXPOSE 8080

# 컨테이너 시작 시 실행될 명령어를 정의합니다.
# java -jar 명령어를 통해 Spring Boot 애플리케이션을 실행합니다.
ENTRYPOINT ["java", "-jar", "app.jar"]

위 Dockerfile은 다음과 같은 명확한 장점을 가집니다:

멀티스테이지 빌드의 핵심 장점

✔️ 최종 이미지 크기 대폭 감소: 빌드 도구(Gradle, JDK)와 소스 코드가 최종 런타임 이미지에 포함되지 않아, 이미지 크기가 일반적으로 100MB ~ 200MB 수준으로 최적화됩니다. (예: 빌드 이미지 약 600MB → 런타임 이미지 약 150MB)

✔️ 보안 강화: 불필요한 빌드 도구와 개발용 라이브러리가 제거되어 잠재적인 공격 표면(attack surface)이 크게 줄어듭니다.

✔️ 빠른 배포 및 효율성: 작은 이미지는 Docker Hub나 컨테이너 레지스트리로의 푸시 및 풀 시간을 단축시키고, 배포 서버의 스토리지 사용량을 절약합니다.

.dockerignore 파일 활용

Dockerfile과 함께 사용하는 .dockerignore 파일은 Docker 이미지 빌드 시 포함하지 않을 파일 및 디렉토리를 지정하는 데 사용됩니다. 이 파일을 통해 불필요한 파일들이 이미지에 포함되는 것을 방지하여 이미지 크기를 줄이고, 빌드 속도를 향상시킬 수 있습니다.

예를 들어, 다음과 같은 내용을 가진 .dockerignore 파일을 생성할 수 있습니다:

build/
.gradle/
*.log
*.tmp
*.class

위의 예시는 빌드 결과물 및 임시 파일들이 Docker 이미지에 포함되지 않도록 설정하는 방법을 보여줍니다. .dockerignore 파일을 적절히 활용하면, 이미지 빌드 시 불필요한 파일이 포함되는 것을 방지하고, 최적화된 이미지를 생성할 수 있습니다.

3. 컨테이너화 과정에서 마주치는 흔한 문제와 해결책

컨테이너화 과정에서 발생할 수 있는 일반적인 문제들은 다음과 같습니다. 이러한 문제들을 사전에 인지하고 해결책을 마련하는 것이 중요합니다.

1. **포트 충돌**: 컨테이너가 사용하는 포트가 이미 다른 프로세스에 의해 사용 중일 경우, 컨테이너가 정상적으로 실행되지 않을 수 있습니다. 이 경우, Dockerfile에서 EXPOSE 지시어를 사용하여 다른 포트를 지정하거나, docker run 명령어에서 -p 옵션을 사용하여 호스트의 포트를 변경할 수 있습니다.

2. **의존성 문제**: 애플리케이션이 필요로 하는 라이브러리나 패키지가 컨테이너 내에 설치되어 있지 않으면, 애플리케이션이 제대로 작동하지 않을 수 있습니다. 이를 해결하기 위해 Dockerfile에 필요한 패키지를 설치하는 RUN 명령어를 추가해야 합니다.

3. **파일 시스템 접근 문제**: 컨테이너 내에서 파일 시스템에 접근할 수 없는 경우, 데이터가 손실될 수 있습니다. 이를 방지하기 위해 Docker의 볼륨 기능을 사용하여 호스트와 컨테이너 간의 파일 공유를 설정할 수 있습니다.

이러한 문제들을 사전에 인지하고 적절한 해결책을 마련하면, Spring Boot 애플리케이션을 Docker 컨테이너에 성공적으로 배포할 수 있습니다.

4. Docker Compose를 활용한 개발/배포 환경 구축

Docker Compose는 여러 개의 컨테이너를 정의하고 실행할 수 있는 도구입니다. 이를 통해 복잡한 애플리케이션을 손쉽게 구성하고 관리할 수 있습니다. Docker Compose를 사용하면, 여러 개의 서비스(예: 데이터베이스, 캐시 서버 등)를 동시에 실행할 수 있어 개발 및 배포 환경을 간소화할 수 있습니다.

Docker Compose 파일(docker-compose.yml)은 YAML 형식으로 작성되며, 각 서비스의 설정을 정의합니다. 예를 들어, Spring Boot 애플리케이션과 MySQL 데이터베이스를 함께 실행하기 위한 Docker Compose 파일은 다음과 같이 작성할 수 있습니다:

version: '3.8'
services:
  spring-boot-app:
    image: kwonputer:latest
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - mysql
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: testdb
    ports:
      - "3306:3306"

위의 예시에서, Spring Boot 애플리케이션은 MySQL 데이터베이스에 의존하고 있으며, 두 서비스는 각각의 포트를 통해 외부와 통신합니다. Docker Compose를 사용하면, docker-compose up 명령어를 통해 모든 서비스를 동시에 시작할 수 있습니다.

5. 자주 묻는 질문 (FAQ)

Q1: Docker와 Docker Compose의 차이는 무엇인가요?

A1: Docker는 컨테이너를 생성하고 관리하는 도구이며, Docker Compose는 여러 개의 컨테이너를 정의하고 동시에 실행할 수 있도록 도와주는 도구입니다.

Q2: Spring Boot 애플리케이션을 Docker로 배포할 때 주의해야 할 점은 무엇인가요?

A2: 애플리케이션의 포트, 데이터베이스 연결 정보, 환경 변수 등을 Dockerfile 및 Docker Compose 파일에 정확히 설정해야 합니다.

Q3: Docker 컨테이너의 로그를 어떻게 확인하나요?

A3: docker logs [컨테이너 ID] 명령어를 사용하여 특정 컨테이너의 로그를 확인할 수 있습니다.