✅ 배포 방식의 변화 과정

▶ 전통적 배포 (Traditional Depolyment)
- 구성: 하드웨어 -> 운영체제 -> 애플리케이션
- 설명: 물리적인 컴퓨터 한 대에 하나의 OS를 설치하고, 애플리케이션이 해당 운영 체제에서 직접 실행되는 방식이다.
- 문제점
- 자원 공유 문제: 애플리케이션들이 동일한 OS를 공유하므로, 같은 리소스(라이브러리, 네트워크, CPU)를 사용하게 된다. 이로 인해 성능 문제가 발생하게 된다.
- 확장성 부족: 새로운 애플리케이션을 설치하거나 추가하려면 운영 체제 및 하드웨어의 환경에 맞게 설치하고 설정해야 한다.
- 배포 방식
- 하나의 물리적 서버가 있다.
- 물리적 서버 위에 운영 체제를 설치한다.
- 동일한 운영 체제에서 여러 프로덕트를 실행한다. 발생하는 문제들을 피하려면 물리적 서버를 추가로 구매해야 한다.
▶ 가상화 배포 (Virtualized Deployment)
- 구성: 하드웨어 -> 운영 체제 -> 하이퍼바이저 -> 가상 머신 (VM)
- 설명: 하이퍼바이저를 통해 여러 가상 머신(VM)을 실행하는 방식이다. 각 VM은 자체 운영 체제를 가지고 있으며, 애플리케이션과 필요한 라이브러리가 포함되어 있어 독립적으로 실행된다.
- 문제점
- 자원 사용의 비효율성: 각 VM이 자체 운영 체제를 포함하고 있어, 독립적인 프로덕트를 추가할 때마다 불필요한 OS 인스턴스가 생성되므로 확장성이 떨어지고 리소스 부담이 크다.
- 배포 방식
- 하나의 물리적 서버가 있다.
- 물리적 서버 위에 하이퍼바이저를 설치한다.
- 하이퍼바이저를 이용해 여러 개의 가상 머신(VM)을 생성한다. 각 가상 머신은 자체 운영 체제를 갖추고 있어 독립적인 서버처럼 동작한다.
- 각 프로덕트를 각각의 가상머신에 배포한다.
가상화(Virtualization): 물리적 하드웨어 자원을 논리적으로 분리하여 여러 개의 가상 환경으로 사용할 수 있게 하는 기술이다. 즉, 하나의 서버에 여러 운영 체제를 동시에 설치하고, 이를 통해 여러 애플리케이션을 독립적으로 실행할 수 있는 방식이다.
▶ 컨테이너 배포 (Container Depolyment)
- 구성: 하드웨어 -> 운영 체제 -> 컨테이너 런타임(Docker 등) -> 컨테이너
- 설명: 컨테이너 배포는 애플리케이션과 필요한 라이브러리를 컨테이너라는 경량화된 가상 환경에서 실행하는 방식이다. 각 컨테이너는 운영 체제의 커널을 공유하지만, 서로 독립적으로 실행되며 필요한 라이브러리와 종속성을 포함한다. 컨테이너는 가상 머신과 달리 별도의 운영 체제를 포함하지 않으므로 자원 소모가 적고, 빠른 실행과 배포가 가능하다.
- 문제점
- 보안 격리 문제: 특정 프로그램이 운영 체제에 문제를 일으킬 경우, 해당 OS에서 실행 중인 다른 컨테이너에도 영향을 미칠 수 있다.
- 방식
- 하나의 물리적 서버가 있다.
- 물리적 서버 위에 운영 체제를 설치한다.
- 운영 체제 위에 컨테이너 런타임(Docker 등)을 설치한다. 컨테이너 런타임은 컨테이너를 생성하고 관리하는 역할을 한다.
- 컨테이너 런타임을 이용해 여러 개의 컨테이너를 생성한다. 각 컨테이너는 애플리케이션과 필요한 라이브러리만을 포함한다.
- 각 프로덕트를 각각의 컨테이너에 배포한다.
컨테이너(Container): 애플리케이션과 그에 필요한 모든 라이브러리, 종속성, 설정 파일 등을 하나의 단위로 묶어 독립적인 서버처럼 사용할 수 있는 경량화된 가상 환경이다.
컨테이너 런타임(Container Runtime): 컨테이너를 실제로 실행하고 관리하는 소프트웨어이다. 컨테이너 이미지에서 컨테이너를 생성하고, 이를 실행하거나 중지하는 등의 작업을 수행한다. 예로 Docker, containerd, CRI-O, runc 등이 있다.
▶ 정리
전통적 배포 | 가상화 배포 | 컨테이너 배포 | |
컴퓨터 | 물리적 컴퓨터 1대 | 물리적 컴퓨터 1대 + 다수의 가상 머신 | 컴퓨터 형태에 영향받지 않음 |
운영 체제 (OS) | 물리적 컴퓨터 1대에 OS 1개 설치 | 물리적 컴퓨터 OS 1대 + 각 가상머신마다 OS 설치 | 컴퓨터 형태와 관계없이 OS 1개 설치 |
리소스 | 컴퓨터 자원을 여러 프로그램이 공유 사용 | 하이퍼바이저를 통해 가상 머신별 개별적 자원 할당 | OS에서 각 컨테이너에 자원을 할당하고 관리 |
격리 수준 | 프로그램 간 격리되지 않음, 간섭 발생 가능 | 각 가상 머신이 완전히 격리됨 | 프로그램 실행 환경은 격리되지만, OS는 공유 |
문제 전이 가능성 | 특정 프로그램의 문제가 시스템 전체 중단 가능 | 특정 가상 머신의 문제는 다른 가상 머신에 영향 없음 | 특정 프로그램의 문제는 다른 프로그램에 영향을 미치지 않지만, 해당 문제가 OS에 영향을 줄 경우 시스템 중단 가능성 있음 |
✅ 도커 (Docker)
도커(Docker)는 애플리케이션을 신속하게 배포하고 운영하기 위해 컨테이너(Container) 기술을 사용하는 플랫폼이다.

🔽 도커 구성 요소
- 도커 파일 (Dockerfile)
- 도커 이미지 (Docker Image)
- 도커 컨테이너 (Docker Container)
▶ 도커 구성 요소: 1. 도커 파일 (Dockerfile)
Dockerfile은 Docker 이미지를 생성하기 위한 설정 파일이다. Dockerfile을 사용하면 이미지를 빌드하는 과정을 자동화하고, 빌드 과정에 대한 세부 사항을 정의할 수 있다. 이를 통해 이미지 빌드를 일관성 있게 반복할 수 있으며, 이미지 구성을 버전 관리 시스템으로 관리하기에도 용이하다.
🔽 Dockerfile 작성 단계
- 베이스 이미지 지정(FROM): 어떤 이미지(운영체제)를 기반으로 도커 이미지를 만들지 지정한다.
- 작업 디렉토리 설정(WORKDIR): 이미지 내에서 작업 디렉토리를 설정하여 파일을 추가하거나 명령을 실행할 위치를 지정한다.
- 필요한 파일 복사(COPY 또는 ADD): 호스트 시스템의 파일을 컨테이너 내부로 복사한다.
- 패키지 설치(RUN): 이미지를 빌드하는 과정에서 필요한 패키지나 소프트웨어를 설치한다.
- 환경변수 설정(ENV): 컨테이너 실행 시 필요한 환경 변수를 설정한다.
- 의존성 설치(RUN 또는 COPY 후 RUN): 필요한 라이브러리나 의존성을 설치한다.
- 포트 설정(EXPOSE): 컨테이너가 외부에서 접근 가능한 포트를 명시한다.
- 명령 실행(CMD 또는 ENTRYPOINT): 컨테이너가 실행될 때 기본으로 실행할 명령을 정의한다.
🔽 Dockerfile 명령어
명령어 | 설명 | 예시 |
FROM | 베이스 이미지 지정 | FROM openjdk:17-jdk-alpine |
WORKDIR | 작업 디렉토리 설정 | WORKDIR /app |
COPY | 호스트 시스템에서 파일, 디렉토리를 컨테이너 내부로 복사 | COPY . /app |
ADD | COPY와 유사하지만, URL에서 직접 파일을 다운로드하거나 압축파일을 풀 수 있는 기능 포함 | ADD https://example.com/file.zip /app |
RUN | 컨테이너 내에서 실행할 명령어 정의 | RUN apt-get update && apt-get install -y curl |
ENV | 환경 변수 설정 | ENV JAVA_HOME /usr/lib/jvm/java-17-openjdk |
EXPOSE | 컨테이너에서 외부로 노출할 포트 지정 | EXPOSE 8080 |
CMD | 컨테이너 시작 시 기본으로 실행할 명령어 | CMD ["java", "-jar", "app.jar"] |
ENTRYPOINT | 컨테이너 시작 시 실행할 명령어 설정 | ENTRYPOINT ["java", "-jar", "app.jar"] |
ARG | Dockerfile 빌드 시 넘겨줄 수 있는 변수 | ARG JAR_FILE=target/app.jar |
VOLUME | 컨테이너와 호스트 간의 공유 디렉토리 설정 | VOLUME /app/data |
🔽 Dockerfile 빌드
docker build 명령은 Docker 이미지를 빌드하기 위해 사용되는 명령어이다. 이 명령어를 통해 Dockerfile에 정의된 지시사항을 순차적으로 수행하여 이미지를 구성하고 빌드할 수 있다. 빌드 과정 중 Dockerfile에 정의된 단계들이 순차적으로 실행되며, 최종적으로 Docker 이미지가 생성된다.
docker build [옵션] [Dockerfile 경로]
- 옵션
- -t, --tag: 빌드된 이미지에 태그 지정, "이미지 이름:태그" 형식으로 사용하며, 생략 시 기본으로 latest 태그가 설정
- -f, --file: 사용할 Dockerfile의 경로를 지정, 기본값은 ./Dockerfile
- -q, --quiet: 빌드 진행 상황 메시지를 출력하지 않음
- --build-arg: Dockerfile 내의 ARG 지시문에 전달할 빌드 인자를 지정
▶ 도커 구성 요소: 2. 도커 이미지 (Docker Image)
Docker 이미지는 애플리케이션과 해당 애플리케이션을 실행하는 데 필요한 모든 것을 포함한 불변의 파일 시스템 스냅샷이다. 이 이미지에는 코드, 런타임, 라이브러리, 환경 변수, 설정 파일 등이 포함되어 있으며, 이를 기반으로 도커 컨테이너가 생성된다.
🔽 특징
- 불변성: 도커 이미지는 변경되지 않으며, 이미지를 수정하려면 새로운 이미지로 빌드해야 한다.
- 레이어 구성: 도커 이미지는 여러 개의 읽기 전용 레이어로 구성된다. 각 레이어는 추가된 파일이나 변경사항을 나타내며, 도커는 이러한 레이어들을 합쳐 하나의 파일 시스템으로 사용한다. 도커는 DockerHub에 이미지 다운로드 또는 업로드 시 변경된 레이어만 전송하므로 효율적으로 이미지를 관리할 수 있다.
- 이미지 관리 및 배포: 도커 이미지는 DockerHub와 같은 서비스에서 버전 관리 및 배포(push & pull)가 가능하다.
- Dockerfile 사용: 도커 이미지는 Dockerfile이라는 파일을 사용해 생성된다.
- 컨테이너 생성의 기반: 도커 이미지를 기반으로 도커 컨테이너가 생성된다. 컨테이너는 이미지의 가상화된 실행 인스턴스이다.
▶ 도커 구성 요소: 3. 도커 컨테이너 (Docker Container)
Docker 컨테이너는 Docker 이미지를 기반으로 실행되는 가상화된 환경이다. 이미지에서 생성된 인스턴스로, 애플리케이션이 실제로 실행되는 공간이다.
🔽 특징
- 읽기/쓰기 가능: 컨테이너는 이미지와 달리 읽기와 쓰기가 가능하다. 이미지를 기반으로 읽기/쓰기 레이어를 추가하여 컨테이너가 생성되며, 변경된 내용은 이 레이어에 저장된다.
- 효율적인 자원 사용: 여러 개의 컨테이너가 동일한 이미지를 기반으로 생성되더라도, 각 컨테이너는 변경된 부분만을 읽기/쓰기 레이어에 기록하므로 최소한의 용량을 사용한다.
- 명시적 삭제 필요: 컨테이너가 종료되더라도 자동으로 삭제되지 않는다. 삭제하려면 명시적으로 삭제 명령을 실행해야 하며, 삭제 시 컨테이너에서 생성된 파일도 함께 제거된다.
- 독립된 실행 환경: 하나의 서버에 여러 개의 컨테이너를 실행할 수 있으며, 각 컨테이너는 서로 완전히 독립된 환경에서 실행되기 때문에 다른 컨테이너나 호스트에 영향을 주지 않는다.
- 호스트 자원 공유: 컨테이너는 호스트 운영체제의 커널과 자원을 공유한다. 따라서 가상 머신보다 가벼운 성능을 제공한다.
🔽 Docker Container 실행
docker run 명령어는 도커 컨테이너를 실행하는 명령어이다.
docker run [옵션] 이미지 [인자]
- 옵션
- -d: 백그라운드에서 실행
- -p: 포트 바인딩
- --name: 컨테이너 이름 지정
- -e: 환경 변수 설정
- -v: 볼륨 마운트
- 이미지: 도커 이미지의 이름이다. 컨테이너를 생성할 이미지 이름을 명시한다. (ex: nginx, mysql:5.7 등)
- 인자: 실행될 명령어나 인자를 지정한다. (ex: /bin/bash, npm start 등)
✅ 도커 포트 바인딩
도커 컨테이너는 기본적으로 외부 네트워크와 격리되어 있어 외부에서 직접 접근할 수 없다. 도커 포트 바인딩은 컨테이너 내부에서 실행되는 서비스나 애플리케이션을 외부에서 접근할 수 있도록 포트를 연결하는 과정이다.
🔽 명령어 예시
포트를 바인딩하려면 docker run 명령어에서 -p 또는 --publish 옵션을 사용한다.
docker run -d -p 8080:80 my-web-app
- 이 예시는 호스트의 8080 포트를 컨테이너 내부의 80 포트에 바인딩한다. 따라서 localhost:8080으로 접근하면 컨테이너 내부의 80 포트에서 제공하는 웹 서비스에 연결된다.
✅ 도커 컴포즈
Docker Compose는 여러 개의 컨테이너를 정의하고, 이들을 한 번에 관리할 수 있는 도구이다. 보통 하나의 애플리케이션은 여러 서비스(예: 웹 서버, 데이터베이스 등)로 구성되며, 각각의 서비스는 별도의 도커 컨테이너로 실행된다. 도커 컴포즈를 사용하면 이러한 여러 컨테이너를 한 번에 설정하고 관리할 수 있다.
▶ 특징
- 멀티 컨테이너 설정 관리: 복잡한 애플리케이션 환경을 코드로 정의하여 여러 컨테이너를 손쉽게 시작하고 종료할 수 있다.
- YAML 파일 사용: docker-compose.yml 파일을 사용하여 다양한 컨테이너 설정(서비스, 네트워크, 볼륨 등)을 정의한다.
- 간편한 명령어: 단일 명령어로 모든 서비스들을 일괄적으로 실행(docker-compose up)하거나 종료(docker-compose down)할 수 있다.
▶ docker-compose.yml 속성
속성 | 설명 | 예시 |
version | docker-compose.yml 파일의 버전을 정의 | version: '3.8' |
services | 여러 컨테이너를 정의하는 부분 | services: web: image: nginx app: build: . |
build | 이미지를 빌드할 디렉토리를 지정 | build: . |
image | 서비스에 사용할 도커 이미지를 정의 | image: my_image:latest |
container_name | 컨테이너의 이름을 설정 | container_name: my_app_container |
ports | 호스트와 컨테이너 간의 포트 매핑을 정의 | ports: - "8080:80" |
volumes | 호스트와 컨테이너 간의 파일 시스템을 공유하는 설정 | volumes: - ./data:/var/lib/data |
environment | 컨테이너 실행 시 환경 변수를 설정 | environment: - JAVA_OPTS=-Xmx512m |
depends_on | 특정 서비스가 다른 서비스보다 먼저 실행되도록 순서를 지정 | depends_on: - db |
networks | 서비스를 연결하는 네트워크를 정의 | networks: - my_network |
command | 컨테이너가 시작될 때 실행할 명령어를 지정 | command: ["npm", "start"] |
restart | 컨테이너가 종료되었을 때 재시작할 정책을 설정 | restart: always |
▶ 명령어
1. 컨테이너 실행
# 컨테이너 실행
docker-compose up
# 컨테이너를 백그라운드 모드에서 실행
docker-compose up -d
# 기존 컨테이너를 삭제하고 새로 생성하여 실행
docker-compose up --force-recreate
# 이미지를 다시 빌드한 후 컨테이너 실행
docker-compose up --build
2. 컨테이너 종료
# 컨테이너 종료
docker-compose down
# 컨테이너 일시 중단
docker-compose stop
✅ 도커의 워크 플로우
1. Dockerfile 작성: 애플리케이션 실행 환경을 정의하는 Dockerfile을 작성한다.
# 베이스 이미지로 OpenJDK 사용
FROM openjdk:17-jdk-alpine
# 컨테이너 내의 작업 디렉토리 설정
WORKDIR /app
# 호스트의 JAR 파일을 컨테이너로 복사
COPY target/app.jar /app/app.jar
# 환경 변수 설정 (필요시)
ENV JAVA_OPTS=""
# 컨테이너가 실행될 때 JAR 파일을 실행하도록 설정
ENTRYPOINT ["java", "-jar", "app.jar"]
2. 이미지 빌드: Dockerfile을 사용하여 도커 이미지를 빌드한다.
docker build -t my_image .
3. 컨테이너 실행: 도커 이미지를 기반으로 컨테이너를 실행하여 애플리케이션을 구동한다.
docker run -p 8080:80 my_image
4. docker-compose.yml 파일 작성: 여러 컨테이너를 쉽게 관리하고 동시에 실행하기 위해 docker-compose.yml 파일을 작성한다.
version: '3.8' # docker-compose 파일의 버전 지정
services:
app: # 서비스 이름
image: my_image # 빌드된 도커 이미지 이름
build:
context: . # Dockerfile의 위치
dockerfile: Dockerfile # 빌드 시 사용할 Dockerfile 지정 (기본값은 Dockerfile)
ports:
- "8080:80" # 호스트의 8080 포트를 컨테이너의 80 포트에 연결
environment:
- JAVA_OPTS=-Xms512m -Xmx1024m # 컨테이너 실행 시 사용할 환경 변수
volumes:
- ./logs:/app/logs # 호스트의 logs 디렉토리를 컨테이너의 /app/logs에 마운트
# 필요한 경우 다른 서비스 추가
database:
image: postgres:14-alpine # PostgreSQL 데이터베이스 이미지 사용
environment:
POSTGRES_USER: user # 데이터베이스 사용자 이름
POSTGRES_PASSWORD: password # 데이터베이스 비밀번호
POSTGRES_DB: my_database # 데이터베이스 이름
ports:
- "5432:5432" # 호스트의 5432 포트를 컨테이너의 5432 포트에 연결
volumes:
- pgdata:/var/lib/postgresql/data # 데이터 유지용 볼륨
volumes:
pgdata: # 볼륨 선언 (데이터 유지)
5. 도커 컴포즈 활용: Compose를 통해 실행한다.
docker-compose up
✅ 도커 이미지 도커 허브에 업로드
- 도커 허브에 로그인: 도커 허브(https://hub.docker.com)에 로그인한다.
- 도커 허브에서 레포지토리 생성:
- 도커 허브에 로그인한 후, 오른쪽 상단의 "Create Repository" 버튼을 클릭한다.
- 레포지토리 이름과 설정(public/private 등)을 지정하고 "Create" 버튼을 눌러 레포지토리를 생성한다.
- 도커 CLI에 로그인: 도커 CLI에서 도커 허브에 로그인한다.
docker login
- 도커 이미지 푸시: 도커 허브에 이미지를 업로드한다. (버전명 존재 시 버전명까지 필수)
docker push 도커허브계정명/도커레포지토리:태그명
📍 참고
✅ 배포 방식의 변화 과정

▶ 전통적 배포 (Traditional Depolyment)
- 구성: 하드웨어 -> 운영체제 -> 애플리케이션
- 설명: 물리적인 컴퓨터 한 대에 하나의 OS를 설치하고, 애플리케이션이 해당 운영 체제에서 직접 실행되는 방식이다.
- 문제점
- 자원 공유 문제: 애플리케이션들이 동일한 OS를 공유하므로, 같은 리소스(라이브러리, 네트워크, CPU)를 사용하게 된다. 이로 인해 성능 문제가 발생하게 된다.
- 확장성 부족: 새로운 애플리케이션을 설치하거나 추가하려면 운영 체제 및 하드웨어의 환경에 맞게 설치하고 설정해야 한다.
- 배포 방식
- 하나의 물리적 서버가 있다.
- 물리적 서버 위에 운영 체제를 설치한다.
- 동일한 운영 체제에서 여러 프로덕트를 실행한다. 발생하는 문제들을 피하려면 물리적 서버를 추가로 구매해야 한다.
▶ 가상화 배포 (Virtualized Deployment)
- 구성: 하드웨어 -> 운영 체제 -> 하이퍼바이저 -> 가상 머신 (VM)
- 설명: 하이퍼바이저를 통해 여러 가상 머신(VM)을 실행하는 방식이다. 각 VM은 자체 운영 체제를 가지고 있으며, 애플리케이션과 필요한 라이브러리가 포함되어 있어 독립적으로 실행된다.
- 문제점
- 자원 사용의 비효율성: 각 VM이 자체 운영 체제를 포함하고 있어, 독립적인 프로덕트를 추가할 때마다 불필요한 OS 인스턴스가 생성되므로 확장성이 떨어지고 리소스 부담이 크다.
- 배포 방식
- 하나의 물리적 서버가 있다.
- 물리적 서버 위에 하이퍼바이저를 설치한다.
- 하이퍼바이저를 이용해 여러 개의 가상 머신(VM)을 생성한다. 각 가상 머신은 자체 운영 체제를 갖추고 있어 독립적인 서버처럼 동작한다.
- 각 프로덕트를 각각의 가상머신에 배포한다.
가상화(Virtualization): 물리적 하드웨어 자원을 논리적으로 분리하여 여러 개의 가상 환경으로 사용할 수 있게 하는 기술이다. 즉, 하나의 서버에 여러 운영 체제를 동시에 설치하고, 이를 통해 여러 애플리케이션을 독립적으로 실행할 수 있는 방식이다.
▶ 컨테이너 배포 (Container Depolyment)
- 구성: 하드웨어 -> 운영 체제 -> 컨테이너 런타임(Docker 등) -> 컨테이너
- 설명: 컨테이너 배포는 애플리케이션과 필요한 라이브러리를 컨테이너라는 경량화된 가상 환경에서 실행하는 방식이다. 각 컨테이너는 운영 체제의 커널을 공유하지만, 서로 독립적으로 실행되며 필요한 라이브러리와 종속성을 포함한다. 컨테이너는 가상 머신과 달리 별도의 운영 체제를 포함하지 않으므로 자원 소모가 적고, 빠른 실행과 배포가 가능하다.
- 문제점
- 보안 격리 문제: 특정 프로그램이 운영 체제에 문제를 일으킬 경우, 해당 OS에서 실행 중인 다른 컨테이너에도 영향을 미칠 수 있다.
- 방식
- 하나의 물리적 서버가 있다.
- 물리적 서버 위에 운영 체제를 설치한다.
- 운영 체제 위에 컨테이너 런타임(Docker 등)을 설치한다. 컨테이너 런타임은 컨테이너를 생성하고 관리하는 역할을 한다.
- 컨테이너 런타임을 이용해 여러 개의 컨테이너를 생성한다. 각 컨테이너는 애플리케이션과 필요한 라이브러리만을 포함한다.
- 각 프로덕트를 각각의 컨테이너에 배포한다.
컨테이너(Container): 애플리케이션과 그에 필요한 모든 라이브러리, 종속성, 설정 파일 등을 하나의 단위로 묶어 독립적인 서버처럼 사용할 수 있는 경량화된 가상 환경이다.
컨테이너 런타임(Container Runtime): 컨테이너를 실제로 실행하고 관리하는 소프트웨어이다. 컨테이너 이미지에서 컨테이너를 생성하고, 이를 실행하거나 중지하는 등의 작업을 수행한다. 예로 Docker, containerd, CRI-O, runc 등이 있다.
▶ 정리
전통적 배포 | 가상화 배포 | 컨테이너 배포 | |
컴퓨터 | 물리적 컴퓨터 1대 | 물리적 컴퓨터 1대 + 다수의 가상 머신 | 컴퓨터 형태에 영향받지 않음 |
운영 체제 (OS) | 물리적 컴퓨터 1대에 OS 1개 설치 | 물리적 컴퓨터 OS 1대 + 각 가상머신마다 OS 설치 | 컴퓨터 형태와 관계없이 OS 1개 설치 |
리소스 | 컴퓨터 자원을 여러 프로그램이 공유 사용 | 하이퍼바이저를 통해 가상 머신별 개별적 자원 할당 | OS에서 각 컨테이너에 자원을 할당하고 관리 |
격리 수준 | 프로그램 간 격리되지 않음, 간섭 발생 가능 | 각 가상 머신이 완전히 격리됨 | 프로그램 실행 환경은 격리되지만, OS는 공유 |
문제 전이 가능성 | 특정 프로그램의 문제가 시스템 전체 중단 가능 | 특정 가상 머신의 문제는 다른 가상 머신에 영향 없음 | 특정 프로그램의 문제는 다른 프로그램에 영향을 미치지 않지만, 해당 문제가 OS에 영향을 줄 경우 시스템 중단 가능성 있음 |
✅ 도커 (Docker)
도커(Docker)는 애플리케이션을 신속하게 배포하고 운영하기 위해 컨테이너(Container) 기술을 사용하는 플랫폼이다.

🔽 도커 구성 요소
- 도커 파일 (Dockerfile)
- 도커 이미지 (Docker Image)
- 도커 컨테이너 (Docker Container)
▶ 도커 구성 요소: 1. 도커 파일 (Dockerfile)
Dockerfile은 Docker 이미지를 생성하기 위한 설정 파일이다. Dockerfile을 사용하면 이미지를 빌드하는 과정을 자동화하고, 빌드 과정에 대한 세부 사항을 정의할 수 있다. 이를 통해 이미지 빌드를 일관성 있게 반복할 수 있으며, 이미지 구성을 버전 관리 시스템으로 관리하기에도 용이하다.
🔽 Dockerfile 작성 단계
- 베이스 이미지 지정(FROM): 어떤 이미지(운영체제)를 기반으로 도커 이미지를 만들지 지정한다.
- 작업 디렉토리 설정(WORKDIR): 이미지 내에서 작업 디렉토리를 설정하여 파일을 추가하거나 명령을 실행할 위치를 지정한다.
- 필요한 파일 복사(COPY 또는 ADD): 호스트 시스템의 파일을 컨테이너 내부로 복사한다.
- 패키지 설치(RUN): 이미지를 빌드하는 과정에서 필요한 패키지나 소프트웨어를 설치한다.
- 환경변수 설정(ENV): 컨테이너 실행 시 필요한 환경 변수를 설정한다.
- 의존성 설치(RUN 또는 COPY 후 RUN): 필요한 라이브러리나 의존성을 설치한다.
- 포트 설정(EXPOSE): 컨테이너가 외부에서 접근 가능한 포트를 명시한다.
- 명령 실행(CMD 또는 ENTRYPOINT): 컨테이너가 실행될 때 기본으로 실행할 명령을 정의한다.
🔽 Dockerfile 명령어
명령어 | 설명 | 예시 |
FROM | 베이스 이미지 지정 | FROM openjdk:17-jdk-alpine |
WORKDIR | 작업 디렉토리 설정 | WORKDIR /app |
COPY | 호스트 시스템에서 파일, 디렉토리를 컨테이너 내부로 복사 | COPY . /app |
ADD | COPY와 유사하지만, URL에서 직접 파일을 다운로드하거나 압축파일을 풀 수 있는 기능 포함 | ADD https://example.com/file.zip /app |
RUN | 컨테이너 내에서 실행할 명령어 정의 | RUN apt-get update && apt-get install -y curl |
ENV | 환경 변수 설정 | ENV JAVA_HOME /usr/lib/jvm/java-17-openjdk |
EXPOSE | 컨테이너에서 외부로 노출할 포트 지정 | EXPOSE 8080 |
CMD | 컨테이너 시작 시 기본으로 실행할 명령어 | CMD ["java", "-jar", "app.jar"] |
ENTRYPOINT | 컨테이너 시작 시 실행할 명령어 설정 | ENTRYPOINT ["java", "-jar", "app.jar"] |
ARG | Dockerfile 빌드 시 넘겨줄 수 있는 변수 | ARG JAR_FILE=target/app.jar |
VOLUME | 컨테이너와 호스트 간의 공유 디렉토리 설정 | VOLUME /app/data |
🔽 Dockerfile 빌드
docker build 명령은 Docker 이미지를 빌드하기 위해 사용되는 명령어이다. 이 명령어를 통해 Dockerfile에 정의된 지시사항을 순차적으로 수행하여 이미지를 구성하고 빌드할 수 있다. 빌드 과정 중 Dockerfile에 정의된 단계들이 순차적으로 실행되며, 최종적으로 Docker 이미지가 생성된다.
docker build [옵션] [Dockerfile 경로]
- 옵션
- -t, --tag: 빌드된 이미지에 태그 지정, "이미지 이름:태그" 형식으로 사용하며, 생략 시 기본으로 latest 태그가 설정
- -f, --file: 사용할 Dockerfile의 경로를 지정, 기본값은 ./Dockerfile
- -q, --quiet: 빌드 진행 상황 메시지를 출력하지 않음
- --build-arg: Dockerfile 내의 ARG 지시문에 전달할 빌드 인자를 지정
▶ 도커 구성 요소: 2. 도커 이미지 (Docker Image)
Docker 이미지는 애플리케이션과 해당 애플리케이션을 실행하는 데 필요한 모든 것을 포함한 불변의 파일 시스템 스냅샷이다. 이 이미지에는 코드, 런타임, 라이브러리, 환경 변수, 설정 파일 등이 포함되어 있으며, 이를 기반으로 도커 컨테이너가 생성된다.
🔽 특징
- 불변성: 도커 이미지는 변경되지 않으며, 이미지를 수정하려면 새로운 이미지로 빌드해야 한다.
- 레이어 구성: 도커 이미지는 여러 개의 읽기 전용 레이어로 구성된다. 각 레이어는 추가된 파일이나 변경사항을 나타내며, 도커는 이러한 레이어들을 합쳐 하나의 파일 시스템으로 사용한다. 도커는 DockerHub에 이미지 다운로드 또는 업로드 시 변경된 레이어만 전송하므로 효율적으로 이미지를 관리할 수 있다.
- 이미지 관리 및 배포: 도커 이미지는 DockerHub와 같은 서비스에서 버전 관리 및 배포(push & pull)가 가능하다.
- Dockerfile 사용: 도커 이미지는 Dockerfile이라는 파일을 사용해 생성된다.
- 컨테이너 생성의 기반: 도커 이미지를 기반으로 도커 컨테이너가 생성된다. 컨테이너는 이미지의 가상화된 실행 인스턴스이다.
▶ 도커 구성 요소: 3. 도커 컨테이너 (Docker Container)
Docker 컨테이너는 Docker 이미지를 기반으로 실행되는 가상화된 환경이다. 이미지에서 생성된 인스턴스로, 애플리케이션이 실제로 실행되는 공간이다.
🔽 특징
- 읽기/쓰기 가능: 컨테이너는 이미지와 달리 읽기와 쓰기가 가능하다. 이미지를 기반으로 읽기/쓰기 레이어를 추가하여 컨테이너가 생성되며, 변경된 내용은 이 레이어에 저장된다.
- 효율적인 자원 사용: 여러 개의 컨테이너가 동일한 이미지를 기반으로 생성되더라도, 각 컨테이너는 변경된 부분만을 읽기/쓰기 레이어에 기록하므로 최소한의 용량을 사용한다.
- 명시적 삭제 필요: 컨테이너가 종료되더라도 자동으로 삭제되지 않는다. 삭제하려면 명시적으로 삭제 명령을 실행해야 하며, 삭제 시 컨테이너에서 생성된 파일도 함께 제거된다.
- 독립된 실행 환경: 하나의 서버에 여러 개의 컨테이너를 실행할 수 있으며, 각 컨테이너는 서로 완전히 독립된 환경에서 실행되기 때문에 다른 컨테이너나 호스트에 영향을 주지 않는다.
- 호스트 자원 공유: 컨테이너는 호스트 운영체제의 커널과 자원을 공유한다. 따라서 가상 머신보다 가벼운 성능을 제공한다.
🔽 Docker Container 실행
docker run 명령어는 도커 컨테이너를 실행하는 명령어이다.
docker run [옵션] 이미지 [인자]
- 옵션
- -d: 백그라운드에서 실행
- -p: 포트 바인딩
- --name: 컨테이너 이름 지정
- -e: 환경 변수 설정
- -v: 볼륨 마운트
- 이미지: 도커 이미지의 이름이다. 컨테이너를 생성할 이미지 이름을 명시한다. (ex: nginx, mysql:5.7 등)
- 인자: 실행될 명령어나 인자를 지정한다. (ex: /bin/bash, npm start 등)
✅ 도커 포트 바인딩
도커 컨테이너는 기본적으로 외부 네트워크와 격리되어 있어 외부에서 직접 접근할 수 없다. 도커 포트 바인딩은 컨테이너 내부에서 실행되는 서비스나 애플리케이션을 외부에서 접근할 수 있도록 포트를 연결하는 과정이다.
🔽 명령어 예시
포트를 바인딩하려면 docker run 명령어에서 -p 또는 --publish 옵션을 사용한다.
docker run -d -p 8080:80 my-web-app
- 이 예시는 호스트의 8080 포트를 컨테이너 내부의 80 포트에 바인딩한다. 따라서 localhost:8080으로 접근하면 컨테이너 내부의 80 포트에서 제공하는 웹 서비스에 연결된다.
✅ 도커 컴포즈
Docker Compose는 여러 개의 컨테이너를 정의하고, 이들을 한 번에 관리할 수 있는 도구이다. 보통 하나의 애플리케이션은 여러 서비스(예: 웹 서버, 데이터베이스 등)로 구성되며, 각각의 서비스는 별도의 도커 컨테이너로 실행된다. 도커 컴포즈를 사용하면 이러한 여러 컨테이너를 한 번에 설정하고 관리할 수 있다.
▶ 특징
- 멀티 컨테이너 설정 관리: 복잡한 애플리케이션 환경을 코드로 정의하여 여러 컨테이너를 손쉽게 시작하고 종료할 수 있다.
- YAML 파일 사용: docker-compose.yml 파일을 사용하여 다양한 컨테이너 설정(서비스, 네트워크, 볼륨 등)을 정의한다.
- 간편한 명령어: 단일 명령어로 모든 서비스들을 일괄적으로 실행(docker-compose up)하거나 종료(docker-compose down)할 수 있다.
▶ docker-compose.yml 속성
속성 | 설명 | 예시 |
version | docker-compose.yml 파일의 버전을 정의 | version: '3.8' |
services | 여러 컨테이너를 정의하는 부분 | services: web: image: nginx app: build: . |
build | 이미지를 빌드할 디렉토리를 지정 | build: . |
image | 서비스에 사용할 도커 이미지를 정의 | image: my_image:latest |
container_name | 컨테이너의 이름을 설정 | container_name: my_app_container |
ports | 호스트와 컨테이너 간의 포트 매핑을 정의 | ports: - "8080:80" |
volumes | 호스트와 컨테이너 간의 파일 시스템을 공유하는 설정 | volumes: - ./data:/var/lib/data |
environment | 컨테이너 실행 시 환경 변수를 설정 | environment: - JAVA_OPTS=-Xmx512m |
depends_on | 특정 서비스가 다른 서비스보다 먼저 실행되도록 순서를 지정 | depends_on: - db |
networks | 서비스를 연결하는 네트워크를 정의 | networks: - my_network |
command | 컨테이너가 시작될 때 실행할 명령어를 지정 | command: ["npm", "start"] |
restart | 컨테이너가 종료되었을 때 재시작할 정책을 설정 | restart: always |
▶ 명령어
1. 컨테이너 실행
# 컨테이너 실행
docker-compose up
# 컨테이너를 백그라운드 모드에서 실행
docker-compose up -d
# 기존 컨테이너를 삭제하고 새로 생성하여 실행
docker-compose up --force-recreate
# 이미지를 다시 빌드한 후 컨테이너 실행
docker-compose up --build
2. 컨테이너 종료
# 컨테이너 종료
docker-compose down
# 컨테이너 일시 중단
docker-compose stop
✅ 도커의 워크 플로우
1. Dockerfile 작성: 애플리케이션 실행 환경을 정의하는 Dockerfile을 작성한다.
# 베이스 이미지로 OpenJDK 사용
FROM openjdk:17-jdk-alpine
# 컨테이너 내의 작업 디렉토리 설정
WORKDIR /app
# 호스트의 JAR 파일을 컨테이너로 복사
COPY target/app.jar /app/app.jar
# 환경 변수 설정 (필요시)
ENV JAVA_OPTS=""
# 컨테이너가 실행될 때 JAR 파일을 실행하도록 설정
ENTRYPOINT ["java", "-jar", "app.jar"]
2. 이미지 빌드: Dockerfile을 사용하여 도커 이미지를 빌드한다.
docker build -t my_image .
3. 컨테이너 실행: 도커 이미지를 기반으로 컨테이너를 실행하여 애플리케이션을 구동한다.
docker run -p 8080:80 my_image
4. docker-compose.yml 파일 작성: 여러 컨테이너를 쉽게 관리하고 동시에 실행하기 위해 docker-compose.yml 파일을 작성한다.
version: '3.8' # docker-compose 파일의 버전 지정
services:
app: # 서비스 이름
image: my_image # 빌드된 도커 이미지 이름
build:
context: . # Dockerfile의 위치
dockerfile: Dockerfile # 빌드 시 사용할 Dockerfile 지정 (기본값은 Dockerfile)
ports:
- "8080:80" # 호스트의 8080 포트를 컨테이너의 80 포트에 연결
environment:
- JAVA_OPTS=-Xms512m -Xmx1024m # 컨테이너 실행 시 사용할 환경 변수
volumes:
- ./logs:/app/logs # 호스트의 logs 디렉토리를 컨테이너의 /app/logs에 마운트
# 필요한 경우 다른 서비스 추가
database:
image: postgres:14-alpine # PostgreSQL 데이터베이스 이미지 사용
environment:
POSTGRES_USER: user # 데이터베이스 사용자 이름
POSTGRES_PASSWORD: password # 데이터베이스 비밀번호
POSTGRES_DB: my_database # 데이터베이스 이름
ports:
- "5432:5432" # 호스트의 5432 포트를 컨테이너의 5432 포트에 연결
volumes:
- pgdata:/var/lib/postgresql/data # 데이터 유지용 볼륨
volumes:
pgdata: # 볼륨 선언 (데이터 유지)
5. 도커 컴포즈 활용: Compose를 통해 실행한다.
docker-compose up
✅ 도커 이미지 도커 허브에 업로드
- 도커 허브에 로그인: 도커 허브(https://hub.docker.com)에 로그인한다.
- 도커 허브에서 레포지토리 생성:
- 도커 허브에 로그인한 후, 오른쪽 상단의 "Create Repository" 버튼을 클릭한다.
- 레포지토리 이름과 설정(public/private 등)을 지정하고 "Create" 버튼을 눌러 레포지토리를 생성한다.
- 도커 CLI에 로그인: 도커 CLI에서 도커 허브에 로그인한다.
docker login
- 도커 이미지 푸시: 도커 허브에 이미지를 업로드한다. (버전명 존재 시 버전명까지 필수)
docker push 도커허브계정명/도커레포지토리:태그명