도커 컨테이너
1. 개요
1. 개요
도커 컨테이너는 애플리케이션과 그 실행에 필요한 모든 요소(라이브러리, 시스템 도구, 코드, 런타임 등)를 하나의 패키지로 묶어, 어떤 컴퓨팅 환경에서도 일관되게 실행할 수 있도록 하는 경량화된 가상화 기술이다. 이 기술은 리눅스 커널의 cgroups와 네임스페이스 기능을 기반으로 하여, 운영 체제 수준의 가상화를 제공한다. 도커 컨테이너는 가상 머신과 달리 게스트 운영 체제를 포함하지 않아 훨씬 가볍고 빠르게 시작 및 중지할 수 있다.
도커 컨테이너의 핵심 가치는 개발부터 테스트, 운영에 이르는 소프트웨어 배포 라이프사이클 전반에 걸쳐 환경 불일치 문제를 해결하는 데 있다. "내 컴퓨터에서는 되는데요"라는 문제를 근본적으로 차단하여, 애플리케이션의 이식성과 확장성을 극대화한다. 이는 마이크로서비스 아키텍처, 지속적 통합/지속적 배포 파이프라인, 클라우드 네이티브 애플리케이션 개발의 핵심 인프라로 자리 잡았다.
도커는 도커 엔진이라는 클라이언트-서버 애플리케이션을 통해 관리된다. 사용자는 도커 클라이언트를 사용해 도커 데몬에 명령을 전달하고, 데몬은 컨테이너 이미지를 빌드, 실행, 관리하는 작업을 수행한다. 도커 허브와 같은 공개 레지스트리를 통해 수많은 공식 및 커뮤니티 이미지를 쉽게 공유하고 활용할 수 있다.
2. 기본 개념
2. 기본 개념
도커 컨테이너의 핵심은 이미지와 컨테이너의 관계, 그리고 이를 관리하는 도커 데몬과 도커 클라이언트의 구조, 그리고 이미지를 저장하고 공유하는 레지스트리라는 세 가지 기본 개념으로 구성된다.
이미지는 애플리케이션을 실행하는 데 필요한 모든 것을 포함한 읽기 전용 템플릿이다. 여기에는 런타임, 시스템 도구, 라이브러리, 애플리케이션 코드가 포함된다. 반면 컨테이너는 이 이미지를 기반으로 생성된 실행 가능한 인스턴스이다. 하나의 이미지로부터 여러 개의 컨테이너를 생성할 수 있으며, 각 컨테이너는 독립된 파일 시스템, 네트워크, 프로세스 공간을 가진다. 컨테이너 내에서 발생하는 변경 사항은 기본 이미지에 영향을 주지 않는다.
도커는 클라이언트-서버 아키텍처로 동작한다. 도커 데몬은 서버 역할을 하며, 이미지와 컨테이너를 실제로 빌드하고 실행하고 관리하는 백그라운드 서비스이다. 도커 클라이언트는 사용자가 터미널에 입력하는 docker run, docker build와 같은 명령어를 데몬에게 전달하는 인터페이스이다. 클라이언트와 데몬은 동일한 시스템에서 실행될 수도 있고, 원격 데몬과 통신하도록 구성될 수도 있다.
이미지를 저장하고 배포하기 위한 중앙 저장소가 레지스트리이다. 가장 대표적인 공개 레지스트리는 Docker Hub이다. 사용자는 레지스트리에서 공개된 이미지를 docker pull 명령어로 가져오거나(pull), 자신이 빌드한 이미지를 docker push 명령어로 업로드할 수 있다. 조직은 Docker Trusted Registry나 Amazon ECR, Google Container Registry와 같은 사설 레지스트리를 구축하여 내부 이미지를 관리할 수도 있다.
2.1. 이미지와 컨테이너
2.1. 이미지와 컨테이너
도커 이미지는 애플리케이션과 그 실행에 필요한 모든 요소를 포함하는 읽기 전용 템플릿이다. 이는 코드, 런타임, 시스템 도구, 시스템 라이브러리, 설정값 등을 계층적으로 패키징한 것이다. 이미지는 Dockerfile이라는 텍스트 파일에 정의된 일련의 지시어를 통해 빌드되며, 도커 허브와 같은 레지스트리에서 공유되고 배포된다.
도커 컨테이너는 도커 이미지의 실행 가능한 인스턴스이다. 이미지를 기반으로 생성되며, 격리된 사용자 공간에서 애플리케이션을 실행한다. 컨테이너는 이미지의 읽기 전용 계층 위에 쓰기 가능한 얇은 계층을 추가하여 생성된다. 이 구조 덕분에 동일한 이미지로부터 여러 개의 독립적인 컨테이너를 빠르게 생성하고 실행할 수 있다.
이미지와 컨테이너의 관계는 객체 지향 프로그래밍에서 '클래스'와 '인스턴스'의 관계에 비유된다. 이미지는 애플리케이션을 정의하는 청사진이고, 컨테이너는 그 청사진을 바탕으로 실제로 실행되는 실체이다. 컨테이너의 생명주기는 실행, 중지, 삭제, 재시작 등으로 관리되며, 컨테이너가 삭제되면 그 위의 쓰기 가능한 계층도 함께 사라진다.
개념 | 설명 | 특징 |
|---|---|---|
도커 이미지 | 애플리케이션 실행을 위한 모든 파일과 설정이 포함된 읽기 전용 템플릿 | 계층적 구조, 불변성, 재사용성, 레지스트리를 통한 공유 |
도커 컨테이너 | 이미지를 실행한 격리된 프로세스 인스턴스 | 경량성, 이식성, 일시성(stateless), 독립적인 실행 환경 |
2.2. 도커 데몬과 클라이언트
2.2. 도커 데몬과 클라이언트
도커는 클라이언트-서버 아키텍처를 기반으로 동작한다. 이 구조의 핵심 구성 요소는 도커 데몬과 도커 클라이언트이다.
도커 데몬(dockerd)은 호스트 시스템에서 백그라운드 서비스로 실행되며, 이미지 관리, 컨테이너 생성 및 실행, 네트워크와 볼륨 관리 등 모든 핵심 작업을 담당하는 서버 컴포넌트이다. 사용자는 직접 데몬과 상호작용하지 않고, 명령줄 인터페이스(CLI)인 도커 클라이언트(docker)를 통해 명령을 전달한다. 클라이언트는 사용자의 명령을 받아 REST API를 통해 데몬에게 전송하고, 데몬이 처리한 결과를 다시 사용자에게 반환한다.
도커 클라이언트와 데몬은 동일한 시스템에서 실행될 수도 있고, 원격 데몬과 통신하도록 구성될 수도 있다. 기본적으로 클라이언트는 유닉스 소켓(/var/run/docker.sock) 또는 윈도우의 네임드 파이프를 통해 로컬 데몬과 통신한다. 원격 접속을 위해서는 데몬이 TCP 포트를 열고 클라이언트가 해당 호스트를 가리키도록 DOCKER_HOST 환경 변수를 설정해야 한다.
구성 요소 | 역할 | 통신 방식 |
|---|---|---|
도커 데몬 ( | 이미지/컨테이너/네트워크의 생명주기 관리 | REST API 엔드포인트 제공 |
도커 클라이언트 ( | 사용자 명령 입력 및 결과 표시 | 소켓 또는 TCP를 통해 데몬의 API 호출 |
이 분리된 아키텍처는 자동화와 원격 관리를 용이하게 하며, 도커 컴포즈나 쿠버네티스와 같은 오케스트레이션 도구들이 도커 엔진과 통합될 수 있는 기반을 제공한다.
2.3. 레지스트리
2.3. 레지스트리
레지스트리는 도커 이미지를 저장하고 배포하는 서비스 또는 저장소이다. 가장 대표적인 공개 레지스트리는 Docker Hub이며, 도커 사용자는 기본적으로 이곳에서 공식 이미지나 커뮤니티가 제공하는 이미지를 검색하고 다운로드한다. 레지스트리는 깃허브와 유사하게 공개 저장소와 비공개 저장소를 제공하며, 조직이나 개인이 자신만의 이미지를 호스팅하고 공유하는 데 사용된다.
레지스트리는 클라이언트-서버 모델로 동작한다. 사용자가 docker pull 또는 docker run 명령을 실행하면 도커 데몬은 지정된 레지스트리(기본값은 Docker Hub)에 접속하여 해당 이미지를 찾고, 필요한 이미지 레이어를 다운로드한다. 반대로 docker push 명령을 사용하면 로컬에 빌드한 이미지를 레지스트리에 업로드하여 배포할 수 있다.
공개 서비스 외에도 Amazon ECR, Google Container Registry, Azure Container Registry 같은 클라우드 제공업체의 관리형 레지스트리나, Harbor, JFrog Artifactory와 같은 오픈소스 또는 상용 프라이빗 레지스트리 솔루션을 자체 인프라에 구축하여 사용할 수 있다. 프라이빗 레지스트리는 보안 요구사항이 높거나, 네트워크 대역폭을 절약해야 하거나, 독자적인 소프트웨어 공급망을 구성할 때 필수적이다.
레지스트리에서 이미지는 이름(리포지토리명)과 태그(태그)로 식별된다. 예를 들어 nginx:latest에서 nginx는 리포지토리 이름, latest는 태그를 의미한다. 태그는 일반적으로 버전이나 빌드 환경을 나타내는 데 사용되며, 특정 태그를 지정하지 않으면 기본적으로 latest 태그가 적용된다.
3. 주요 명령어
3. 주요 명령어
도커 명령어는 도커 CLI를 통해 실행되며, 크게 이미지 관리와 컨테이너 실행 및 관리로 구분된다.
이미지 관리 명령어
이미지를 다루는 기본적인 명령어는 다음과 같다.
명령어 | 설명 |
|---|---|
| |
| 로컬에 저장된 이미지 목록을 보여준다. |
| 지정한 이미지를 로컬에서 삭제한다. |
| 현재 디렉토리의 Dockerfile을 사용하여 새로운 이미지를 빌드한다. |
컨테이너 실행 및 관리 명령어
컨테이너의 생명주기를 관리하는 핵심 명령어는 아래와 같다.
명령어 | 설명 |
|---|---|
| 새 컨테이너를 생성하고 실행한다. 주요 옵션으로 |
| 실행 중인 컨테이너 목록을 보여준다. |
| 실행 중인 컨테이너를 정지시킨다. |
| 정지된 컨테이너를 다시 시작한다. |
| 정지된 컨테이너를 삭제한다. |
| 실행 중인 컨테이너 내부에서 명령어를 실행한다. |
|
이 명령어들을 조합하여 컨테이너를 풀, 실행, 모니터링, 정리하는 기본 작업 흐름을 구성한다. 예를 들어, docker run -d -p 80:80 --name webserver nginx 명령은 nginx 이미지를 백그라운드에서 실행하고 호스트의 80번 포트와 연결하며, 컨테이너 이름을 'webserver'로 지정한다. 이후 docker logs webserver로 상태를 확인하거나 docker stop webserver로 서비스를 중단할 수 있다.
3.1. 이미지 관리 명령어
3.1. 이미지 관리 명령어
도커 이미지는 컨테이너를 생성하기 위한 읽기 전용 템플릿이다. 이미지 관리는 도커 허브나 사설 레지스트리에서 이미지를 가져오고, 로컬 이미지 목록을 확인하며, 불필요한 이미지를 삭제하는 작업을 포함한다.
주요 이미지 관리 명령어는 다음과 같다.
명령어 | 설명 |
|---|---|
| 지정된 이미지를 레지스트리에서 로컬 시스템으로 다운로드한다. 태그를 생략하면 |
| 로컬에 저장된 모든 도커 이미지 목록을 보여준다. 이미지 ID, 저장소 이름, 태그, 생성 시기 및 크기 정보를 포함한다. |
| 지정된 로컬 이미지를 삭제한다. 해당 이미지를 사용하는 컨테이너가 존재하면 삭제에 실패한다. |
| 기존 이미지에 새로운 이름이나 태그를 부여한다. 주로 사설 레지스트리에 푸시하기 전에 사용한다. |
| |
| 지정된 경로의 Dockerfile을 사용하여 새로운 이미지를 빌드하고 태그를 지정한다. |
docker pull 명령은 원격 저장소에서 최신 버전의 이미지를 가져올 때 사용한다. docker images 명령은 현재 시스템에 어떤 이미지들이 캐시되어 있는지 확인하고 디스크 사용량을 파악하는 데 유용하다. 더 이상 사용하지 않는 이미지는 docker rmi 명령으로 삭제하여 디스크 공간을 확보할 수 있다. 여러 이미지를 한꺼번에 삭제하려면 docker rmi $(docker images -q)와 같은 명령어 조합을 사용하기도 한다[1].
3.2. 컨테이너 실행 및 관리 명령어
3.2. 컨테이너 실행 및 관리 명령어
컨테이너를 실행하는 가장 기본적인 명령어는 docker run이다. 이 명령어는 지정된 이미지로부터 새로운 컨테이너를 생성하고 시작한다. 주요 옵션으로는 백그라운드 실행을 위한 -d, 포트 매핑을 위한 -p, 컨테이너 이름 지정을 위한 --name, 환경 변수 설정을 위한 -e 등이 있다. 예를 들어, docker run -d -p 8080:80 --name myweb nginx는 nginx 이미지를 기반으로 'myweb'이라는 이름의 컨테이너를 백그라운드에서 실행하며, 호스트의 8080번 포트를 컨테이너의 80번 포트에 연결한다.
실행 중인 컨테이너를 관리하기 위한 명령어는 다음과 같다.
명령어 | 주요 옵션 | 설명 |
|---|---|---|
|
| 실행 중인 컨테이너 목록을 표시한다. |
| 컨테이너 ID 또는 이름 | 실행 중인 컨테이너를 정상적으로 중지한다. |
| 컨테이너 ID 또는 이름 | 중지된 컨테이너를 다시 시작한다. |
| 컨테이너 ID 또는 이름 | 컨테이너를 재시작한다. |
|
| 컨테이너를 삭제한다. |
|
| 컨테이너의 로그를 확인한다. |
|
| 실행 중인 컨테이너 내부에서 명령어를 실행한다. |
docker exec -it myweb /bin/bash와 같은 명령어는 'myweb' 컨테이너 내부에 bash 셸을 열어 대화형으로 접근할 수 있게 한다. 이는 컨테이너 내부 상태를 점검하거나 디버깅할 때 유용하다. 한편, docker rm $(docker ps -aq) 명령어는 모든 컨테이너를 삭제하는 방법으로, 시스템 정리 시 사용된다. 컨테이너의 자원 사용량을 확인하려면 docker stats 명령어를 사용한다.
4. Dockerfile 작성
4. Dockerfile 작성
Dockerfile은 도커 이미지를 빌드하기 위한 텍스트 파일이다. 이 파일에는 베이스 이미지부터 시작하여 애플리케이션을 실행 가능한 상태로 만들기 위해 필요한 모든 명령어와 설정이 순서대로 기록된다. docker build 명령어는 이 파일을 읽어 각 지시어를 순차적으로 실행하며 새로운 이미지 레이어를 생성한다. Dockerfile을 사용하면 애플리케이션의 실행 환경을 코드로 정의하고, 버전 관리하며, 재현 가능한 빌드 프로세스를 확립할 수 있다.
주요 지시어는 다음과 같다.
* FROM: 빌드의 기반이 될 베이스 이미지를 지정한다. 모든 Dockerfile은 이 지시어로 시작해야 한다.
* RUN: 이미지 빌드 과정에서 컨테이너 내부에서 실행할 쉘 명령어를 정의한다. 주로 패키지 설치나 파일 설정에 사용된다.
* COPY와 ADD: 호스트 머신의 파일이나 디렉터리를 이미지 내부로 복사한다. ADD는 압축 파일 자동 해제나 원격 URL 지원 등 추가 기능을 갖는다.
* WORKDIR: 이후의 RUN, CMD, ENTRYPOINT, COPY, ADD 지시어가 실행될 작업 디렉터리를 설정한다.
* ENV: 컨테이너 내에서 사용될 환경 변수를 설정한다.
* EXPOSE: 컨테이너가 런타임에 특정 네트워크 포트를 사용할 것임을 선언한다.
* CMD와 ENTRYPOINT: 컨테이너가 시작될 때 실행될 기본 명령어를 정의한다. ENTRYPOINT는 고정된 실행 파일을, CMD는 ENTRYPOINT에 전달될 기본 인자를 지정하는 데 주로 사용된다.
이미지 빌드 최적화를 위해 몇 가지 원칙을 준수하는 것이 좋다. 먼저, .dockerignore 파일을 사용하여 불필요한 파일이 이미지에 복사되는 것을 방지해야 한다. 둘째, Dockerfile의 각 지시어는 캐시된 레이어를 생성하므로, 변경 빈도가 낮은 지시어(예: FROM, RUN으로 의존성 설치)를 상단에, 변경 빈도가 높은 지시어(예: COPY로 애플리케이션 소스 복사)를 하단에 배치하여 빌드 캐시를 효율적으로 활용한다. 또한, RUN 명령어를 여러 줄로 나눌 때는 &&로 연결하고, 불필요한 파일을 정리하는 명령을 같은 레이어 내에서 수행하여 최종 이미지 크기를 줄인다. 적절한 베이스 이미지(예: Alpine Linux)를 선택하는 것도 이미지 크기 최소화에 기여한다.
4.1. 기본 지시어
4.1. 기본 지시어
Dockerfile은 도커 이미지를 빌드하기 위한 텍스트 파일로, 일련의 지시어(Directive)로 구성된다. 각 지시어는 이미지 생성 과정에서 특정 단계를 수행하도록 지시한다. 가장 기본적이고 필수적인 지시어는 다음과 같다.
FROM 지시어는 빌드할 새 이미지의 기반이 될 베이스 이미지를 지정한다. 모든 유효한 Dockerfile은 반드시 FROM 지시어로 시작해야 한다. 예를 들어, FROM ubuntu:22.04는 우분투 22.04 버전의 공식 이미지를 기반으로 빌드를 시작한다는 의미이다. FROM scratch는 완전히 빈 베이스 이미지를 사용한다는 뜻으로, 최소한의 실행 파일만 필요한 이미지를 만들 때 사용된다.
RUN, COPY, ADD, WORKDIR, CMD, ENTRYPOINT 지시어는 이미지의 내용과 동작을 정의한다. RUN 지시어는 현재 이미지 위에 새 레이어를 생성하며, 그 안에서 지정된 명령어(예: 패키지 설치, 파일 생성)를 실행한다. COPY와 ADD는 호스트 머신의 파일이나 디렉터리를 이미지 내부로 복사하지만, ADD는 추가로 압축 파일 자동 해제나 원격 URL에서의 다운로드 기능을 제공한다. WORKDIR는 이후의 RUN, CMD, ENTRYPOINT, COPY, ADD 지시어가 실행될 작업 디렉터리를 설정한다. CMD는 컨테이너가 시작될 때 실행될 기본 명령어나 인자를 제공하며, ENTRYPOINT는 컨테이너를 실행 파일처럼 구성할 때 사용된다.
지시어 | 주요 용도 | 예시 |
|---|---|---|
| 베이스 이미지 지정 |
|
| 명령어 실행 (패키지 설치 등) |
|
| 로컬 파일/디렉터리 복사 |
|
| 파일 복사 (추가 기능 포함) |
|
| 작업 디렉터리 설정 |
|
| 컨테이너 실행 시 기본 명령 |
|
| 컨테이너의 주요 실행 파일 설정 |
|
이 외에도 ENV는 환경 변수를 설정하고, EXPOSE는 컨테이너가 런타임에 특정 네트워크 포트를 사용할 것임을 문서화한다. ARG는 빌드 시에만 사용되는 변수를 정의하며, LABEL은 이미지에 메타데이터를 추가한다. 이러한 지시어들을 조합하여 애플리케이션에 필요한 모든 의존성과 설정이 포함된 재현 가능한 이미지를 정의한다.
4.2. 이미지 빌드 및 최적화
4.2. 이미지 빌드 및 최적화
Dockerfile을 작성한 후에는 docker build 명령어를 사용하여 도커 이미지를 생성한다. 빌드 명령어는 docker build -t <이미지명:태그> <빌드 컨텍스트 경로> 형식으로 실행한다. 빌드 컨텍스트는 Dockerfile과 이미지에 포함될 파일들이 위치한 디렉토리를 의미하며, 불필요한 파일이 포함되지 않도록 .dockerignore 파일을 사용하여 제외할 파일을 명시하는 것이 좋다.
이미지 빌드 과정을 최적화하여 빌드 시간을 단축하고 최종 이미지 크기를 줄이는 것은 중요하다. 주요 최적화 기법은 다음과 같다.
계층 캐싱 활용: Dockerfile의 각 지시어는 새로운 이미지 레이어를 생성한다. 도커는 빌드 시 이전에 빌드된 레이어 캐시를 재사용한다. 변경이 빈번한 지시어(예: 애플리케이션 소스 코드 복사)는 Dockerfile 하단에, 변경이 적은 지시어(예: 패키지 설치)는 상단에 배치하여 캐시 적중률을 높여야 한다.
멀티-스테이지 빌드 사용: 하나의 Dockerfile 내에 여러 개의
FROM지시어를 사용하여 빌드 스테이지를 분리한다. 컴파일이나 패키징과 같은 빌드 도구는 첫 번째 스테이지에서 사용하고, 최종 실행에 필요한 산출물만 최종 스테이지로 복사한다. 이를 통해 빌드 의존성은 포함되지 않고 실행 파일만 포함된 경량 이미지를 생성할 수 있다.불필요한 파일 제거: 패키지 관리자 캐시나 임시 파일은 같은 레이어 내에서 설치 명령어와 함께 삭제해야 한다. 예를 들어,
apt-get install후apt-get clean을 실행하거나,&&연산자를 사용하여 여러 명령을 하나의 RUN 지시어로 결합하여 불필요한 중간 레이어 생성을 방지한다.
최적화 기법 | 목적 | 예시 |
|---|---|---|
계층 캐싱 전략 | 빌드 시간 단축 |
|
멀티-스테이지 빌드 | 최종 이미지 크기 축소 | 첫 번째 스테이지에서 Go 코드를 컴파일하고, 두 번째 스테이지에서 컴파일된 바이너리만 복사 |
레이어 통합 | 레이어 수 및 크기 최소화 |
|
이러한 최적화를 적용하면 더 빠르게 빌드되고, 보안상 취약점이 줄어들며, 저장 및 배포 효율성이 높아진다.
5. 네트워킹
5. 네트워킹
도커 컨테이너는 격리된 환경에서 실행되지만, 외부와의 통신이나 컨테이너 간 통신을 위해 네트워크 기능을 제공합니다. 도커는 다양한 네트워크 드라이버를 지원하여 사용 사례에 맞는 네트워크 구성을 가능하게 합니다. 컨테이너는 이러한 네트워크에 연결되어 가상의 네트워크 인터페이스를 할당받고, 내부 IP 주소를 가지게 됩니다.
주요 네트워크 드라이버로는 bridge, host, none, overlay 등이 있습니다. 기본적으로 생성되는 bridge 네트워크는 컨테이너가 개별 IP를 가지며, 호스트 내부에서 서로 통신할 수 있게 합니다. host 드라이버는 컨테이너가 호스트의 네트워크 스택을 직접 사용하여 성능 오버헤드를 최소화합니다. overlay 네트워크는 도커 스웜이나 쿠버네티스와 같은 클러스터 환경에서 여러 호스트에 걸친 컨테이너 간 통신을 가능하게 합니다. none 드라이버는 네트워크를 완전히 비활성화합니다.
드라이버 | 설명 | 주요 사용 사례 |
|---|---|---|
| 도커가 기본으로 생성하는 가상 네트워크. 컨테이너에 내부 IP를 할당. | 단일 호스트 내에서 독립된 컨테이너 실행 |
| 컨테이너가 호스트의 네트워크 네임스페이스를 직접 사용. | 네트워크 성능이 극도로 중요한 경우 |
| 여러 도커 호스트를 연결하는 가상 네트워크. | 분산 애플리케이션, 클러스터 환경 |
| 네트워크 인터페이스를 컨테이너에 할당하지 않음. | 완전한 네트워크 격리가 필요한 경우 |
컨테이너 내부에서 실행 중인 애플리케이션(예: 웹 서버)을 외부에서 접근하려면 포트 매핑이 필요합니다. -p 또는 --publish 옵션을 사용하여 호스트의 특정 포트를 컨테이너의 포트에 바인딩합니다. 예를 들어, docker run -p 8080:80 nginx 명령은 호스트의 8080 포트로 들어오는 트래픽을 컨테이너 내부의 80 포트로 전달합니다. 이를 통해 호스트의 IP 주소와 매핑된 포트를 통해 컨테이너 서비스에 접근할 수 있습니다.
5.1. 네트워크 드라이버 종류
5.1. 네트워크 드라이버 종류
도커는 컨테이너 간 또는 컨테이너와 외부 네트워크 간의 통신을 관리하기 위해 다양한 네트워크 드라이버를 제공한다. 각 드라이버는 특정 사용 사례에 맞는 네트워크 격리 및 연결 방식을 구현한다. 사용자는 애플리케이션의 요구사항에 따라 적절한 네트워크 드라이버를 선택하여 컨테이너를 실행할 수 있다.
주요 네트워크 드라이버의 종류와 특징은 다음과 같다.
드라이버 | 설명 | 주요 사용 사례 |
|---|---|---|
| 도커가 설치될 때 자동으로 생성되는 기본 네트워크 드라이버이다. 동일한 | 단일 도커 호스트 내에서 독립적으로 실행되는 컨테이너들 간의 통신에 적합하다. |
| 컨테이너가 호스트 머신의 네트워크 스택을 완전히 공유한다. 컨테이너의 네트워크 격리가 제거되며, 호스트의 IP와 포트를 직접 사용한다. | 네트워크 성능이 극도로 중요하고, 컨테이너 수준의 네트워크 격리가 필요 없는 경우에 사용한다. |
| 컨테이너에 어떠한 네트워크 인터페이스도 할당하지 않는다. 컨테이너는 루프백( | 보안 테스트나 오프라인 데이터 처리 등 네트워크 접근이 전혀 필요하지 않은 특수한 경우에 사용한다. |
| 여러 도커 데몬 호스트(예: 도커 스웜 또는 쿠버네티스 클러스터)에 걸쳐 있는 컨테이너들이 서로 통신할 수 있게 해주는 네트워크를 생성한다. | 분산된 서비스로 구성된 클러스터 환경에서 컨테이너 간 통신에 필수적이다. |
| 컨테이너에 물리적 네트워크의 MAC 주소를 부여하여, 컨테이너가 물리 네트워크상의 실제 장치처럼 보이게 한다. | 컨테이너가 기존 VLAN을 인식해야 하거나 특정 MAC 주소를 요구하는 레거시 애플리케이션을 마이그레이션할 때 유용하다. |
이 외에도 서드파티 플러그인을 통해 사용자 정의 네트워크 드라이버를 구현하고 사용할 수 있다. 네트워크 드라이버는 docker network create --driver <드라이버명> 명령어로 생성하며, docker run --network <네트워크명> 옵션으로 컨테이너를 특정 네트워크에 연결한다.
5.2. 포트 매핑
5.2. 포트 매핑
포트 매핑은 호스트 머신의 특정 포트를 도커 컨테이너 내부의 포트로 연결하는 기능이다. 컨테이너는 격리된 네트워크 환경에서 실행되므로, 외부에서 컨테이너 내부에서 실행 중인 애플리케이션(예: 웹 서버)에 접근하려면 이 매핑이 필요하다. docker run 명령어에서 -p 또는 -P 옵션을 사용하여 설정한다.
-p 옵션을 사용하면 호스트 포트와 컨테이너 포트를 명시적으로 지정할 수 있다. 기본 형식은 -p 호스트_포트:컨테이너_포트이다. 예를 들어, -p 8080:80은 호스트의 8080 포트로 들어오는 트래픽을 컨테이너의 80 포트로 전달한다. 특정 호스트 IP를 지정하거나, UDP 프로토콜을 명시하는 등 더 세부적인 설정도 가능하다[2]. 반면 -P(대문자) 옵션을 사용하면 Dockerfile 내 EXPOSE 지시어로 정의된 모든 컨테이너 포트를 호스트의 임의의 사용 가능한 포트에 자동으로 매핑한다. 이때 실제 매핑된 포트는 docker ps 명령으로 확인할 수 있다.
포트 매핑은 개발, 테스트, 배포 단계에서 매우 유용하다. 여러 개의 동일한 애플리케이션 컨테이너를 다른 호스트 포트에 매핑하여 동시에 실행하거나, 호스트의 잘 알려진 포트(80, 443)를 컨테이너에 연결하여 서비스를 제공할 수 있다. 그러나 동일한 호스트 포트에 두 개 이상의 컨테이너를 매핑하려고 하면 충돌이 발생하므로 주의가 필요하다.
옵션 | 설명 | 사용 예 |
|---|---|---|
| 명시적 포트 매핑 |
|
|
|
|
| 컨테이너 포트만 지정, 호스트 포트는 임의 할당 |
|
6. 볼륨과 데이터 관리
6. 볼륨과 데이터 관리
도커 컨테이너는 기본적으로 상태가 없는(Stateless) 방식으로 동작합니다. 컨테이너 내부에서 생성되거나 변경된 모든 파일은 해당 컨테이너의 생명주기에 묶여 있으며, 컨테이너가 삭제되면 데이터도 함께 사라집니다. 또한, 한 컨테이너 내부의 데이터는 다른 컨테이너에서 직접 접근하기 어렵습니다. 이러한 특성으로 인해 데이터의 지속성(Persistence)과 컨테이너 간 데이터 공유를 위해 볼륨과 마운트 기능이 제공됩니다. 도커는 호스트 머신의 파일 시스템이나 네트워크 스토리지를 컨테이너 내부의 특정 경로에 연결하는 여러 방식을 지원합니다.
주요 데이터 관리 방식은 다음과 같습니다.
방식 | 설명 | 데이터 위치 | 생명주기 관리 |
|---|---|---|---|
볼륨 마운트 | 도커가 관리하는 볼륨을 컨테이너에 마운트합니다. | 도커 저장 영역( | 도커가 관리하며, 컨테이너와 독립적입니다. |
바인드 마운트 | 호스트 머신의 특정 파일이나 디렉터리를 컨테이너에 마운트합니다. | 호스트 머신의 사용자 지정 경로 | 사용자가 직접 관리합니다. |
tmpfs 마운트 | 데이터를 호스트 머신의 메모리에만 저장합니다. | 호스트 머신의 메모리 | 컨테이너가 중지되면 데이터가 사라집니다. |
볼륨 마운트는 도커 데이터 관리를 위한 권장 방식입니다. docker volume create 명령어로 명시적으로 생성하거나, 컨테이너 실행 시 자동으로 생성될 수 있습니다. 볼륨은 도커 데몬에 의해 관리되며, docker volume 명령어 집합을 통해 조회, 삭제, 백업이 가능합니다. 이 방식은 리눅스와 윈도우 호스트 모두에서 동일하게 작동하며, 데이터를 호스트 파일 시스템의 특정 영역에 안전하게 저장합니다. 반면, 바인드 마운트는 호스트 파일 시스템의 기존 디렉터리나 파일을 컨테이너 경로에 직접 연결합니다. 이는 호스트의 설정 파일(/etc, /usr 등)을 컨테이너에 제공하거나, 개발 중인 소스 코드를 컨테이너에 실시간으로 반영할 때 유용합니다. 하지만 호스트의 파일 시스템 구조에 의존하므로 이식성이 떨어질 수 있습니다.
데이터 관리 전략을 선택할 때는 애플리케이션의 요구사항을 고려해야 합니다. 데이터베이스의 데이터 파일이나 업로드된 파일처럼 컨테이너 재생성 후에도 반드시 유지되어야 하는 데이터는 볼륨 마운트를 사용하는 것이 안전합니다. 개발 환경에서 빠른 코드 반복 테스트가 필요하다면 바인드 마운트가 효율적입니다. 민감한 정보를 일시적으로만 처리해야 한다면 tmpfs 마운트를 사용하여 컨테이너 종료 시 데이터가 자동으로 제거되도록 할 수 있습니다.
6.1. 볼륨 마운트
6.1. 볼륨 마운트
볼륨 마운트는 도커가 관리하는 영구적인 데이터 저장소를 컨테이너에 연결하는 방식이다. 도커 엔진이 생성하고 관리하는 특수 디렉터리로, 호스트 파일 시스템 내의 /var/lib/docker/volumes/ 경로 아래에 위치한다. 사용자는 docker volume create 명령어로 명시적으로 볼륨을 생성하거나, 컨테이너 실행 시 -v 또는 --mount 옵션을 사용하면 도커가 자동으로 해당 볼륨을 생성한다.
볼륨 마운트의 주요 장점은 데이터의 생명주기가 컨테이너와 독립적이라는 점이다. 컨테이너를 삭제해도 볼륨과 그 안의 데이터는 보존된다. 또한, 여러 컨테이너가 동일한 볼륨에 동시에 읽기/쓰기 접근할 수 있어 데이터 공유에 유용하다. 도커 명령어(docker volume ls, docker volume inspect, docker volume prune 등)를 통한 중앙 집중식 관리가 용이하며, 리눅스 호스트뿐만 아니라 윈도우 호스트에서도 일관되게 동작한다.
특징 | 설명 |
|---|---|
생성 및 관리 | 도커 엔진에 의해 관리되며, |
저장 위치 | 호스트의 |
데이터 지속성 | 컨테이너 삭제 후에도 데이터가 보존된다. |
사용 사례 | 데이터베이스 파일, 애플리케이션 로그, 업로드된 파일 등 영구 저장이 필요한 데이터에 적합하다. |
볼륨은 도커 컴포즈나 쿠버네티스와 같은 오케스트레이션 도구에서도 널리 사용된다. 컴포즈 파일의 volumes: 섹션을 통해 정의하면, 서비스 컨테이너들 간에 데이터 볼륨을 쉽게 공유하고 구성할 수 있다. 보안 측면에서, 호스트 파일 시스템의 특정 경로에 직접 접근하는 바인드 마운트보다 권한과 이식성 면에서 더 안전한 방식으로 간주된다.
6.2. 바인드 마운트
6.2. 바인드 마운트
바인드 마운트는 호스트 머신의 파일 시스템에 있는 특정 경로나 파일을 도커 컨테이너 내부의 경로에 직접 연결하는 방법이다. 볼륨 마운트가 도커가 관리하는 전용 스토리지 영역을 사용하는 것과 달리, 바인드 마운트는 호스트의 기존 디렉터리나 파일을 참조한다. 이 방식은 컨테이너가 호스트의 구성 파일, 소스 코드, 또는 로그 디렉터리와 같은 특정 데이터에 직접 접근해야 할 때 주로 사용된다.
docker run 명령어에서 -v 또는 --mount 플래그를 사용하여 바인드 마운트를 설정할 수 있다. 경로를 지정할 때 호스트의 절대 경로를 명시적으로 제공해야 한다. 예를 들어, docker run -v /home/user/app:/app 명령은 호스트의 /home/user/app 디렉터리를 컨테이너 내부의 /app 경로에 마운트한다. --mount 플래그를 사용할 경우 형식이 더 명시적이며, type=bind,source=/home/user/app,target=/app와 같이 지정한다.
바인드 마운트의 주요 특징은 성능과 직접적인 제어에 있다. 호스트 파일 시스템을 직접 사용하기 때문에 I/O 성능이 일반적으로 좋으며, 호스트의 기존 도구를 사용하여 데이터를 쉽게 관리하고 모니터링할 수 있다. 그러나 이는 동시에 보안과 이식성 측면에서 주의가 필요하다. 컨테이너가 호스트의 민감한 시스템 파일에 접근할 수 있게 되어 보안 위험이 발생할 수 있으며, 호스트의 특정 경로 구조에 의존하기 때문에 다른 호스트 환경으로 애플리케이션을 이동할 때 문제가 생길 수 있다[3].
따라서 바인드 마운트는 주로 개발 환경에서 소스 코드를 실시간으로 반영하거나, 호스트의 특정 로그 수집기를 공유하는 등 호스트와 긴밀한 통합이 필요한 시나리오에 적합하다. 프로덕션 환경에서는 데이터의 지속성과 이식성을 보장하는 도커 볼륨이나 더욱 관리가 쉬운 네임드 볼륨을 사용하는 것이 일반적인 모범 사례이다.
7. 도커 컴포즈
7. 도커 컴포즈
도커 컴포즈는 YAML 형식의 설정 파일(docker-compose.yml)을 사용하여 다중 컨테이너 애플리케이션을 정의하고 실행하기 위한 도구이다. 단일 명령어로 애플리케이션을 구성하는 모든 서비스(예: 웹 서버, 데이터베이스, 캐시 서버)를 함께 시작, 중지, 재구성할 수 있다. 이는 개발, 테스트, 스테이징 환경에서 복잡한 애플리케이션 스택을 손쉽게 관리할 수 있게 해주며, 특히 마이크로서비스 아키텍처 환경에서 유용하게 활용된다.
docker-compose.yml 파일의 구조는 주로 version, services, networks, volumes 등의 최상위 키로 구성된다. services 섹션 아래에 각 컨테이너 서비스를 정의하며, 각 서비스는 사용할 도커 이미지, 포트 매핑, 환경 변수, 볼륨 마운트, 의존성 관계, 네트워크 설정 등을 지정한다. 예를 들어, 웹 애플리케이션과 데이터베이스를 연결하는 기본적인 파일 구조는 다음과 같다.
```yaml
version: '3.8'
services:
web:
image: nginx:latest
ports:
"80:80"
depends_on:
db
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: examplepassword
volumes:
db_data:/var/lib/postgresql/data
volumes:
db_data:
```
도커 컴포즈를 사용한 다중 컨테이너 애플리케이션 관리는 몇 가지 핵심 명령어로 이루어진다. docker-compose up 명령은 구성 파일에 정의된 모든 서비스를 시작하며, -d 옵션을 추가하면 백그라운드에서 실행된다. docker-compose down 명령은 실행 중인 모든 서비스를 중지하고 네트워크를 제거한다. 또한, docker-compose ps로 서비스 상태를 확인하고, docker-compose logs로 로그를 출력하며, docker-compose exec를 통해 실행 중인 특정 서비스 컨테이너 내부에 명령을 실행할 수 있다. 이를 통해 개발자는 로컬 환경에서 프로덕션과 유사한 복합 서비스 환경을 일관되고 재현 가능하게 구성할 수 있다.
7.1. YAML 파일 구조
7.1. YAML 파일 구조
docker-compose.yml 파일은 YAML 형식을 따르며, 애플리케이션을 구성하는 서비스, 네트워크, 볼륨을 선언적으로 정의합니다. 파일의 최상위 키는 주로 version, services, networks, volumes로 구성됩니다. version 키는 사용할 도커 컴포즈 파일 형식의 버전을 지정하며, 이는 사용 가능한 기능과 호환성에 영향을 미칩니다. services 키 아래에 각 컨테이너 서비스의 설정을 정의합니다.
각 서비스는 image나 build 같은 필수 항목을 포함하여 세부 구성을 명시합니다. image는 사용할 도커 이미지를 지정하고, build는 Dockerfile이 위치한 컨텍스트 경로를 지정하여 이미지를 빌드하도록 지시합니다. 그 외에 자주 사용되는 구성 옵션은 다음과 같습니다.
옵션 | 설명 | 예시 |
|---|---|---|
| 호스트와 컨테이너 간의 포트 매핑을 설정합니다. |
|
|
| |
| 컨테이너 내 환경 변수를 설정합니다. |
|
| 서비스 간의 시작 의존성을 선언합니다. |
|
| 서비스가 연결될 네트워크를 지정합니다. |
|
networks와 volumes 최상위 키에서는 사용자 정의 도커 네트워크와 도커 볼륨을 정의합니다. 이를 통해 서비스들이 독립된 네트워크에서 통신하거나 데이터를 영구적으로 저장할 수 있습니다. 파일 구조는 들여쓰기에 민감하므로 공백을 일관되게 사용해야 합니다. 이 선언적 접근 방식은 복잡한 멀티 컨테이너 애플리케이션의 설정과 실행을 단일 명령어(docker-compose up)로 가능하게 합니다.
7.2. 다중 컨테이너 애플리케이션 관리
7.2. 다중 컨테이너 애플리케이션 관리
도커 컴포즈는 docker-compose.yml 파일에 정의된 서비스, 네트워크, 볼륨 설정을 기반으로 다중 컨테이너 애플리케이션의 생명주기를 관리한다. 단일 명령어로 여러 컨테이너를 한꺼번에 시작, 중지, 재시작하거나 상태를 확인할 수 있다. 이는 마이크로서비스 아키텍처나 웹 애플리케이션, 데이터베이스, 캐시 서버 등 상호 의존적인 구성 요소를 함께 실행해야 하는 환경에서 개발과 테스트 워크플로우를 단순화한다.
애플리케이션 관리를 위한 주요 명령어는 다음과 같다.
명령어 | 설명 |
|---|---|
| 구성 파일에 정의된 모든 서비스의 컨테이너를 생성하고 시작한다. |
| 실행 중인 모든 서비스 컨테이너를 중지하고 제거한다. 네트워크와 볼륨도 함께 제거할 수 있다. |
| 현재 프로젝트의 각 서비스 컨테이너 상태를 보여준다. |
| 모든 서비스 컨테이너의 로그 출력을 확인한다. 특정 서비스(예: |
| 모든 서비스 컨테이너를 재시작한다. |
| 실행 중인 특정 서비스 컨테이너 내에서 명령어를 실행한다. 예를 들어 데이터베이스 셸에 접속할 때 사용된다. |
컨테이너 간의 의존성은 depends_on 지시어로 관리하여 특정 서비스가 다른 서비스 이후에 시작되도록 보장한다. 또한, docker-compose.yml 파일에서 환경 변수를 .env 파일로 분리하거나, 여러 컴포즈 파일을 -f 옵션으로 조합하여 개발, 테스트, 프로덕션 등 다른 환경에 맞게 설정을 유연하게 변경할 수 있다. 이를 통해 로컬 개발 환경과 배포 환경의 구성 차이를 쉽게 관리한다.
8. 보안 모범 사례
8. 보안 모범 사례
컨테이너는 호스트 시스템의 커널을 공유하지만, 적절한 격리와 보안 설정이 이루어지지 않으면 잠재적인 위협이 될 수 있다. 보안 강화를 위해 루트 권한으로 컨테이너를 실행하는 것을 피해야 한다. Dockerfile 내에서 USER 지시어를 사용하여 특정 사용자로 전환하거나, docker run 명령어에 --user 옵션을 추가하여 권한이 제한된 사용자로 컨테이너를 실행하는 것이 좋다. 또한, 불필요한 setuid 및 setgid 권한이 설정된 바이너리를 컨테이너 이미지에서 제거해야 한다.
이미지의 취약점 관리는 지속적으로 이루어져야 한다. 공식 및 검증된 베이스 이미지를 사용하고, 불필요한 패키지 설치를 최소화하여 공격 표면을 줄여야 한다. 정기적으로 docker scan 명령어나 외부 도구를 활용하여 이미지 내 알려진 취약점을 점검하고, 최신 보안 패치가 적용된 이미지로 재빌드하는 과정이 필요하다. 컨테이너 런타임 시에는 필요한 최소한의 커널 능력만을 부여해야 하며, --cap-drop 옵션으로 불필요한 능력을 제거하고 --cap-add로 필요한 능력만을 선택적으로 추가할 수 있다.
네트워크 보안도 중요한 고려 사항이다. 기본 브리지 네트워크 대신 사용자 정의 네트워크를 생성하여 컨테이너 간 통신을 세밀하게 제어해야 한다. 불필요한 포트는 노출하지 않으며, 컨테이너 간 통신이 필요한 경우 내부 네트워크만을 사용하도록 구성한다. 민감한 데이터는 환경 변수보다는 도커 시크릿이나 볼륨 마운트를 통해 안전하게 전달해야 한다.
보안 영역 | 모범 사례 | 관련 도커 옵션/기능 |
|---|---|---|
권한 관리 | 비루트 사용자로 실행, 불필요한 커널 능력 제거 |
|
이미지 보안 | 최소 베이스 이미지 사용, 정기적 취약점 스캔, 서명된 이미지 사용 |
|
네트워크 격리 | 사용자 정의 네트워크 사용, 불필요한 포트 노출 금지 |
|
자료 관리 | 시크릿 사용, 읽기 전용 볼륨 마운트 활용 |
|
호스트 보호 |
|
마지막으로, 호스트 시스템 자체의 보안을 유지하는 것이 근본적이다. 도커 데몬에 대한 접근 권한을 엄격히 관리하고, 최신 버전의 도커 엔진과 호스트 OS를 유지해야 한다. 필요에 따라 AppArmor나 SELinux와 같은 호스트 수준의 보안 모듈을 컨테이너 프로필과 함께 사용하여 격리 수준을 강화할 수 있다.
9. 모니터링과 로깅
9. 모니터링과 로깅
도커 컨테이너 기반 애플리케이션의 상태를 추적하고 문제를 진단하기 위해서는 체계적인 모니터링과 로깅이 필수적이다. 컨테이너는 일시적이고 동적으로 생성되거나 소멸될 수 있기 때문에, 전통적인 물리 서버나 가상 머신과는 다른 접근 방식이 필요하다.
모니터링은 주로 컨테이너의 자원 사용량과 상태를 실시간으로 관찰하는 것을 의미한다. docker stats 명령어를 사용하면 실행 중인 컨테이너의 CPU, 메모리, 네트워크 I/O, 블록 I/O 사용량을 간편하게 확인할 수 있다. 보다 중앙화되고 지속적인 모니터링을 위해서는 프로메테우스와 그라파나 같은 도구들이 널리 사용된다. 프로메테우스는 컨테이너, 호스트, 애플리케이션에서 메트릭을 수집하고, 그라파나는 이를 시각화한다. 도커 데몬 자체도 메트릭을 노출시키며, 이를 수집하여 전체 시스템의 건강 상태를 파악할 수 있다.
로깅은 애플리케이션이나 시스템에서 생성된 텍스트 출력을 수집하고 관리하는 과정이다. 도커는 컨테이너 내부의 표준 출력(stdout)과 표준 에러(stderr) 스트림을 캡처하는 통합 로깅 메커니즘을 제공한다. docker logs 명령어로 특정 컨테이너의 로그를 확인할 수 있다. 그러나 대규모 환경에서는 로그를 파일이나 호스트에만 두는 것은 비효율적이며, 중앙 집중식 로그 관리 시스템이 필요하다. 이를 위해 Fluentd, Logstash, 파일비트 같은 로그 수집기를 컨테이너로 배포하여 로그를 수집한 후, 엘라스틱서치에 저장하고 키바나로 조회 및 분석하는 ELK 스택이 일반적으로 구성된다.
도구 유형 | 대표 도구 | 주요 용도 |
|---|---|---|
명령어 |
| 실시간 자원 확인, 로그 간편 조회 |
모니터링 | 메트릭 수집, 대시보드 시각화 | |
로깅 | 로그 수집, 중앙 저장, 분석 |
효과적인 모니터링과 로깅 전략은 애플리케이션의 가용성을 높이고, 장애 발생 시 신속한 원인 분석을 가능하게 하며, 성능 병목 현상을 사전에 발견하는 데 기여한다. 특히 마이크로서비스 아키텍처에서는 수십, 수백 개의 컨테이너를 관리해야 하므로 이러한 관찰 가능성 도구들의 역할이 더욱 중요해진다.
