
1. Docker란?
Docker는 애플리케이션을 개발하고 패키징하여 Container 형태로 격리된 환경에서 실행할 수 있도록 제공하는 플랫폼입니다
공식 문서에서는 Docker를 다음과 같이 설명합니다
Docker is an open platform for developing, shipping, and running applications.
What is Docker?
Get an in-depth overview of the Docker platform including what it can be used for, the architecture it employs, and its underlying technology.
docs.docker.com
Docker 자체가 Container 의미하는 것은 아니고 Docker는 Container를 생성,실행,관리하기 위한 기능을 제공하며
Docker Engin은 Image,Container,Network,Volume과 같은 여러 Docker Object를 관리합니다
Docker를 사용하면 애플리케이션과 실행에 필요한 환경을 하나의 Image를 구성하고 Image를 기반으로 Container를 실행할 수 있습니다
예를 들어 Spring Boot 애플리케이션을 Docker로 실행한다고 생각해 보겠습니다
Dockerfile
FROM eclipse-temurin:21-jre
COPY app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
💡 Dockerfile이란?
Docker Image를 만들기 위한 설정 파일로 실행 환경과 애플리케이션 구성 방법을 정의합니다
FROM,COPY,RUN,ENTRYPOINT 등의 명령어를 사용해 Image 생성 과정을 자동화할 수 있습니다
Dockerfile을 이용하면 Java 21 환경과 애플리케이션 실행 방법을 하나의 이미지로 만들 수 있습니다
이후 로컬이나 서버에서 Java를 직접 설치하고 버전을 맞추는 대신 Docker가 설치되어 있다면 해당 이미지를 사용하여 애플리케이션을 컨테이너 환경으로 띄워 실행할 수 있습니다
docker build -t my-app .
docker run -p 8080:8080 my-app
2. Docker Image란?
Docker에서 Image는 Container를 만들기 위한 실행 환경의 템플릿이라고 생각할 수 있습니다
쉽게 비유하면 정해진 레시피대로 완성품을 만드는 밀키트나 객체를 생성하기 위한 클래스와 비슷한 개념입니다
Dockerfile을 기반으로 Image를 만들고 그 Image를 실행하면 Container가 생성되어 실행되는 방식이라고 볼 수 있습니다
Image에는 애플리케이션 실행에 필요한 바이너리,라이브러리,설정 등이 포함될 수 있고 Docker 공식 문서에서는 Image를 Container 실행에 필요한 파일과 설정을 포함하는 표준화된 패키지로 설명합니다
예를 들어 MySQL 이미지를 내려받았다고 해서 MySQL이 실행되는 것은 아닙니다
docker pull mysql:8
이 명령어는 MySQL Image를 가져오는 과정이고
docker run mysql:8
처럼 Image를 실행했을 때 Container가 생성됩니다
Docker 공식 문서에서도 Container를 Image의 실행 가능한 인스턴스라고 설명하고 있습니다
3. Docker Container란?
Docker Container는 Docker Image를 기반으로 생성되어 격리된 환경에서 실행되는 프로세스입니다
실행에 필요한 파일은 Image에서 가져와 Container마다 별도의 파일 시스템과 네트워크,프로세스 환경을 가질 수 있습니다
일반적인 Linux 환경에서는 여러 프로세스가 하나의 운영체제 위에서 실행됩니다
Docker를 사용하면 각각을 독립적인 Container 안에서 실행할 수 있습니다
예를 들어 다음처럼 구성할 수 있습니다

각 Container는 서로 분리된 파일 시스템과 네트워크 등의 환경을 가지면서 Host OS의 Kernel을 공유합니다
이 부분이 Virtual Machine과 가장 큰 차이 중 하나입니다
💡Virtual Machine이란?
Virtual Machine은 Hypervisor 위에서 각각의 Guest OS를 포함해 독립된 가상 컴퓨터처럼 동작하는 환경입니다
반면 Docker Container는 별도의 Guest OS를 포함하지 않고 Host OS의 Kernel을 공유하면서 프로세스를 격리해 실행합니다
4. Docker를 왜 사용할까?
Docker를 사용하는 큰 이유 중 하나는 실행 환경을 일관되게 유지하기 쉽기 때문이라고 생각합니다
로컬환경에서 다음과 같은 환경에서 개발했다고 가정했을 때 Docker를 사용하지 않는다면 다른 사용자의 로컬에서 프로젝트를 실행하기 위해서는 각각의 프로그램을 설치해야 합니다 Java,MySQL,Redis를 설치하고 환경 변수와 설정 파일 또한 구성해야 합니다
Java 21
MySQL 8.0
Redis 7
Docker를 사용한다면 필요한 환경을 Docker Image와 Docker Compose로 정의할 수 있습니다
예를 들어 MySQL을 다음과 같이 Docker Container로 실행할 수 있습니다
docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=1234 \
-p 3306:3306 \
mysql:8
로컬 환경에 MySQL을 직접 설치하지 않아도 Docker Container 내부에서 MySQL을 실행 및 접속할 수 있습니다
Docker Compose를 사용한다면 여러 Image를 받아 Container로 한 번에 실행하도록 구성할 수 있습니다
Spring Boot 애플리케이션에서 MySQL, Redis, Nginx, Prometheus, Grafana, Loki를 함께 사용한다고 가정해 보겠습니다
Docker Compose를 사용하면 각 컨테이너의 실행 설정뿐만 아니라 환경 변수, 볼륨, 네트워크까지 하나의 파일에서 관리할 수 있습니다
services:
app:
build: .
container_name: spring-app
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/${MYSQL_DATABASE}
SPRING_DATASOURCE_USERNAME: ${MYSQL_USER}
SPRING_DATASOURCE_PASSWORD: ${MYSQL_PASSWORD}
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379
depends_on:
- mysql
- redis
networks:
- app-network
mysql:
image: mysql:8
container_name: mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
networks:
- app-network
redis:
image: redis:7
container_name: redis
ports:
- "6379:6379"
environment:
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PASSWORD: ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- app-network
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
networks:
- app-network
prometheus:
image: prom/prometheus
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
networks:
- app-network
grafana:
image: grafana/grafana
container_name: grafana
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
volumes:
- grafana-data:/var/lib/grafana
networks:
- app-network
loki:
image: grafana/loki
container_name: loki
ports:
- "3100:3100"
networks:
- app-network
volumes:
mysql-data:
redis-data:
grafana-data:
networks:
app-network:
driver: bridge
이렇게 구성하면 각 컨테이너는 app-network라는 동일한 Docker Network에 연결됩니다
같은 네트워크에 속한 컨테이너끼리는 IP 주소를 직접 지정하지 않고 서비스 이름을 Hostname처럼 사용하여 통신할 수 있습니다
예를 들어 Spring Boot에서 MySQL에 접근할 때는 다음과 같이 localhost가 아니라 mysql이라는 서비스 이름을 사용합니다
또한 MySQL이나 Redis와 같이 데이터가 유지되어야 하는 서비스는 Volume을 연결하여 컨테이너가 삭제되더라도 데이터를 보존할 수 있습니다
결과적으로 Docker Compose를 사용하면 여러 컨테이너를 단순히 실행하는 것뿐만 아니라 컨테이너 간 네트워크, 데이터 저장소, 환경 변수, 실행 순서 등을 하나의 파일에서 관리할 수 있습니다
docker compose up -d
위 명령어 하나로 정의된 전체 환경을 실행할 수 있습니다.