java -jar -Dspring.profiles.active=prod myapp.jar
| 구분 | 설명 | 문제점 |
|---|---|---|
| 환경 의존성 문제 | 서버마다 JDK, 라이브러리, DB, OS 버전 등이 달라 동일 애플리케이션이 환경에 따라 정상 동작하지 않는 경우가 많았다. 특히 OS 버전 업그레이드 시 기존 설정과 충돌이 발생하여 재배포 과정에서 장애가 빈번했다. | 환경 재현성이 낮아 개발-테스트-운영 간 일관성이 깨지고 배포 안정성이 저하됨 |
| 설치 과정의 복잡성 | JDK 설치, 의존성 구성, 설정 파일 관리, 실행 스크립트 작성 등을 모두 수동으로 진행해야 했다. | 사람 실수에 의한 오류가 자주 발생, 서버가 늘어날수록 설치 및 관리 부담 증가, 자동화 도구 부족으로 유지보수 어려움 |
| 서버 자원 활용 비효율 | 하나의 서버에 여러 애플리케이션을 배포하면 충돌이 발생하거나 특정 애플리케이션만 과도하게 자원을 점유할 수 있었다. 또한 서버 단위 확장이 필요해 비용과 관리 부담이 커졌다. | 자원 격리와 최적화 부족으로 인프라 활용 효율 저하 |
Docker는 애플리케이션과 그 실행 환경(라이브러리, 설정 등)을 컨테이너(container)라는 독립된 단위로 패키징하여 어디서든 동일하게 실행할 수 있도록 하는 플랫폼이다.
리눅스 커널의 네임스페이스와 cgroups 기능을 활용하여 가볍고 격리된 실행 환경을 제공한다.
이를 통해 개발•테스트•운영 환경 간의 일관성, 이식성, 확장성을 보장한다.
| 구분 | 가상화 (Virtual Machine) | 컨테이너 (Docker) |
|---|---|---|
| 구조 | 하이퍼바이저 위에 각 VM이 Guest OS + 라이브러리 + 앱 포함된 구조 | Docker Engine 위에 라이브러리 + 앱만 포함 |
| 운영체제 | VM마다 독립적인 OS 필요 → 무겁고 자원 소모 큼, OS 격리 가능 | Host OS 공유, 컨테이너마다 별도 OS 불필요 |
| 성능 | OS 중복 실행으로 부팅/실행 느리고 메모리 사용량 많음 | 가볍고 빠른 실행, 메모리 효율적 |
| 배포/이식성 | VM 이미지는 용량이 크고 이식에 시간 소요 | 이미지 기반으로 빠른 배포, 이식성 뛰어남 |
| 격리성 | OS 단위 격리 → 높은 보안성, 완벽한 독립 환경 제공 | 프로세스 단위 격리 → 빠르지만 보안 측면 상대적으로 약함 |
| 활용 사례 | 레거시 시스템 운영, 완전한 OS 환경이 필요한 경우 | 마이크로서비스, DevOps, CI/CD, 클라우드 네이티브 환경 |
Docker는 클라이언트(Client) – 호스트(Docker Host) – 레지스트리(Registry) 3계층 구조로 동작하며, 이미지(Image)와 컨테이너(Container)를 중심으로 운영된다.
Docker는 2013년 Solomon Hykes가 dotCloud라는 PaaS 회사에서 내부 프로젝트로 시작되고 발전 되었다.
이후 컨테이너(Container) 기술을 대중화시키고 표준화한 플랫폼으로 성장 하였다.
애플리케이션과 실행 환경을 이미지 단위로 패키징하여 어디서나 동일하게 동작하게 해주며, DevOps와 클라우드 네이티브 아키텍처의 핵심 기반으로 자리 잡았다. 현재 Kubernetes와 같은 오케스트레이션 도구에서도 사실상 컨테이너 실행 표준(Runtime 표준)으로 Docker 기술이 반영되었다.
| 특징 | 설명 |
|---|---|
| 경량성 (Lightweight) | 별도의 Guest OS 없이 애플리케이션과 라이브러리만 포함하여 가볍게 실행됨 |
| 이미지 기반 (Image-based) | 컨테이너 실행 단위를 이미지로 관리하여 버전 관리, 배포, 공유가 용이함 |
| 격리성 (Isolation) | 각 컨테이너는 독립된 프로세스로 실행되어 충돌 없이 동작 |
| 신속한 실행 (Fast Startup) | VM보다 훨씬 빠르게 컨테이너를 생성하고 실행 가능 |
| 표준화 (Standardization) | 컨테이너 실행 및 관리에 있어 사실상 업계 표준으로 자리 잡음 |
| 장점 | 설명 |
|---|---|
| 이식성 (Portability) | 동일한 이미지를 기반으로 개발, 테스트, 운영 환경 어디서든 동일하게 실행 가능 |
| 효율성 (Efficiency) | VM보다 자원 소모가 적어 서버 활용도를 높임 |
| 확장성 (Scalability) | 마이크로서비스 단위로 손쉽게 확장 및 축소 가능 |
| DevOps 최적화 | CI/CD 파이프라인과 자연스럽게 통합되어 자동화 및 빠른 배포 지원 |
| 생태계 (Ecosystem) | Docker Hub 등 다양한 공개 이미지 및 커뮤니티 지원으로 생산성 향상 |
컨테이너(Container) : 애플리케이션과 실행 환경을 격리하여 실행되는 가상화된 인스턴스이다.
이미지로부터 생성되며 독립된 프로세스(CPU, 메모리 사용)로 동작한다. (살아 있는 instance 개념)
이미지(Image) : 컨테이너 실행 하기 위한 불변의 템플릿이다. 코드, 라이브러리, 설정 등 실행에 필요한 요소를 포함하고 있으며 언제든 컨테이너로 실행 할 수 있다. (굳어 있는 class, 설계도 개념)
| 개념 | 설명 |
|---|---|
| 컨테이너 (Container) | 애플리케이션과 의존성을 포함한 독립적 실행 단위로, 격리된 환경에서 실행되지만 호스트 OS 커널을 공유함 |
| 이미지 (Image) | 컨테이너를 생성하기 위한 읽기 전용 템플릿으로, 애플리케이션 코드, 런타임, 라이브러리 등을 포함함 |
| Dockerfile | 이미지를 빌드하기 위한 지시사항을 담은 텍스트 파일로, 베이스 이미지 선택부터 애플리케이션 실행까지 정의함 |
| 레지스트리 (Registry) | Docker 이미지를 저장하고 배포하는 저장소로, 공용(Docker Hub)과 프라이빗 레지스트리가 존재함 |
| 볼륨 (Volume) | 컨테이너 외부에 데이터를 저장하여 컨테이너가 삭제되어도 데이터가 유지되도록 하는 영속적 저장소 |
| 네트워크 (Network) | 컨테이너 간 통신 및 외부 연결을 관리하는 가상 네트워크로, 브리지·호스트·오버레이 등 다양한 네트워크 드라이버 제공 |
| 엔진 (Docker Engine) | 컨테이너의 생성, 실행, 관리 등을 담당하는 핵심 런타임으로, 클라이언트-서버 구조로 구성되며 CLI/REST API를 통해 컨테이너, 이미지, 네트워크, 볼륨 등을 관리함 |
컨테이너화를 통한 배포는 애플리케이션과 실행 환경을 이미지로 패키징하여 어디서든 동일하게 실행할 수 있도록 한다. 이를 통해 배포 과정이 자동화되고 일관성이 보장되어 운영 효율성이 크게 향상된다.
Docker Hub는 Docker에서 제공하는 공식 이미지 저장소(Registry 서비스)이다.
개발자는 Docker Hub를 통해 공개된 다양한 베이스 이미지(Ubuntu, Postgre 등)를 다운로드(pull)하여 활용할 수 있고, 자신이 만든 이미지를 업로드(push)하여 다른 사람들과 공유할 수도 있다.
공개 저장소(Public Repository)와 비공개 저장소(Private Repository)를 모두 지원하며, CI/CD 파이프라인과 연동되어 자동 빌드, 버전 관리, 협업이 가능하다.
공식 이미지(Official) : Docker에서 직접 관리하거나 신뢰할 수 있는 벤더가 제공하는 검증된 표준 이미지
사용자 이미지(User) : 일반 사용자가 직접 빌드하고 업로드한 커스텀 이미지
docker pull nginx # 공식 이미지
docker pull bitnami/postgresql # 사용자 이미지
로컬 PC에서 손쉽게 Docker 환경을 실행하고 관리할 수 있도록 제공되는 GUI 기반 프로그램이다.
컨테이너, 이미지, 네트워크, 볼륨 등을 시각적으로 관리할 수 있으며 CLI와 통합되어 개발 편의성을 높인다.
Windows, macOS에서 가상화 환경을 활용해 Linux 기반 컨테이너 실행을 지원한다.
→ 기능은 좋으나 아쉽게도 로컬로만 실행됨으로 실습 때 외에는 활용 할 일이 별로 없다.
컨테이너 관리 : 실행, 중지, 삭제 및 상태 확인
이미지 관리 : 빌드, 다운로드, 업로드 및 버전 관리
네트워크·볼륨 : 컨테이너 통신과 데이터 지속성 관리
개발 환경 통합 : 로컬 Kubernetes, 가상화 기반 컨테이너 실행
Docker의 공식 문서(https://docs.docker.com/)는 다음과 같은 주요 섹션으로 구성되어 있다.
Docker 명령어는 다음과 같은 구조로 되어 있다.
docker [OPTIONS] COMMAND [ARG...]
명령어에 대한 도움말을 보려면 아래와 같이 명령어를 통해 볼 수 있다.
docker --help # 전체 명령어 목록
docker run --help # 특정 명령어(run)에 대한 도움말을 볼 수 있다.
개발 과정에서 자주 참조해야 할 문서 페이지는 다음과 같다.
| 명령어 | 설명 |
|---|---|
docker images | 로컬에 저장된 이미지 목록 확인 |
docker image ls | docker images와 동일 (공식 최신 문법) |
docker search <이미지명> | Docker Hub에서 이미지 검색 |
docker pull <이미지명>:<태그> | 레지스트리에서 이미지 다운로드 |
docker inspect <이미지> | 이미지 메타데이터(레이어, 환경변수 등) 확인 |
docker history <이미지> | 이미지 레이어별 생성 이력 확인 |
docker rmi <이미지> | 특정 이미지 삭제 |
docker image prune | 사용하지 않는 모든 이미지/중간 레이어 삭제 |
docker tag <이미지> <새이름>:<태그> | 이미지에 새 태그 부여(이름/레포 변경) |
docker build -t <이름>:<태그> <경로> | Dockerfile로 새 이미지 생성 |
docker save -o <파일>.tar <이미지> | 이미지를 tar 파일로 저장(백업/이동용) |
docker load -i <파일>.tar | tar 파일에서 이미지 불러오기 |
docker push <레포>/<이미지>:<태그> | 이미지 레지스트리에 푸시 |
원격 저장소(Docker Hub, ECR 등)에 있는 이미지를 로컬 환경으로 다운로드하는 명령어이다.
(docker run으로도 같은 기능을 가지고 있어 사실 사용할 일이 많이 없다.)
# 기본 구문
docker pull [저장소명]/[이미지명]:[태그]
# 최신 버전 다운로드
docker pull postgres
docker pull postgres:latest
# 특정 버전 다운로드 (17.6)
docker pull postgres:17.6
# 특정 다이제스트로 다운로드
docker pull postgres@sha256:fb11a641ba92390de4f781dc6f7b315f5eacb0c2f5569f67959f76f1f80b49b1
현재 로컬 환경에 다운로드 되어 있는 Docker 이미지 목록을 조회하는 명령어이다.
# 기본 구문
docker images [OPTIONS] [REPOSITORY[:TAG]]
# 모든 이미지 보기
docker images
# 특정 이미지만 보기
docker images postgres
# 사용하지 않는 이미지만 보기 (dangling)
docker images --f "dangling=true"
# 이미지 ID만 표시
docker images -q
<주요 옵션>
-a, --all : 모든 이미지 출력 (중간 레이어까지 포함)
-q, --quiet : 이미지 ID만 출력
-f, --filter : 조건에 따라 필터링
--format : 출력 형식 지정 (Go 템플릿 사용)
불필요한 이미지를 삭제하여 디스크 공간을 확보할 수 있는 명령어
# 기본 구문
docker rmi [OPTIONS] IMAGE [IMAGE...]
# 이미지 ID로 삭제
docker rmi a4a3c25e5d8c
# 이미지 이름:태그로 삭제
docker rmi postgres:17.6
# 사용하지 않는 이미지 모두 삭제
docker image prune
# 강제 삭제 (컨테이너가 이 이미지를 사용 중일 때)
docker rmi -f postgres:17.6
| 명령어 | 설명 | 예시 |
|---|---|---|
docker ps | 실행 중인 컨테이너 목록 확인 | docker ps |
docker ps -a | 중지 포함 전체 컨테이너 목록 확인 | docker ps -a |
docker run [옵션] <이미지> | 새 컨테이너 생성 및 실행 (이미지 없으면 자동 pull) | docker run -d --name my-postgres -e POSTGRES_PASSWORD=1234 -p 5432:5432 postgres:17 |
docker start <컨테이너> | 중지된 컨테이너 시작 | docker start my-postgres |
docker stop <컨테이너> | 실행 중 컨테이너 중지 | docker stop my-postgres |
docker restart <컨테이너> | 컨테이너 재시작 | docker restart my-postgres |
docker exec -it <컨테이너> <명령> | 실행 중 컨테이너 내부 명령 실행 | docker exec -it my-postgres bash |
docker logs <컨테이너> | 컨테이너 로그 출력 | docker logs my-postgres |
docker rm <컨테이너> | (중지된) 컨테이너 삭제 | docker rm my-postgres |
docker rm -f <컨테이너> | 강제 삭제(실행 중 포함) | docker rm -f my-postgres |
docker container prune | 사용하지 않는 모든 컨테이너 삭제 | docker container prune |
docker cp <로컬> <컨테이너:경로> | 로컬↔컨테이너 파일 복사 | docker cp ROOT.war my-tomcat:/usr/local/tomcat/webapps/ROOT.war |
컨테이너 이미지를 기반으로 새 컨테이너를 생성하고 지정한 프로세스를 실행하는 명령이다.
이미지가 없는 경우 docker pull을 대신 수행함으로 해당 명령만 있으면 이미지 pull + run을 동시에 수행한다.
# 기본 구문
docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]
# 기본 실행
docker run --name my-tomcat -d tomcat
# 포트 매핑 추가
docker run --name my-tomcat -p 80:8080 -d tomcat
# 포트 매핑 + 파일 복사
docker run --name my-tomcat-hello -d -p 8080:8080
-v ./hello.jsp:/usr/local/tomcat/webapps/ROOT/hello.jsp
tomcat:9.0
→ http://localhost:8080/hello.jsp로 접속해야 보임
# 환경 변수 사용 및 볼륨 마운트 추가
docker run --name my-postgres
-e POSTGRES_USER=user1
-e POSTGRES_PASSWORD=mypassword
-e POSTGRES_DB=appdb
-p 5432:5432
-v postgres-data:/var/lib/postgresql/data
-d postgres:17.6
<옵션>
--name : 컨테이너 이름 지정
-d : 백그라운드 모드(detached)
-e : 환경 변수 설정
-p : 호스트와 컨테이너 간 포트 매핑
-v : 볼륨 마운트
실행 컨테이너 목록을 출력하는 명령어, 컨테이너 ID, 이미지, 상태, 포트 매핑과 같은 주요 정보를 확인 가능
기본적으로 중지된 컨테이너는 표시되지 않지만, 옵션을 활용하면 확인이 가능하다.
# 기본 구문
docker ps [OPTIONS]
# 실행 중인 컨테이너만 표시
docker ps
# 모든 컨테이너 표시 (중지된 컨테이너 포함)
docker ps -a
# 최근에 생성된 컨테이너만 표시
docker ps -l
# 특정 이름 패턴으로 필터링
docker ps --filter "name=postgres"
# 컨테이너 ID만 표시
docker ps -q
<옵션>
-a : 중지된 컨테이너까지 모두 출력
-q : 컨테이너 ID만 출력
-n <숫자> : 최근 생성된 N개의 컨테이너 출력
--filter : 조건에 맞는 컨테이너만 출력 (예: 이름, 상태)
--format : 출력 형식을 지정하여 원하는 정보만 표시
start, docker stop, docker restart는 컨테이너의 실행 상태를 제어하는 기본 명령어이다.
# 기본 구문
docker start [OPTIONS] CONTAINER [CONTAINER...]
docker stop [OPTIONS] CONTAINER [CONTAINER...]
docker restart [OPTIONS] CONTAINER [CONTAINER...]
# 컨테이너 시작
docker start my-postgres
docker start a1b2c3d4e5f6 # id로 제어 가능
# 컨테이너 중지
docker stop my-postgres
docker stop a1b2c3d4e5f6 # id로 제어 가능
# 컨테이너 재시작
docker restart my-postgres
docker restart a1b2c3d4e5f6 # id로 제어 가능
# 타임아웃 설정 (10초 후 강제 종료)
docker stop -t 10 my-postgres
실행 중인 컨테이너 안에서 추가 명령어를 실행할 때 사용하는 명령어이다.
# 기본 구문
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
# 대화형 쉘로 접속
docker exec -it my-postgres bash
# 직접 psql 실행
docker exec -it my-postgres psql -U postgres
# 단일 명령 실행
docker exec my-postgres pg_isready
<옵션>
i: 표준 입력을 유지(interactive)
t: TTY 할당
e: 환경 변수 설정
실행 중이거나 종료된 컨테이너의 표준 출력(stdout)과 표준 에러(stderr) 로그를 확인하는 명령어다.
# 기본 구문
docker logs [OPTIONS] CONTAINER
# 모든 로그 출력
docker logs my-tomcat
# 실시간 로그 추적
docker logs -f my-tomcat
# 최근 10줄만 표시
docker logs --tail 10 my-tomcat
# 타임스탬프 표시
docker logs -t my-tomcat
# 최근 10분간 로그만 출력
docker logs --since 10m my-postgres
<주요 옵션>
-f, --follow : 실시간 로그 스트리밍 (tail -f처럼 동작)
--tail <숫자> : 마지막 N줄만 출력 (--tail 100)
-t, --timestamps : 로그에 타임스탬프 표시
--since <시간> : 특정 시점 이후의 로그만 표시
(--since 10m, --since 2025-09-20T10:00:00)
--until <시간> : 특정 시점까지의 로그만 표시
컨테이너를 삭제하는 명령어이다. 컨테이너를 삭제하면 해당 컨테이너의 파일시스템, 설정, 네트워크 정보가 사라진다.
단, 볼륨(-v 옵션) 을 지정하지 않는 이상 데이터 볼륨은 삭제되지 않는다.
# Postgres 컨테이너 삭제 (중지 상태일 때)
docker rm my-postgres
# Tomcat 컨테이너 강제 삭제 (실행 중 포함)
docker rm -f my-tomcat
# 컨테이너와 연결된 볼륨까지 함께 삭제
docker rm -v my-postgres
# 여러 컨테이너 한 번에 삭제
docker rm my-postgres my-tomcat
<주요 옵션>
-f, --force : 실행 중인 컨테이너도 강제로 삭제 (내부적으로
docker stop 후 rm)
-v, --volumes : 컨테이너와 연결된 볼륨도 함께 삭제
-l, --link : 컨테이너 간 링크만 삭제 (컨테이너 자체는 유지)
컨테이너와 호스트 간 파일을 주고받는 명령어이다.
컨테이너 내부 파일시스템과 로컬 파일시스템 간에 자유롭게 복사가 가능하다.
단, 컨테이너가 실행 중이든 중지 중이든 상관없이 동작한다.
# 호스트 → 컨테이너 복사
# hello.jsp를 my-tomcat 컨테이너의 ROOT 디렉토리로 복사
docker cp ./hello.jsp my-tomcat:/usr/local/tomcat/webapps/ROOT/hello.jsp
# 컨테이너 → 호스트 복사
# my-postgres 컨테이너의 데이터 디렉토리를 로컬로 백업
docker cp my-postgres:/var/lib/postgresql/data ./data-backup
# 디렉토리 단위 복사
# 호스트 src 디렉토리를 my-tomcat 컨테이너의 webapps로 복사
docker cp ./src my-tomcat:/usr/local/tomcat/webapps/
# my-tomcat 컨테이너의 logs 디렉토리를 로컬 logs 폴더로 복사
docker cp my-tomcat:/usr/local/tomcat/logs ./logs
Docker 네트워크는 컨테이너 간 통신을 가능하게 하는 가상 네트워크이다.
컨테이너들은 동일 네트워크 안에서 서로 이름(DNS)으로 접근할 수 있다. 또한 브리지, 호스트, 오버레이와 같은 네트워크 드라이버를 통해 통신 방식을 선택하고 제어할 수 있다.
| 네트워크 종류 | 특징 | 명령어/예시 |
|---|---|---|
| bridge (기본) | 단일 호스트 내 컨테이너용 기본 네트워크. 사용자 정의 브리지에선 컨테이너 이름(DNS) 으로 통신 가능. 외부 접근은 포트 바인딩 필요. | docker network create -d bridge my-bridgedocker run -d --name app --network my-bridge -p 8080:8080 myimg |
| host | 컨테이너가 호스트 네트워크를 그대로 사용. 포트 바인딩 불필요(호스트 포트=컨테이너 포트). 성능은 좋지만 격리/보안 취약 → 일반적으로 비권장. | docker run -d --network host myimg |
| overlay | 여러 호스트 간 컨테이너 통신. 스웜/오케스트레이션 환경에서 서비스 간 보안 네트워크 제공. (Docker Swarm/Kubernetes에서 사용) | docker swarm initdocker network create --driver overlay my-overlaydocker service create --name web --network my-overlay nginx |
| none | 네트워크 비활성화. 외부·내부 통신 불가(완전 격리용). | docker run -d --network none myimg |
| 명령어 | 설명 | 예시 |
|---|---|---|
docker network ls | 현재 생성된 네트워크 목록 조회 | docker network ls |
docker network inspect <NAME> | 특정 네트워크 상세 정보 확인(드라이버, 서브넷, 연결 컨테이너 등) | docker network inspect bridge |
docker network create <NAME> | 사용자 정의 네트워크 생성(드라이버 지정 가능: bridge, overlay 등) | docker network create my-net |
docker network rm <NAME> | 특정 네트워크 삭제 | docker network rm my-net |
docker network prune | 사용하지 않는 네트워크 일괄 삭제(컨테이너에 미연결된 네트워크만) | docker network prune |
docker network connect <NET> <CONTAINER> | 컨테이너를 기존 네트워크에 연결 | docker network connect my-net my-container |
docker network disconnect <NET> <CONTAINER> | 컨테이너를 특정 네트워크에서 분리 | docker network disconnect my-net my-container |
기본 네트워크로, 컨테이너를 생성할 때 별도로 네트워크를 지정하지 않으면 자동으로 bridge 네트워크로 연결된다. 동일한 Docker 호스트 내에서 실행되는 컨테이너 간의 통신에 적합하다.
# 사용자 정의 bridge 네트워크 생성
docker network create --driver bridge my-bridge-network
# 컨테이너를 사용자 정의 bridge 네트워크에 연결하여 실행
docker run --name postgres-db --network my-bridge-network -e
POSTGRES_PASSWORD=mysecretpassword -d postgres:15.5
# 같은 네트워크의 다른 컨테이너에서는'postgres-db'라는 호스트명으로 접근 가능
docker run --name app --network my-bridge-network -d myapp
컨테이너가 호스트의 네트워크 스택을 직접 사용한다. 컨테이너와 호스트 간 네트워크 격리가 없으므로 성능이 가장 좋다.
# host 네트워크를 사용하여 PostgreSQL 실행
docker run --name tomcat-host --network host -d tomcat:11
# 위 컨테이너는 호스트의 5432 포트를 직접 사용
# 포트 매핑(-p) 옵션 불필요
네트워크 기능을 완전히 비활성화한다.
컨테이너가 외부와 통신할 수 없으며, 로컬 루프백 인터페이스만 사용 가능하다.
# 네트워크 없이 컨테이너 실행
docker run --name isolated-container --network none -d alpine sleep infinity
여러 Docker 호스트 간 통신을 위한 네트워크이다.
Docker Swarm이나 Kubernetes와 같은 클러스터 환경에서 사용된다.
# overlay 네트워크 생성 (Docker Swarm 모드에서)
docker network create --driver overlay my-overlay-network
Docker Volume은 컨테이너와 독립적으로 데이터를 저장하는 영구적 저장소이다. 컨테이너가 삭제되거나 재시작 되어도 볼륨에 저장된 데이터는 유지되며, 여러 컨테이너가 같은 볼륨을 공유하여 데이터 일관성과 지속성을 확보할 수 있다.
Docker 볼륨 명령어는 컨테이너와 분리된 데이터 저장 공간을 생성, 조회, 삭제, 관리하기 위해 사용된다.
# 볼륨 목록 확인
docker volume ls
# 볼륨 생성
docker volume create postgres-data
# 볼륨 정보 확인
docker volume inspect postgres-data
# 사용하지 않는 볼륨 삭제
docker volume prune
# 볼륨 삭제
docker volume rm postgres-data
Dockerfile은 도커 이미지를 자동으로 빌드하기 위한 명령어 스크립트이다.
베이스 이미지, 필요한 패키지, 환경 변수, 실행 명령어 등을 순차적으로 기술하여 자동화된 빌드를 지원한다.
docker build 명령으로 Dockerfile을 기반으로 한 커스텀 이미지를 만들 수 있다.
# Amazon Corretto 17 이미지를 기반으로 사용
FROM amazoncorretto:17
# 작업 디렉터리 설정
WORKDIR /app
# 빌드된 JAR 파일을 컨테이너로 복사
COPY build/libs/myapp.jar app.jar
# 애플리케이션 포트 노출
EXPOSE 8080
# 컨테이너 실행 시 JAR 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
| 지시어 | 설명 | 예시 |
|---|---|---|
FROM | 기반(Base) 이미지 지정 | FROM amazoncorretto:17 |
WORKDIR | 작업 디렉터리 설정 | WORKDIR /app |
COPY | 호스트 파일/디렉터리를 컨테이너로 복사 | COPY build/libs/myapp.jar app.jar |
ADD | COPY와 유사하지만 압축 해제·URL 다운로드 지원 | ADD https://example.com/config.tar.gz /app/ |
RUN | 빌드 과정에서 실행할 명령어 수행 | RUN yum update -y && yum install -y curl |
ENV | 환경 변수 설정 | ENV SPRING_PROFILES_ACTIVE=prod |
EXPOSE | 컨테이너에서 열어줄 포트 지정 (실제 포트 바인딩은 -p 옵션 필요) | EXPOSE 8080 |
CMD | 컨테이너 시작 시 실행할 기본 명령 (덮어쓰기 가능) | CMD ["java", "-jar", "app.jar"] |
ENTRYPOINT | 컨테이너 실행 진입점 지정 (필수 실행, CMD와 조합 가능) | ENTRYPOINT ["java","-jar","app.jar"] |
# Amazon Corretto 17 (JDK) 기반 이미지 사용
FROM amazoncorretto:17
# 컨테이너 안 작업 디렉토리 설정
WORKDIR /app
# 호스트의 JAR 파일을 컨테이너 내부로 복사
COPY blog-1.0.0_h2.jar app.jar
# 8080 포트 노출 (Spring Boot 기본 포트)
EXPOSE 8080
# JAR 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
빌드 명령어
docker build -t blog-app .
실행 확인
docker run --name my-blog -d -p 8080:8080 blog-app
멀티 스테이지(Multi-Stage) Dockerfile은 빌드 과정과 실행 환경을 분리하여 최적화하는 기법이다.
빌드 스테이지에서는 빌드 도구와 의존성을 포함해 애플리케이션을 컴파일하고 산출물을 생성한다.
최종 런타임 스테이지에는 최소한의 OS와 실행에 필요한 파일만 포함해 이미지 크기를 줄이고 보안을 강화한다.
확장 빌드 도구: docker build의 확장 버전으로, 멀티 아키텍처(arm64, amd64 등) 이미지 빌드와 고급 캐시 기능 지원
장점: M1/M2 맥 같은 ARM 환경에서도--platform 옵션을 통해 x86_64용 이미지를 만들어 배포할 수 있다.
# 단일 아키텍처 빌드
docker buildx build -t my-app:1.0 .
# 멀티 아키텍처 빌드 및 푸시
docker buildx build --platform linux/amd64,linux/arm64 -t my-dockerhub-id/my-app:1.0 --push .
형식: repository:tag
repository = 이미지 이름 (ex: nginx, my-dockerhub-id/my-app)
tag = 버전 또는 구분자 (ex: latest, 1.0, prod), 태그가 없으면 자동으로 latest가 붙는다.
# 빌드하면서 태그 붙이기
docker build -t my-app:1.0 .
# 태그 추가
docker tag my-app:1.0 my-dockerhub-id/my-app:1.0
# 1. 로그인
docker login # DockerHub 계정 / 비밀번호 입력
# 2. 태그 지정
docker tag my-app:1.0 my-dockerhub-id/my-app:1.0
# 3. 푸시
docker push my-dockerhub-id/my-app:1.0
# 4. 확인
# - DockerHub 웹 대시보드에 가서 리포지토리에 이미지가 올라왔는지 확인
# - 다른 환경에서 pull 가능
docker pull my-dockerhub-id/my-app:1.0
Docker Compose는 여러 개의 컨테이너 서비스를 하나의 설정 파일로 정의하고 관리하는 도구이다.
하나의 앱을 구성하는 DB, 웹서버, 백엔드 등을 동시에 실행하고 네트워크·볼륨을 자동으로 설정해준다.
주로 docker-compose.yml 파일로 생성하며 docker compose up 같은 명령으로 손쉽게 빌드·실행·중지까지 전체 환경을 일괄 관리할 수 있다.
docker-compose.yml
services:
db:
build: ./db
image: my-postgres:17.6
environment:
POSTGRES_DB: my_blog
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- app-net
ports:
- "5432:5432"
app:
build: ./app
image: blog-app:latest
environment:
SPRING_PROFILES_ACTIVE: prod
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/my_blog
depends_on:
- db
networks:
- app-net
ports:
- "8080:8080"
networks:
app-net:
name: app-net
volumes:
pgdata:
name: pgdata
Docker Compose에서.env 파일은 컨테이너 실행 시 참조할 환경 변수 값을 정의하는 설정 파일이다.
docker-compose.yml 안의 ${VAR_NAME} 구문과 매핑되어 서비스별 환경 변수로 주입된다.
Spring Boot는 이 환경 변수를 그대로 인식해 application.yml의 설정 값으로 활용할 수 있다.
(docker compose 명령을 통해 같은 디렉터리에 .env 파일이 있으면 자동으로 읽음으로 별도 설정 불필요)
→ 주로 민감정보를 외부와 분리하는데 사용되며, .gitignore와 .dockerignore 동시에 활용 필요
.env
SPRING_PROFILES_ACTIVE=prod
SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/my_blog
SPRING_DATASOURCE_USERNAME=user1
SPRING_DATASOURCE_PASSWORD=1234
docker-compose.yml
services:
app:
image: my-spring-project:1.0.0
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE}
SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL}
SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME}
SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
| 계층 | 키워드 | 설명 | 예시 |
|---|---|---|---|
| 루트 | services | 실행할 컨테이너 서비스 정의의 최상위 블록 | services: { app: ..., db: ... } |
networks | 서비스 간 통신에 사용하는 네트워크 정의 | networks: { app-net: {} } | |
volumes | 데이터 영속화를 위한 볼륨 정의 | volumes: { pgdata_dev: {} } | |
| services 하위 | <service-name> | 각 서비스 이름 정의 | app:, db: |
build | Dockerfile 빌드 정보 | build: ./app | |
image | 사용할 이미지 이름/태그 | image: blog-app:latest | |
container_name | 컨테이너 이름 지정 | container_name: my-blog | |
ports | 호스트:컨테이너 포트 매핑 | ports: ["8080:8080"] | |
environment | 환경 변수 설정 | environment: { SPRING_PROFILES_ACTIVE: prod } | |
volumes | 호스트 경로 또는 볼륨 마운트 | volumes: ["pgdata_dev:/var/lib/postgresql/data"] | |
networks | 서비스가 연결될 네트워크 지정 | networks: [app-net] | |
depends_on | 서비스 실행 순서/의존성 지정 | depends_on: [db] | |
restart | 재시작 정책 | restart: unless-stopped | |
| build 하위 | healthcheck | 서비스 상태 체크 방법 정의 | healthcheck: { test: "CMD-SHELL ..." } |
context | 빌드 컨텍스트(디렉토리) | context: ./app | |
dockerfile | 사용할 Dockerfile 이름/경로 | dockerfile: Dockerfile | |
| networks 하위 | <network-name> | 네트워크 이름 정의 | app-net: |
external | 이미 존재하는 네트워크 재사용 여부 | external: true | |
| volumes 하위 | <volume-name> | 볼륨 이름 정의 | pgdata: |
external | 이미 존재하는 볼륨 재사용 여부 | external: true |
# 전체 서비스 빌드 후 실행 (백그라운드 모드)
docker compose up -d
# 컨테이너, 네트워크, 볼륨까지 모두 정리
docker compose down -v --rmi all
# 변경된 이미지 다시 빌드 후 실행
docker compose up -d --build
# 서비스 상태 확인
docker compose ps
# 서비스 로그 확인 (app 서비스, 실시간)
docker compose logs -f app
# 특정 컨테이너 내부로 접속 (db 서비스에 bash)
docker compose exec db bash
# 특정 서비스에 일회성 명령 실행 (psql 접속 예시)
docker compose run --rm db psql -U user1 my_blog
# 설정 파일 확인 (merge된 실제 적용 설정 보기)
docker compose config
# 서비스가 사용하는 이미지 목록 확인
docker compose images
# 실행 중인 컨테이너의 프로세스 확인
docker compose top
Spring Boot 프로젝트 내에서 컨테이너 실행 환경에 맞는 설정 분리 통해 안정성을 확보하는 과정이다.
컨테이너화를 위해 빌드 스크립트(build.gradle), Dockerfile, docker-compose.yml, .env 를 구성하여 실행과 배포를 표준화 하며 로그 관리, 환경변수 주입, 헬스체크 같은 운영 관리 요소까지 포함해 프로덕션 환경에 적합하게 셋팅 할 수 있다.
Dockerfile 작성시에는 빌드 스테이지와 런타임 스테이지를 분리해 이미지 크기와 보안을 최적화해야 한다.
또한 amazoncorretto:17-alpine3.21처럼 경량 베이스 이미지를 활용해 성능과 배포 효율성을 높인다.
# 빌드 스테이지
FROM amazoncorretto:17 AS builder
WORKDIR /app
COPY gradle ./gradle
COPY gradlew ./gradlew
COPY build.gradle settings.gradle ./
RUN ./gradlew dependencies
COPY src ./src
RUN ./gradlew build-x test
# 런타임 스테이지
FROM amazoncorretto:17-alpine3.21
WORKDIR /app
ENV PROJECT_NAME=discodeit \
PROJECT_VERSION=1.2-M8 \
JVM_OPTS=""
COPY --from=builder /app/build/libs/${PROJECT_NAME}-${PROJECT_VERSION}.jar ./
EXPOSE 80
ENTRYPOINT ["sh", "-c", "java ${JVM_OPTS} -jar ${PROJECT_NAME}-${PROJECT_VERSION}.jar"]
.dockerignore는 빌드에 불필요한 파일(.git, 로그, 빌드 등)을 제외해 이미지 크기와 빌드 속도를 최적화한다.
보안상 민감 정보(.env, 인증키 등)도 반드시 포함해 이미지 내부에 노출되지 않도록 관리해야 한다.
.gradle
build
out
.git
**/*.iml
*.log
Dockerfile
docker-compose.yml
.env
.env 파일은 데이터베이스 계정, API 키 등 환경별 설정값을 정의해 코드와 분리하여 관리한다.
민감 정보는 Git에 커밋하지 말고.gitignore에 추가해 보안을 유지해야 한다.
compose를 통해 서비스, 볼륨, 네트워크를 정의해 여러 컨테이너를 하나의 애플리케이션 단위로 관리한다.
환경변수와 의존성(depends_on)을 명확히 설정해 실행 순서와 환경을 일관성 있게 유지해야 한다.
version: '3.8'
services:
app:
build: .
ports: ["8081:80"]
env: SPRING_PROFILES_ACTIVE=prod…
volumes: [binary-content-storage:/app/storage]
depends_on: [db]
db:
image: postgres:16-alpine
ports: ["5432:5432"]
env: DB명=discodeit, …
volumes: [postgres-data:/var/lib/postgresql/data, schema.sql]
volumes:
postgres-data:
binary-content-storage:
networks:
discodeit-network:
Spring boot에서는 기존 민감 정보를 모두 제거하고, EL 표현식 ${~~}를 통해 적용하면 된다.
아래 설정 정보는 compose를 통해 환경변수로 주어짐으로 Spring에서는 제거한다.
server:
port: 80
spring:
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
jpa:
properties:
hibernate:
format_sql: false
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
environment:
SPRING_PROFILES_ACTIVE: prod
SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL}
SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME}
SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health | grep -q '\"status\":\"UP\"'"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s