[강의] Docker 빌드/배포/컨테이너 실행하기

Jerry·2025년 9월 25일

Docker 개요

전통적인 배포 방식

  1. 환경별 설치 및 설정이 수동으로 이루어져 일관성이 보장되지 않고 오류 발생 가능성이 높았다.
  2. JDK, DB, 의존성 등을 개별적으로 설치•관리해야 하므로 유지보수와 확장이 어려웠다.
  3. 서버마다 설정이 달라 재현성과 이식성이 떨어지고 자동화 및 대규모 운영에 한계가 있었다.

Spring Boot 애플리케이션 배포 과전

  1. JDK 설치
  2. 애플리케이션 빌드 (JAR/WAR 파일 생성)
  3. 서버 환경에 JDK 설치
  4. 애플리케이션 구성 파일 설정 (application.yml)
  5. 데이터베이스 및 기타 의존성 설치 및 구성
  6. 실행 스크립트 작성
  7. 서비스 등록 및 시작

수동 설치와 설치 과정

  1. Java 런타입 환경 설치 및 설정
  2. 외부 의존성 설치 (데이터베이스, 캐시 등)
  3. 환경별 설정 파일 관리
  4. 시스템 부팅 시 자동 시작 설정

전통적인 Spring Boot 배포 명령어 예시

java -jar -Dspring.profiles.active=prod myapp.jar

전통적인 배포 방식의 문제점

구분설명문제점
환경 의존성 문제서버마다 JDK, 라이브러리, DB, OS 버전 등이 달라 동일 애플리케이션이 환경에 따라 정상 동작하지 않는 경우가 많았다. 특히 OS 버전 업그레이드 시 기존 설정과 충돌이 발생하여 재배포 과정에서 장애가 빈번했다.환경 재현성이 낮아 개발-테스트-운영 간 일관성이 깨지고 배포 안정성이 저하됨
설치 과정의 복잡성JDK 설치, 의존성 구성, 설정 파일 관리, 실행 스크립트 작성 등을 모두 수동으로 진행해야 했다.사람 실수에 의한 오류가 자주 발생, 서버가 늘어날수록 설치 및 관리 부담 증가, 자동화 도구 부족으로 유지보수 어려움
서버 자원 활용 비효율하나의 서버에 여러 애플리케이션을 배포하면 충돌이 발생하거나 특정 애플리케이션만 과도하게 자원을 점유할 수 있었다. 또한 서버 단위 확장이 필요해 비용과 관리 부담이 커졌다.자원 격리와 최적화 부족으로 인프라 활용 효율 저하

Docker의 개념

Docker는 애플리케이션과 그 실행 환경(라이브러리, 설정 등)을 컨테이너(container)라는 독립된 단위로 패키징하여 어디서든 동일하게 실행할 수 있도록 하는 플랫폼이다.
리눅스 커널의 네임스페이스와 cgroups 기능을 활용하여 가볍고 격리된 실행 환경을 제공한다.
이를 통해 개발•테스트•운영 환경 간의 일관성, 이식성, 확장성을 보장한다.

가상화 (Virtual Machine) vs 컨테이너 (Docker)

구분가상화 (Virtual Machine)컨테이너 (Docker)
구조하이퍼바이저 위에 각 VM이 Guest OS + 라이브러리 + 앱 포함된 구조Docker Engine 위에 라이브러리 + 앱만 포함
운영체제VM마다 독립적인 OS 필요 → 무겁고 자원 소모 큼, OS 격리 가능Host OS 공유, 컨테이너마다 별도 OS 불필요
성능OS 중복 실행으로 부팅/실행 느리고 메모리 사용량 많음가볍고 빠른 실행, 메모리 효율적
배포/이식성VM 이미지는 용량이 크고 이식에 시간 소요이미지 기반으로 빠른 배포, 이식성 뛰어남
격리성OS 단위 격리 → 높은 보안성, 완벽한 독립 환경 제공프로세스 단위 격리 → 빠르지만 보안 측면 상대적으로 약함
활용 사례레거시 시스템 운영, 완전한 OS 환경이 필요한 경우마이크로서비스, DevOps, CI/CD, 클라우드 네이티브 환경

Docker의 아키텍처

Docker는 클라이언트(Client) – 호스트(Docker Host) – 레지스트리(Registry) 3계층 구조로 동작하며, 이미지(Image)와 컨테이너(Container)를 중심으로 운영된다.

  • Client : 사용자가 docker build, docker pull, docker run 명령어를 실행하는 인터페이스
  • Docker Daemon : Docker Host에서 동작하며, 클라이언트 명령을 받아 컨테이너 생성·실행·관리 담당
  • Images : 실행 가능한 컨테이너의 템플릿, 애플리케이션과 환경(라이브러리, 설정 등)을 포함
  • Containers : 이미지를 기반으로 실행되는 인스턴스, 실제 애플리케이션이 동작하는 단위
  • Registry : Docker 이미지를 저장하고 공유하는 중앙 저장소 (예: Docker Hub, 프라이빗 레지스트리)

컨테이너 기술의 산업 표준

Docker는 2013년 Solomon Hykes가 dotCloud라는 PaaS 회사에서 내부 프로젝트로 시작되고 발전 되었다.
이후 컨테이너(Container) 기술을 대중화시키고 표준화한 플랫폼으로 성장 하였다.
애플리케이션과 실행 환경을 이미지 단위로 패키징하여 어디서나 동일하게 동작하게 해주며, DevOps와 클라우드 네이티브 아키텍처의 핵심 기반으로 자리 잡았다. 현재 Kubernetes와 같은 오케스트레이션 도구에서도 사실상 컨테이너 실행 표준(Runtime 표준)으로 Docker 기술이 반영되었다.

Docker의 특징과 장점

Docker 특징

특징설명
경량성 (Lightweight)별도의 Guest OS 없이 애플리케이션과 라이브러리만 포함하여 가볍게 실행됨
이미지 기반 (Image-based)컨테이너 실행 단위를 이미지로 관리하여 버전 관리, 배포, 공유가 용이함
격리성 (Isolation)각 컨테이너는 독립된 프로세스로 실행되어 충돌 없이 동작
신속한 실행 (Fast Startup)VM보다 훨씬 빠르게 컨테이너를 생성하고 실행 가능
표준화 (Standardization)컨테이너 실행 및 관리에 있어 사실상 업계 표준으로 자리 잡음

Docker 장점

장점설명
이식성 (Portability)동일한 이미지를 기반으로 개발, 테스트, 운영 환경 어디서든 동일하게 실행 가능
효율성 (Efficiency)VM보다 자원 소모가 적어 서버 활용도를 높임
확장성 (Scalability)마이크로서비스 단위로 손쉽게 확장 및 축소 가능
DevOps 최적화CI/CD 파이프라인과 자연스럽게 통합되어 자동화 및 빠른 배포 지원
생태계 (Ecosystem)Docker Hub 등 다양한 공개 이미지 및 커뮤니티 지원으로 생산성 향상

컨테이너와 이미지의 개념

컨테이너(Container) : 애플리케이션과 실행 환경을 격리하여 실행되는 가상화된 인스턴스이다.
이미지로부터 생성되며 독립된 프로세스(CPU, 메모리 사용)로 동작한다. (살아 있는 instance 개념)
이미지(Image) : 컨테이너 실행 하기 위한 불변의 템플릿이다. 코드, 라이브러리, 설정 등 실행에 필요한 요소를 포함하고 있으며 언제든 컨테이너로 실행 할 수 있다. (굳어 있는 class, 설계도 개념)

Docker의 주요 개념

개념설명
컨테이너 (Container)애플리케이션과 의존성을 포함한 독립적 실행 단위로, 격리된 환경에서 실행되지만 호스트 OS 커널을 공유함
이미지 (Image)컨테이너를 생성하기 위한 읽기 전용 템플릿으로, 애플리케이션 코드, 런타임, 라이브러리 등을 포함함
Dockerfile이미지를 빌드하기 위한 지시사항을 담은 텍스트 파일로, 베이스 이미지 선택부터 애플리케이션 실행까지 정의함
레지스트리 (Registry)Docker 이미지를 저장하고 배포하는 저장소로, 공용(Docker Hub)과 프라이빗 레지스트리가 존재함
볼륨 (Volume)컨테이너 외부에 데이터를 저장하여 컨테이너가 삭제되어도 데이터가 유지되도록 하는 영속적 저장소
네트워크 (Network)컨테이너 간 통신 및 외부 연결을 관리하는 가상 네트워크로, 브리지·호스트·오버레이 등 다양한 네트워크 드라이버 제공
엔진 (Docker Engine)컨테이너의 생성, 실행, 관리 등을 담당하는 핵심 런타임으로, 클라이언트-서버 구조로 구성되며 CLI/REST API를 통해 컨테이너, 이미지, 네트워크, 볼륨 등을 관리함

컨테이너화를 통한 배포의 해결

컨테이너화를 통한 배포는 애플리케이션과 실행 환경을 이미지로 패키징하여 어디서든 동일하게 실행할 수 있도록 한다. 이를 통해 배포 과정이 자동화되고 일관성이 보장되어 운영 효율성이 크게 향상된다.

Docker 시작하기

DockerHub란?

Docker Hub는 Docker에서 제공하는 공식 이미지 저장소(Registry 서비스)이다.
개발자는 Docker Hub를 통해 공개된 다양한 베이스 이미지(Ubuntu, Postgre 등)를 다운로드(pull)하여 활용할 수 있고, 자신이 만든 이미지를 업로드(push)하여 다른 사람들과 공유할 수도 있다.
공개 저장소(Public Repository)와 비공개 저장소(Private Repository)를 모두 지원하며, CI/CD 파이프라인과 연동되어 자동 빌드, 버전 관리, 협업이 가능하다.

DockerHub - 공식 이미지와 사용자 이미지

공식 이미지(Official) : Docker에서 직접 관리하거나 신뢰할 수 있는 벤더가 제공하는 검증된 표준 이미지
사용자 이미지(User) : 일반 사용자가 직접 빌드하고 업로드한 커스텀 이미지
docker pull nginx # 공식 이미지
docker pull bitnami/postgresql # 사용자 이미지

Docker Desktop

로컬 PC에서 손쉽게 Docker 환경을 실행하고 관리할 수 있도록 제공되는 GUI 기반 프로그램이다.
컨테이너, 이미지, 네트워크, 볼륨 등을 시각적으로 관리할 수 있으며 CLI와 통합되어 개발 편의성을 높인다.
Windows, macOS에서 가상화 환경을 활용해 Linux 기반 컨테이너 실행을 지원한다.
→ 기능은 좋으나 아쉽게도 로컬로만 실행됨으로 실습 때 외에는 활용 할 일이 별로 없다.

Docker Desktop 주요 기능

컨테이너 관리 : 실행, 중지, 삭제 및 상태 확인
이미지 관리 : 빌드, 다운로드, 업로드 및 버전 관리
네트워크·볼륨 : 컨테이너 통신과 데이터 지속성 관리
개발 환경 통합 : 로컬 Kubernetes, 가상화 기반 컨테이너 실행

Docker 공식 문서 활용

Docker의 공식 문서(https://docs.docker.com/)는 다음과 같은 주요 섹션으로 구성되어 있다.

  • Get Started: Docker의 기본 개념과 설치 방법
  • Guides: 다양한 사용 사례와 모범 사례
  • Manuals: Docker Engine, Compose, Desktop 등의 상세 매뉴얼
  • Reference: 명령어, API, Dockerfile 등의 레퍼런스
  • Samples: 다양한 예제와 데모

Docker 공식 문서 활용- 명령어 레퍼런스 활용법

Docker 명령어는 다음과 같은 구조로 되어 있다.
docker [OPTIONS] COMMAND [ARG...]
명령어에 대한 도움말을 보려면 아래와 같이 명령어를 통해 볼 수 있다.

docker --help # 전체 명령어 목록
docker run --help # 특정 명령어(run)에 대한 도움말을 볼 수 있다.

개발 과정에서 자주 참조해야 할 문서 페이지는 다음과 같다.

Docker 이미지 명령어

Docker 이미지 주요 명령어

명령어설명
docker images로컬에 저장된 이미지 목록 확인
docker image lsdocker 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 <파일>.tartar 파일에서 이미지 불러오기
docker push <레포>/<이미지>:<태그>이미지 레지스트리에 푸시

Docker 이미지 명령어

docker pull

원격 저장소(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 images

현재 로컬 환경에 다운로드 되어 있는 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

불필요한 이미지를 삭제하여 디스크 공간을 확보할 수 있는 명령어

# 기본 구문
docker rmi [OPTIONS] IMAGE [IMAGE...]

# 이미지 ID로 삭제
docker rmi a4a3c25e5d8c

# 이미지 이름:태그로 삭제
docker rmi postgres:17.6

# 사용하지 않는 이미지 모두 삭제
docker image prune

# 강제 삭제 (컨테이너가 이 이미지를 사용 중일 때)
docker rmi -f postgres:17.6

Docker 컨테이너 명령어

Docker 컨테이너 주요 명령어

명령어설명예시
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 컨테이너 명령어

docker run

컨테이너 이미지를 기반으로 새 컨테이너를 생성하고 지정한 프로세스를 실행하는 명령이다.
이미지가 없는 경우 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 : 볼륨 마운트

docker ps

실행 컨테이너 목록을 출력하는 명령어, 컨테이너 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 : 출력 형식을 지정하여 원하는 정보만 표시

docker start/stop/restart

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

실행 중인 컨테이너 안에서 추가 명령어를 실행할 때 사용하는 명령어이다.

# 기본 구문
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: 환경 변수 설정

docker logs

실행 중이거나 종료된 컨테이너의 표준 출력(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 <시간> : 특정 시점까지의 로그만 표시

docker rm

컨테이너를 삭제하는 명령어이다. 컨테이너를 삭제하면 해당 컨테이너의 파일시스템, 설정, 네트워크 정보가 사라진다.
단, 볼륨(-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 : 컨테이너 간 링크만 삭제 (컨테이너 자체는 유지)

docker cp

컨테이너와 호스트 간 파일을 주고받는 명령어이다.
컨테이너 내부 파일시스템과 로컬 파일시스템 간에 자유롭게 복사가 가능하다.
단, 컨테이너가 실행 중이든 중지 중이든 상관없이 동작한다.

# 호스트 → 컨테이너 복사
# 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의 네트워크와 볼륨

Docker의 네트워크의 개념

Docker 네트워크는 컨테이너 간 통신을 가능하게 하는 가상 네트워크이다.
컨테이너들은 동일 네트워크 안에서 서로 이름(DNS)으로 접근할 수 있다. 또한 브리지, 호스트, 오버레이와 같은 네트워크 드라이버를 통해 통신 방식을 선택하고 제어할 수 있다.

Docker의 네트워크의 종류

네트워크 종류특징명령어/예시
bridge (기본)단일 호스트 내 컨테이너용 기본 네트워크. 사용자 정의 브리지에선 컨테이너 이름(DNS) 으로 통신 가능. 외부 접근은 포트 바인딩 필요.docker network create -d bridge my-bridge
docker run -d --name app --network my-bridge -p 8080:8080 myimg
host컨테이너가 호스트 네트워크를 그대로 사용. 포트 바인딩 불필요(호스트 포트=컨테이너 포트). 성능은 좋지만 격리/보안 취약 → 일반적으로 비권장.docker run -d --network host myimg
overlay여러 호스트 간 컨테이너 통신. 스웜/오케스트레이션 환경에서 서비스 간 보안 네트워크 제공. (Docker Swarm/Kubernetes에서 사용)docker swarm init
docker network create --driver overlay my-overlay
docker service create --name web --network my-overlay nginx
none네트워크 비활성화. 외부·내부 통신 불가(완전 격리용).docker run -d --network none myimg

Docker의 네트워크 명령어

명령어설명예시
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 네트워크

기본 네트워크로, 컨테이너를 생성할 때 별도로 네트워크를 지정하지 않으면 자동으로 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 네트워크

컨테이너가 호스트의 네트워크 스택을 직접 사용한다. 컨테이너와 호스트 간 네트워크 격리가 없으므로 성능이 가장 좋다.

# host 네트워크를 사용하여 PostgreSQL 실행
docker run --name tomcat-host --network host -d tomcat:11
# 위 컨테이너는 호스트의 5432 포트를 직접 사용
# 포트 매핑(-p) 옵션 불필요

None 네트워크

네트워크 기능을 완전히 비활성화한다.
컨테이너가 외부와 통신할 수 없으며, 로컬 루프백 인터페이스만 사용 가능하다.

# 네트워크 없이 컨테이너 실행
docker run --name isolated-container --network none -d alpine sleep infinity

Overlay 네트워크

여러 Docker 호스트 간 통신을 위한 네트워크이다.
Docker Swarm이나 Kubernetes와 같은 클러스터 환경에서 사용된다.

# overlay 네트워크 생성 (Docker Swarm 모드에서)
docker network create --driver overlay my-overlay-network

Docker Volume의 개념

Docker Volume은 컨테이너와 독립적으로 데이터를 저장하는 영구적 저장소이다. 컨테이너가 삭제되거나 재시작 되어도 볼륨에 저장된 데이터는 유지되며, 여러 컨테이너가 같은 볼륨을 공유하여 데이터 일관성과 지속성을 확보할 수 있다.

Docker 볼륨 명령어

Docker 볼륨 명령어는 컨테이너와 분리된 데이터 저장 공간을 생성, 조회, 삭제, 관리하기 위해 사용된다.

# 볼륨 목록 확인
docker volume ls

# 볼륨 생성
docker volume create postgres-data

# 볼륨 정보 확인
docker volume inspect postgres-data

# 사용하지 않는 볼륨 삭제
docker volume prune

# 볼륨 삭제
docker volume rm postgres-data

Dockerfile과 이미지 빌드 및 배포

Dockerfile의 개념

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"]

Dockerfile 주요 지시어

지시어설명예시
FROM기반(Base) 이미지 지정FROM amazoncorretto:17
WORKDIR작업 디렉터리 설정WORKDIR /app
COPY호스트 파일/디렉터리를 컨테이너로 복사COPY build/libs/myapp.jar app.jar
ADDCOPY와 유사하지만 압축 해제·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"]

Dockerfile 작성 (기본)

# 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

Dockerfile 레이어의 개념

  1. 이미지 = 여러 레이어의 누적
    Docker 이미지는 하나의 파일 덩어리가 아니라, 여러 단계(layer) 로 나뉜다.
    FROM, RUN, COPY, ADD 같은 명령어가 실행될 때마다 새로운 레이어가 추가된다.
  2. 읽기 전용 레이어 + 쓰기 가능한 레이어
    빌드된 이미지는 읽기 전용 레이어들의 스택이고, 컨테이너가 실행되면 그 위에 쓰기 가능한 컨테이너 레이어가 덧붙여진다.
  3. 캐시 활용
    Docker는 같은 명령어와 같은 입력이 있으면 이전에 만들어둔 레이어를 재사용(cache)한다. 그래서 코드 변경이 없으면 빠르게 빌드 된다.

Dockerfile 최적화 방법 – multi stage

멀티 스테이지(Multi-Stage) Dockerfile은 빌드 과정과 실행 환경을 분리하여 최적화하는 기법이다.
빌드 스테이지에서는 빌드 도구와 의존성을 포함해 애플리케이션을 컴파일하고 산출물을 생성한다.
최종 런타임 스테이지에는 최소한의 OS와 실행에 필요한 파일만 포함해 이미지 크기를 줄이고 보안을 강화한다.

이미지 빌드와 배포

docker buildx build

확장 빌드 도구: 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 .

이미지 태깅 (Tagging)

형식: 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

DockerHub 배포

# 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 활용

Docker Compose의 개념

Docker Compose는 여러 개의 컨테이너 서비스를 하나의 설정 파일로 정의하고 관리하는 도구이다.
하나의 앱을 구성하는 DB, 웹서버, 백엔드 등을 동시에 실행하고 네트워크·볼륨을 자동으로 설정해준다.
주로 docker-compose.yml 파일로 생성하며 docker compose up 같은 명령으로 손쉽게 빌드·실행·중지까지 전체 환경을 일괄 관리할 수 있다.

Docker Compose 소개

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에서.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}

Docker Compose 계층 별 사용 키워드 정리

계층키워드설명예시
루트services실행할 컨테이너 서비스 정의의 최상위 블록services: { app: ..., db: ... }
networks서비스 간 통신에 사용하는 네트워크 정의networks: { app-net: {} }
volumes데이터 영속화를 위한 볼륨 정의volumes: { pgdata_dev: {} }
services 하위<service-name>각 서비스 이름 정의app:, db:
buildDockerfile 빌드 정보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 관련 주요 명령어

# 전체 서비스 빌드 후 실행 (백그라운드 모드)
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 어플리케이션 컨테이너화

Spring Boot 어플리케이션 준비

Spring Boot 프로젝트 내에서 컨테이너 실행 환경에 맞는 설정 분리 통해 안정성을 확보하는 과정이다.
컨테이너화를 위해 빌드 스크립트(build.gradle), Dockerfile, docker-compose.yml, .env 를 구성하여 실행과 배포를 표준화 하며 로그 관리, 환경변수 주입, 헬스체크 같은 운영 관리 요소까지 포함해 프로덕션 환경에 적합하게 셋팅 할 수 있다.

Dockerfile 작성

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 작성

.dockerignore는 빌드에 불필요한 파일(.git, 로그, 빌드 등)을 제외해 이미지 크기와 빌드 속도를 최적화한다.
보안상 민감 정보(.env, 인증키 등)도 반드시 포함해 이미지 내부에 노출되지 않도록 관리해야 한다.

.gradle
build
out
.git
**/*.iml
*.log
Dockerfile
docker-compose.yml
.env

.env 작성

.env 파일은 데이터베이스 계정, API 키 등 환경별 설정값을 정의해 코드와 분리하여 관리한다.
민감 정보는 Git에 커밋하지 말고.gitignore에 추가해 보안을 유지해야 한다.

docker compose 작성

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 - application.yml 적용

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

컨테이너 실행과 관리

  1. 로그 관리 (Log Management)
    표준 출력/표준 에러 사용
    • Spring Boot는 기본적으로 콘솔 로그를 표준 출력(stdout)으로 남긴다.
    • Docker 컨테이너는 이를 수집해 docker logs <컨테이너명>으로 확인 가능하다.
logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"
  1. 환경변수 주입 (Environment Variables)
  • .env 파일 → docker-compose.yml → 컨테이너 ENV 구조로 관리
  • Spring Boot는 SPRING_DATASOURCE_URL, SPRING_PROFILES_ACTIVE 같은 표준 키를 자동 인식한다.
  • 보안 정보(DB 비밀번호 등)는 운영 환경에서 비밀관리자(Secrets Manager)로 대체하는 것이 권장된다.
environment:
  SPRING_PROFILES_ACTIVE: prod
  SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL}
  SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME}
  SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD}
  1. 헬스체크 (Health Check)
  • Docker Compose의 healthcheck를 이용해 DB 연결이나 HTTP 응답을 주기적으로 확인한다.
healthcheck:
  test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health | grep -q '\"status\":\"UP\"'"]
  interval: 10s
  timeout: 5s
  retries: 10
  start_period: 30s
  1. 애플리케이션 레벨
    • Spring Boot Actuator health, readiness, liveness 엔드포인트 활용
    • /actuator/health → 기본 상태 확인
    • /actuator/health/liveness → 애플리케이션 살아있는지 확인
    • /actuator/health/readiness → 서비스 요청을 받을 준비가 되었는지 확인
profile
Backend engineer

0개의 댓글