본문 바로가기
DevOps

[Docker] Docker, Docker-Compose 개념

by 감자b 2024. 12. 23.

Docker는 컨테이너 기반의 오픈소스 가상화 플랫폼으로, 애플리케이션을 경량의 독립된 환경에서 실행할 수 있도록 해준다.

컨테이너는 운영체제(OS) 커널을 공유하면서도 애플리케이션과 그 실행에 필요한 모든 종속성을 포함하는 격리된 공간을 제공하여, 개발 환경과 운영 환경 간의 일관성을 보장한다. 이를 통해 소프트웨어의 배포, 관리, 확장을 용이하게 하고, 시스템 자원을 효율적으로 활용할 수 있다. 또한, 컨테이너는 가상 머신(VM)과 달리 전체 OS를 포함하지 않고 필요한 라이브러리 및 실행 파일만 패키징하여 가볍고 빠른 실행이 가능하다. Docker는 이러한 컨테이너 기술을 손쉽게 활용할 수 있도록 제공하는 도구로, 개발자가 더 빠르고 효율적으로 애플리케이션을 빌드, 테스트 및 배포할 수 있도록 돕는다.

개발 환경 변화

 

1. 전통적 개발 환경 방식 : 오래 전에 쓰이던 방식으로 컴퓨터 한 대에 하나의 OS를 설치하고 여러 가지 프로그램을 동작시키는 방식

→ 이는 특정 프로그램이 성능을 독점할 경우 다른 프로그램 성능이 저하될 수 있다.

 

2. 가상 머신 환경 : 하이퍼바이저라는 다수의 게스트 OS를 구동할 수 있게 하는 소프트웨어를 두어 하나의 호스트 OS에서 여러 가상 머신을 동작시키는 방식이다.

→ 가상 머신은 독립적으로 동작하기 때문에 1번 방식과는 다르게 각 프로그램이 서로 영향을 끼치지 않으며, 각 가상 머신의 성능과 개수를 조절하여 유연한 처리와 높은 격리 수준 설정이 가능하다.

하지만 가상 머신은 컴퓨터이고, 운영체제를 가상화했기에 무겁다.

 

3. 컨테이너 환경 : VM 환경과 비슷하게 도커 엔진과 같은 Container Runtime 위에서 실행되지만, VM과 달리 호스트 OS의 커널을 공유하면서도 격리된 환경을 제공할 수 있다.

→ 이는 리눅스 커널의 네임스페이스 가상화를 활용하여, 각 컨테이너가 프로세스 ID, 네트워크, 파일 시스템, UTS 등 다양한 네임스페이스를 따로 가짐으로써 독립적인 환경을 제공하는 원리다. (프로세스 수준의 격리)

따라서 별도의 게스트 OS가 필요 없으므로 VM보다 가볍고 빠르며, 독립적인 환경 제공하지만 호스트 OS의 커널을 공유하기 때문에 다른 컨테이너가 OS에 문제를 일으킨다면 다른 컨테이너가 영향을 받을 수 있다.

 

여기서 Windows의 경우 Windows Subsystem for Linux (WSL)로 리눅스를 직접 실행할 수 있기 때문에, 리눅스 기반 컨테이너와 , 윈도우 기반 컨테이너를 실행할 수 있다.


Docker에서 사용하는 용어

  • 이미지 : 코드, 종속성, 라이브러리 및 설정과 같은 응용프로그램을 실행하는데 필요한 모든 것을 포함하는 패키지로 불변임
    • Dockerfile을 기반으로 생성되며, docker build 명령어를 사용하여 빌드 가능
  • 컨테이너 : 도커 이미지를 독립된 공간에서 실행할 수 있게 해주는 기술 (도커 이미지의 실행 가능한 인스턴스)
  • 즉, 이미지는 컨테이너를 만들기 위한 템플릿, 컨테이너는 실행 중인 이미지를 뜻함.
  • Dockerfile : 도커 이미지를 구성하기 위해 있어야 할 패키지, 의존성, 소스코드 등을 하나의 file로 기록하여 이미지화 시킬 명령 파일
  • Docker Hub : 도커 이미지의 저장소로, 사용자들이 이미지를 공유하고 다운로드할 수 있는 클라우드 기반 플랫폼
  • 볼륨 (Volume) : 컨테이너가 데이터를 저장할 수 있는 경로

Docker의 컨테이너 실행 과정 (Dockerfile → build → Docker Image → run → Docker Container)

 

1. Dockerfile로 컨테이너 환경을 정의

2. 해당 파일을 build하여 도커 이미지 생성

3. 생성된 Docker Image는 실행에 필요한 모든 정보를 가지고 있음

4. 이미지를 기반으로 컨테이너 실행

5. 실제 애플리케이션이 동작하는 Docker Container 환경이 실행

 

이러한 과정을 통해  새로운 서버가 추가되더라도 의존성 파일을 컴파일하거나 추가 설치할 필요 없이, 동일한 환경에서 애플리케이션을 손쉽게 실행할 수 있다.

아래에서 1~5번 과정에 대해 상세히 알아보도록 하겠다.


Dockerfile

Docker Image 생성 방법을 지정하는 파일로 한 줄에 하나씩 명령어 인자 형태로 작성한다.

 

명령어의 종류

  • FROM → 새로운 이미지를 생성할 때 기반으로 사용할 Base 이미지를 이정 (이미지 이름:태그)
  • ARG → 이미지 빌드 시점에서 사용할 변수 지정
  • COPY → 호스트에 있는 파일이나 디렉토리를 Docker 이미지의 파일 시스템으로 복사
  • ENV → 컨테이너에서 사용할 환경 변수를 지정
  • ENTRYPOINT → 컨테이너가 실행되었을 때 항상 실행되어야 하는 커맨드를 지정
  • RUN → 컨테이너를 실행 하기 전 수행할 명령
  • CMD → 컨테이너 시작 시 실행되는 명령어

기본적으로 사용할 이미지는 Docker Hub에서 검색이 가능하다.

 

Docker Hub Container Image Library | App Containerization

Increase your reach and adoption on Docker Hub With a Docker Verified Publisher subscription, you'll increase trust, boost discoverability, get exclusive data insights, and much more.

hub.docker.com

 

도커 파일 예시)

# 1. Python 공식 이미지를 사용
FROM python:3.9

# 2. 로컬 파일을 /app 디렉토리로 복사
COPY . /app

# 3. /app 디렉토리로 이동하여 Python 애플리케이션 실행
CMD ["python", "/app/app.py"]

 

Build

빌드 예시)

-t 옵션은 새로 만드는 이미지에 이름을 부여하는 옵션이며, 주로 이미지이름:버전번호 형태나, 가장 최근 버전의 경우 이미지이름:latest 으로 짓는다.

docker build -t my-python-app:1 .

 

가지고 있는 이미지는 docker images를 통해 확인이 가능하다.

 

run

실행 예시)

-d : detach의 약자로 컨테이너를 백그라운드에서 실행

-p : 호스트의 8080 포트로 들어오는 트래픽을 컨테이너의 80 포트로 매핑한다는 의미

이 때 이미지가 존재하지 않다면 Docker Hub에서 자동으로 다운로드하고 실행한다. (단 이미지명을 Docker Hub에 존재하는 이름과 일치시켜야 함)

docker -d -p 8080:80 run my-python-app:1

 

docker ps -a 명령을 통해 실행 중인 컨테이너 목록을 확인할 수 있다.

그리고 여기서 CONTAINER-ID를 확인할 수 있는데, docker stop <CONTAINER-ID> 명령으로 해당 컨테이너를 정지하고, docker rm <CONTAINER-ID> 명령을 통해 지울 수 있다.


Docker-Compose

여러 개의 컨테이너로 구성된 애플리케이션을 한 번에 정의하고 실행할 수 있도록 도와주는 도구

예를 들어 App, DB, Nginx 등을 각 컨테이너로 관리한다고 했을 때 docker-compose.yml 파일을 사용하여 해당 컨테이너들을 정의하고, docker-compose  up 명령어 한 번으로 설정된 모든 컨테이너를 실행하여 여러 개의 도커 컨테이너로부터 이루어진 서비스를 구축 및 네트워크 연결, 실행 순서, 라이프 사이클을 자동으로 관리할 수 있도록 한다.

 

docker-compose 명령어

  • -f : 어떤 docker-compose 파일을 실행시킬 것인가
  • up : docker-compose.yml에 정의된 모든 서비스를 시작하고 연결
  • down : Docker Compose에서 정의된 모든 서비스를 중지하고, 해당 서비스들이 사용하던 네트워크, 볼륨, 컨테이너를 모두 제거하는 역할
  • -d : 컨테이너를 백그라운드에서 실행
docker-compose -f docker-compose-local.yml up -d
 docker-compose -f docker-compose-local.yml down

 

docker-compose.yml 예시)

version: '3.8'                     # 도커 컴포즈 버전

services:                          # 하위에 실행하려는 컨테이너 정의
  app:                             # 서비스명
    build:                         # DockerFile이 있는 위치 지정
      context: ./app
      dockerfile: Dockerfile
    ports:                         # 접근 포트 설정(컨테이너 외부:내부, docker run -p와 같음)
      - "8080:8080"
    environment:                   # 환경 변수
      - SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/mydatabase
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=root
    depends_on:                    # 특정 컨테이너 대한 의존관계 설정
      - db                         # db 서비스가 실행 된 후 app 서비스가 실행

  db:
    image: "mysql:5.7"             # 컨테이너 생성 시 사용할 도커 이미지 지정
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=mydatabase
    volumes:                       # 호스트 디렉토리:컨테이너 디렉토리 매핑
      - db_data:/var/lib/mysql

  nginx:
    image: "nginx:latest"
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app

volumes:
  db_data: