컨테이너 기술과 관련된 리눅스 기능
Container는 Application과 실행 환경을 하나로 묶어, 어디서나 동일하게 실행할 수 있도록 해주는 기술이다.
가상 머신과 달리 호스트 OS의 커널을 공유하면서도 프로세스를 격리하여 실행하기 때문에 가볍고 빠르다.
이러한 Container 기술의 핵심은 리눅스 커널이 제공하는 두 가지 기능에 기반한다.

Namespace: 격리(Isolation)
Namespace는 리눅스 커널 단에서 제공하는 격리 기술이다.
자원을 분리하여 프로세스가 서로를 볼 수 없도록 독립된 공간을 제공한다.
대표적으로 다음과 같은 요소들이 격리된다.
- 프로세스 공간
- 네트워크 인터페이스
- 파일 시스템
이를 통해 컨테이너 내부의 프로세스는 마치 독립된 시스템에서 실행되는 것처럼 동작한다.
Cgroups: 제한(Resource Control)
Cgroups(Control Groups)는 컨테이너가 사용할 수 있는 자원의 양을 제한하는 기술이다.
다음과 같은 자원 사용량을 제어할 수 있다.
- CPU 사용량
- 메모리 사용량
- 디스크 I/O
Namespace가 격리를 담당한다면, Cgroups는 자원 사용의 상한선을 관리한다고 이해하면 된다.
Docker 컨테이너 주요 용어 정리
컨테이너 엔진

컨테이너 엔진은 컨테이너의 생성, 시작, 중지, 삭제를 관리하는 상위 시스템이다.
대표적인 컨테이너 엔진은 다음과 같다.
- Docker
- Podman
- Containerd
- CRI-O
사용자가 docker 명령어를 입력하면, 컨테이너 엔진이 이를 해석하여 네트워크 설정, 볼륨 연결, 실행 환경 구성을 처리한다.
컨테이너 이미지(Container Image)
컨테이너 이미지는 애플리케이션 실행에 필요한 모든 요소를 패키지화한 결과물이다.
이미지에는 다음이 포함된다.
- 파일 시스템
- 애플리케이션 코드
- 라이브러리 및 의존성

컨테이너 이미지는 여러 개의 레이어가 아래에서 위로 쌓인 구조를 가진며, 각 레이어는 독립적이며 변경되지 않는다.
이미지의 가장 아래에는 호스트 OS의 커널이 존재하며, 이를 모든 컨테이너가 공유한다.
그 위에 base image가 올라가고, 그 위에 애플리케이션 코드와 설정이 추가된다.
이미지 레이어는 읽기 전용이며, 컨테이너 실행 시에만 writable layer가 생성된다.
이 writable layer는 컨테이너가 종료되면 사라진다.
Dockerfile을 사용하면 이러한 레이어 구조를 누구나 동일하게 재현할 수 있다.
Dockerfile


Dockerfile은 컨테이너 이미지를 어떻게 생성할 것인지를 정의한 빌드 명세서다.
단순히 명령어 모음이 아니라, 애플리케이션 실행 환경을 재현하기 위한 선언적 레시피라고 이해하는 것이 정확하다.
Dockerfile에는 다음과 같은 정보가 순차적으로 기술된다.
- 어떤 베이스 이미지에서 시작할 것인지
- 애플리케이션 실행에 필요한 라이브러리와 패키지를 어떻게 설치할 것인지
- 어떤 파일을 이미지에 포함할 것인지
- 컨테이너가 시작될 때 어떤 명령을 실행할 것인지
Dockerfile은 단순한 텍스트 파일이며, 도커 엔진은 docker build 명령을 통해 이 파일을 위에서 아래로 한 줄씩 해석하면서 이미지 레이어를 생성한다.
각 명령어는 하나의 이미지 레이어를 만들며, 이 레이어 구조 덕분에 빌드 캐시와 재사용이 가능해진다.
즉, Dockerfile의 핵심 역할은 다음과 같다.
- 실행 환경을 코드로 명확하게 정의한다
- 누가 빌드하더라도 동일한 이미지를 재현할 수 있게 한다
- 환경 구성 과정을 자동화하고 문서화한다
이 때문에 Dockerfile은 단순한 설정 파일이 아니라, 인프라를 코드로 관리하는 IaC(Infrastructure as Code)의 핵심 요소 중 하나로 사용된다.
Image Tag
Image Tag는 컨테이너 이미지의 버전이나 변형을 구분하기 위한 식별자다.
이미지 이름 뒤에 콜론(:)으로 붙으며, 하나의 이미지 저장소(repository) 안에서 여러 버전을 관리하는 역할을 한다.
예를 들면 다음과 같다.
- nginx:1.25
- python:3.11-slim
여기서 nginx나 python은 이미지 이름이고, 1.25, 3.11-slim은 태그다.
태그를 사용하지 않으면 기본적으로 latest가 사용된다.
태그는 단순한 버전 번호일 수도 있고, 이미지의 특성을 나타내는 의미 있는 이름일 수도 있다.
- 3.11: 파이썬 버전
- slim: 불필요한 패키지를 제거한 경량 이미지
- alpine: Alpine Linux 기반의 초경량 이미지
Registry
Registry는 컨테이너 이미지를 저장하고 공유하는 중앙 저장소다.
GitHub가 소스 코드를 저장하는 곳이라면, Registry는 컨테이너 이미지를 저장하는 곳이라고 볼 수 있다.
대표적인 컨테이너 레지스트리는 다음과 같다.
- Docker Hub
- Amazon ECR
Registry는 단순한 파일 저장소가 아니라, 다음과 같은 기능을 제공한다.
- 이미지 버전 관리
- 접근 권한 제어
- 조직 또는 팀 단위의 이미지 공유
- CI/CD 파이프라인과의 연동
레지스트리는 공개(public) 또는 비공개(private) 형태로 운영할 수 있다.
공개 레지스트리는 누구나 이미지를 pull할 수 있고, 비공개 레지스트리는 인증된 사용자만 접근 가능하다.
실무 환경에서는 다음과 같은 패턴이 일반적이다.
- 오픈소스나 테스트용 이미지는 Docker Hub에 공개
- 사내 서비스 이미지는 private registry에 저장
- 클라우드 환경에서는 ECR, GCR, ACR 같은 관리형 레지스트리 사용
컨테이너(Container)
컨테이너는 이미지를 기반으로 실행 중인 프로세스다.
컨테이너 런타임이 이미지를 로드한 뒤, 격리된 환경에서 실제 프로세스를 실행한 결과물이다.
중요한 점은 컨테이너가 가상 머신이 아니라는 것이다.
컨테이너는 호스트 OS의 커널을 공유하며, 프로세스 수준에서 격리된다.
컨테이너의 특징은 다음과 같다.
- 하나 이상의 프로세스를 실행하지만, 보통 하나의 주 애플리케이션을 중심으로 구성된다
- 독립된 파일 시스템, 네트워크, 프로세스 공간을 가진다
- 생성과 종료가 매우 빠르다
- 상태를 가지지 않는(stateless) 실행 단위로 사용하는 것이 권장된다
컨테이너는 본질적으로 “실행 중인 상태”다.
이미지는 정적인 결과물이고, 컨테이너는 그 이미지를 실행한 동적인 인스턴스다.
같은 이미지를 사용해도 여러 개의 컨테이너를 동시에 실행할 수 있으며, 각각은 서로 격리된 환경에서 동작한다.
이 개념을 명확히 구분하면 다음과 같다.
- Image: 실행 환경과 코드가 포함된 설계도
- Container: 그 설계도를 기반으로 실행 중인 프로세스
컨테이너 엔진과 컨테이너 런타임의 차이

컨테이너 엔진(Container Engine)
컨테이너 엔진은 컨테이너 생명주기 전체를 관리하는 상위 제어 시스템이다.
사용자가 입력하는 명령을 받아, 컨테이너 실행에 필요한 모든 준비 과정을 총괄한다.
Docker를 예로 들면, 사용자가 docker build, docker run 같은 명령을 입력하면 다음과 같은 작업을 수행한다.
- Dockerfile을 해석하여 이미지 빌드
- 이미지 레이어 관리 및 캐시 처리
- 네트워크 생성 및 포트 매핑
- 볼륨 생성 및 마운트
- 컨테이너 실행 정책 설정
- 사용자와의 인터랙션 처리
즉, 컨테이너 엔진은 “무엇을 어떻게 실행할 것인가”를 결정하고 조율하는 컨트롤 플레인에 해당한다.
사용자 입장에서는 컨테이너 엔진이 하나의 통합 관리 시스템처럼 보인다.
컨테이너 런타임(Container Runtime)
반면, 컨테이너 런타임은 컨테이너 엔진 내부에서 동작하는 하위 구성 요소로, 실제로 컨테이너를 실행하는 역할을 담당한다.
컨테이너 런타임은 매우 low-level 작업을 수행한다.
대표적인 역할은 다음과 같다.
- 리눅스 namespace를 설정하여 격리 환경 생성
- cgroups를 통해 CPU, 메모리 등의 자원 제한 적용
- 파일 시스템(rootfs) 마운트
- 컨테이너 내부 프로세스 생성 및 실행
즉, 런타임은 “결정된 실행 계획을 실제로 실행하는 실행기”에 가깝다.
Docker 내부 구조: containerd와 runc
Docker는 단일한 프로그램처럼 보이지만, 내부적으로는 여러 계층으로 분리된 구조를 가진다.
현재 Docker의 내부 구성은 대략 다음과 같다.
- Docker CLI: 사용자가 명령을 입력하는 인터페이스
- Docker Engine(Daemon): 상위 관리 및 제어 로직
- containerd: 컨테이너 라이프사이클 관리용 런타임
- runc: OCI(Open Container Initiative) 스펙을 따르는 실제 실행기
containerd는 이미지 관리, 컨테이너 생성·삭제, 상태 관리 등을 담당하며,
runc는 최종적으로 리눅스 커널을 호출해 프로세스를 실행한다.
이 구조 덕분에 Docker는 OCI 표준을 따르는 다른 런타임과도 호환될 수 있다.
쿠버네티스와 CRI(Container Runtime Interface)
초기 Kubernetes는 Docker에 강하게 의존했다.
하지만 Docker는 단일 노드 사용자를 위한 기능이 많아, 대규모 오케스트레이션 관점에서는 무겁고 불필요한 요소가 포함되었다.
이를 해결하기 위해 쿠버네티스는 Container Runtime Interface(CRI)를 도입했다.
CRI는 “쿠버네티스가 컨테이너를 실행하기 위해 런타임과 통신하는 표준 인터페이스”다.
CRI 도입 이후 쿠버네티스는 특정 엔진에 종속되지 않고 다음과 같은 런타임을 직접 사용할 수 있게 되었다.
- containerd
- CRI-O
CRI-O는 쿠버네티스를 위해 설계된 경량 런타임으로, Docker의 불필요한 상위 기능을 제거하고 CRI에 최적화된 구조를 가진다.
결과적으로 쿠버네티스는 더 이상 Docker 자체를 필요로 하지 않으며,
containerd나 CRI-O 같은 런타임을 직접 사용한다.
Docker의 핵심 철학 : Build, Ship, Run

Docker는 컨테이너 기술을 단순한 실행 도구가 아니라, 소프트웨어 전달 방식 자체를 바꾸는 플랫폼으로 정의했다.
이를 가장 잘 표현하는 개념이 바로 Build, Ship, Run이라는 세 단계 철학이다.
이 철학의 핵심은 애플리케이션을 개발(build), 전달(ship), 실행(run)이라는 명확히 분리된 단계로 나누고,
각 단계가 동일한 결과물을 중심으로 유기적으로 연결되도록 만드는 데 있다.
Build: 실행 환경을 코드로 정의하다
Build 단계는 컨테이너 이미지 생성 과정이다.
개발자는 애플리케이션 코드와 함께 Dockerfile을 작성한다.
Dockerfile은 단순한 설정 파일이 아니라,
애플리케이션이 실행되기까지 필요한 모든 환경을 명시적으로 기술한 실행 환경 정의서다.
이 단계에서 정의되는 요소는 다음과 같다.
- 사용할 운영체제 또는 런타임 환경
- 필요한 라이브러리와 의존성
- 애플리케이션 파일 구조
- 기본 실행 명령
docker build 명령을 실행하면 Docker 엔진은 Dockerfile을 위에서 아래로 해석하며 이미지 레이어를 생성한다.
그 결과물인 컨테이너 이미지는 실행에 필요한 모든 요소를 포함한 불변의 아티팩트가 된다.
이 단계를 통해 다음을 실현할 수 있다.
- 실행 환경을 코드로 관리할 수 있다
- 환경 구성의 재현성이 보장된다
- 개발자 로컬 환경과 운영 환경의 차이를 최소화한다
Ship: 실행 결과물을 이동시키다
Ship 단계는 빌드된 이미지를 컨테이너 Registry로 전달하는 과정이다.
이 단계에서 컨테이너 이미지는 단순한 로컬 산출물이 아니라, 공유 가능한 배포 단위가 된다.
docker push 명령을 통해 이미지를 레지스트리에 업로드하면 다음과 같은 효과가 발생한다.
- 다른 개발자나 팀이 동일한 이미지를 사용할 수 있다
- CI/CD 파이프라인에서 자동 배포가 가능해진다
- 개발 환경과 운영 환경이 동일한 이미지로 통일된다
이때 중요한 점은 Ship 단계에서는 더 이상 환경을 재구성하지 않는다는 것이다.
이미지는 빌드 단계에서 완성된 상태 그대로 이동하며, 운영 환경에서는 단순히 실행만 수행한다.
이로 인해 “내 PC에서는 되는데 서버에서는 안 된다”라는 문제가 구조적으로 제거된다.
Run: 동일한 결과물을 어디서나 실행하다
Run 단계는 컨테이너 이미지를 실제로 실행하는 단계다.
docker run 명령을 통해 이미지를 기반으로 컨테이너가 생성되고, 애플리케이션이 동작한다.
이 단계의 특징은 다음과 같다.
- 실행 환경이 이미 이미지에 포함되어 있다
- 서버마다 별도의 환경 설정이 필요 없다
- 컨테이너는 빠르게 생성되고 쉽게 제거할 수 있다
Run 단계에서는 애플리케이션 실행에만 집중한다.
빌드나 설정과 관련된 작업은 이미 이전 단계에서 모두 완료되었기 때문이다.
이 구조 덕분에 Docker는 개발, 테스트, 스테이징, 운영 환경 전반에서 동일한 실행 단위를 사용할 수 있게 만든다.
'Tool 활용법 > Docker 활용법' 카테고리의 다른 글
| [Docker 기초 3] Docker Container 필수 명령어 정리 (0) | 2026.02.06 |
|---|---|
| [Docker 기초 2] Dockerfile로 내 프로그램을 Docker Image로 만들기 (0) | 2026.02.06 |
| [Docker 기초 1] Docker로 띄울 간단한 웹서버 만드는 방법 (0) | 2026.02.05 |
| Docker 설치방법 및 기본 이미지 실행하기 (Image) (0) | 2026.02.05 |
| Docker를 사용해야 하는 이유 (Docker와 Container) (0) | 2026.02.05 |