Containerization & Docker Mechanics
애플리케이션과 그 실행 환경을 표준화된 단위로 묶는 가상화 기술과, 운영체제 수준에서 격리된 공간을 만드는 컨테이너 물리학을 다루는 학습 노드입니다.
Article
M
Me
hyunyoun's Blog
system-architecture-distributed-systemssystem-architecturedistributed-systemsmicroservicescontainerscontainerizationdocker-mechanicslearning10 min read
1. Overview
컨테이너화와 도커 역학(Containerization & Docker Mechanics)은 "내 노트북에서는 잘 되는데요?"라는 개발자의 변명을 영원히 박살 내고, OS부터 애플리케이션 코드까지 통째로 얼려서(Image) 지구상 어디든 똑같이 복제해 내는 현대 인프라의 표준 배송 규격을 해부합니다.
학습자는 무거운 하드웨어를 통째로 가상화하던 **가상 머신(Virtual Machine, Hypervisor)**의 비효율을 깨닫고, 리눅스 커널(Kernel)을 공유하면서 프로세스만 감옥(Namespace)에 가두는 **컨테이너(Container)**의 극단적인 가벼움을 뜯어봅니다. 나아가 Dockerfile을 통해 인프라 구축을 한 줄 한 줄의 코드(IaC)로 선언하고, 수천 개의 이미지를 효율적으로 겹쳐(Layer) 빌드 속도를 기하급수적으로 끌어올리는 **도커 이미지 레이어 아키텍처(Union File System)**를 장악합니다. 마지막으로, 컨테이너가 파괴되면 내부 데이터도 영원히 날아가는 휘발성(Ephemeral)의 한계를 깨고 볼륨(Volume) 마운트를 통해 생명력을 연장하는 인프라 튜닝 역량을 확보합니다.
2. Scope & Boundaries
In-Scope
- Virtual Machine vs Container: Hypervisor(OS 가상화)와 Linux Container(프로세스 격리)의 물리적 차이.
- Linux Kernel Features: Namespaces(자원 격리), cgroups(자원 할당 제한).
- Docker Architecture: Docker Daemon, Client, Registry, Image, Container.
- Image Layering (UnionFS): 캐싱을 활용한
Dockerfile최적화, Multi-stage Build (이미지 다이어트).
Out-of-Scope
- Kubernetes 기반 100개 컨테이너 자동 관리: 07-06-03 Kubernetes & Cluster Orchestration 영역으로 위임 (본 문서는 단일 컨테이너 혹은 Docker-Compose 수준에 집중).
- CI/CD 파이프라인 자동 배포: 09-02 CI/CD & DevOps 영역.
Boundaries
- Container는 미니 리눅스가 아니다: 초보자들은 도커 컨테이너 안에 SSH로 접속해서
apt-get install을 치고 설정을 바꿉니다. 이는 가상 머신(VM) 시절의 낡은 사고방식입니다. 컨테이너는 불변(Immutable)해야 하며 언제든 죽이고 새로 띄울 수 있는 '일회용 소모품(Disposable)'입니다. 변경 사항이 있다면 컨테이너 안에서 수정할 것이 아니라,Dockerfile을 고쳐서 완전히 새로운 이미지를 빌드해야 한다는(Immutable Infrastructure) 선을 명확히 긋습니다.
3. Counterexample
- 10GB짜리 괴물 이미지:
Dockerfile을 대충 짰습니다. 우분투 풀 버전을 베이스로 깔고, 빌드 도구(gcc)와 수많은 패키지를 설치한 뒤 소스코드를 컴파일했습니다. 최종 도커 이미지가 5GB가 되었습니다. 배포할 때마다 서버가 5GB를 다운로드하느라 배포 시간이 30분씩 걸립니다. 컴파일에 쓴 도구(gcc)는 버리고 최종 실행 파일(Binary)만 쏙 빼서 50MB짜리 알파인(Alpine) 이미지로 만드는Multi-stage Build기술을 모르는 자원의 학살입니다. - 데이터 휘발의 공포 (Ephemeral Death): 도커 컨테이너 안에 MySQL을 띄웠습니다. 유저 데이터가 착실히 쌓이고 있습니다. 어느 날
docker stop후docker rm으로 컨테이너를 지우고 새 버전으로 업데이트했습니다. 유저 데이터가 흔적도 없이 증발했습니다. 컨테이너의 파일 시스템은 컨테이너와 운명을 함께한다는 불변의 법칙을 무시하고, 호스트 OS의 디스크를 연결하는 볼륨(Volume) 마운트를 빼먹은 초보적인 대참사입니다.
4. Prerequisites
- 리눅스 OS 기초 (Basic): 프로세스와 파일 시스템 계층 구조. (03-01 OS Core)
- 가상화 개념 (Basic): 하드웨어 가상화와 OS. (03-02 Networking Basics)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 무거운 OS를 벗어던지다 (VM vs Container)
- Why to Learn: 애플리케이션 하나 띄우겠다고 2GB짜리 OS 10개를 부팅하던 구시대 가상 머신(VM)의 비효율을 깨고, 단 1초 만에 켜지는 컨테이너의 구조적 승리를 이해하기 위함입니다.
- What to Learn:
- Concepts: Hypervisor, Guest OS, Container Engine (Docker), Host OS Kernel Sharing, Ephemeral (휘발성).
- Skills: VM과 Container의 아키텍처 다이어그램 비교 및 부팅 속도(Overhead)의 물리적 차이 도출.
- How to Learn:
- 1단계: VM의 딜레마: 집(물리 서버) 안에 방 3개를 만듭니다. VM은 각 방마다 화장실, 주방, 보일러(OS)를 전부 따로 설치합니다. 무겁고 비쌉니다.
- 2단계: 컨테이너의 공용화: 컨테이너는 주방과 보일러(리눅스 커널)를 하나만 두고, 각 방에는 칸막이(격리)만 칩니다. 애플리케이션 입장에서는 자기 방만 보이니까 독립적이라고 느끼지만, 실제 하드웨어 제어는 공용 커널이 다 해주는 극강의 효율을 해부합니다.
- Implement: 도커 컨테이너 부팅 속도 시뮬레이션. 터미널에서
time docker run ubuntu echo "Hello"를 실행하면 1초도 안 걸려서 끝남. OS 부팅 과정(Init, Systemd)이 아예 생략되고 오직echo프로세스 하나만 실행됨을 터미널 로그로 증명.
Recommended
Core Topic 02: 리눅스 커널의 환술, 격리와 통제 (Namespaces & cgroups)
- Why to Learn: "도커는 어떻게 프로세스들을 완벽히 분리하는가?"에 대한 답이 결국 도커의 마법이 아니라 리눅스 커널의 기본 기능(Namespace, cgroup)을 포장한 것임을 꿰뚫기 위함입니다.
- What to Learn:
- Concepts: Linux Namespace (PID, NET, MNT - 논리적 격리), Control Groups (cgroups - 물리적 자원 제한).
- Skills: 특정 컨테이너가 호스트 CPU를 잡아먹는 현상을 막기 위한 리소스 쿼터(Quota) 할당.
- How to Learn:
- 1단계: Namespace (보이지 않는 벽): 호스트 서버에는 1,000개의 프로세스가 돌고 있습니다. 도커가 컨테이너를 띄우면, 그 컨테이너 안의 프로세스에게 PID Namespace라는 안경을 씌웁니다. 이 프로세스는 자기가 "PID 1번(대장)"인 줄 알고, 다른 999개의 프로세스를 아예 보지(View) 못하는 착각의 감옥을 해부합니다.
- 2단계: cgroups (물리적 목줄): A 컨테이너가 버그에 걸려 메모리를 무한대로 씁니다. 호스트 OS가 뻗기 전에 리눅스
cgroup이 작동하여 "너는 RAM 500MB까지만 써!"라며 가차 없이 OOM(Out of Memory)으로 컨테이너를 죽여버리는 자원 통제 기전을 뜯어봅니다.
- Implement: CPU 강제 제한 데모.
docker run --cpus=".5" ubuntu stress --cpu 1실행. 호스트 OS에서htop으로 확인하면, 컨테이너 안의stress프로세스가 아무리 CPU를 쓰려고 발악해도, 실제 호스트 CPU 코어 하나 기준으로는 정확히 만 점유하는 cgroup의 통제력 렌더링.
Practical
Core Topic 03: 비닐을 겹쳐라, 도커 이미지 레이어 (Dockerfile & UnionFS)
- Why to Learn: 무지성으로
Dockerfile을 짜면 코드를 한 줄만 고쳐도 전체 이미지를 다시 다운받아야 하는(캐시 무효화) 재앙을 막고, 캐시(Cache)를 극대화하는 빌드 최적화 역량을 장악하기 위함입니다. - What to Learn:
- Concepts: Dockerfile 명령어 (
FROM,RUN,COPY,CMD), Union File System (UnionFS), Image Layers, Layer Caching (레이어 캐싱). - Skills: 변경이 잦은 코드(Source)와 변경이 드문 의존성(npm install)의 순서를 배치하는
Dockerfile캐싱 최적화 설계.
- Concepts: Dockerfile 명령어 (
- How to Learn:
- 1단계: UnionFS (셀로판지 겹치기): 도커 이미지는 하나의 큰 파일이 아닙니다.
FROM ubuntu(1번 비닐),RUN apt-get(2번 비닐),COPY . .(3번 비닐)처럼 투명한 셀로판지를 겹겹이 쌓아 올린 구조(Layer)입니다. 아래쪽 비닐은 누구나 공유해서 쓸 수 있어 디스크 용량을 획기적으로 아끼는 구조를 해부합니다. - 2단계: 캐싱의 저주:
COPY . .(소스 코드 복사)를 먼저 하고RUN npm install(라이브러리 설치)을 하면, 코드를 한 글자만 고쳐도 캐시가 깨져서 무거운 라이브러리를 매번 새로 설치해야 합니다. "자주 변하지 않는 것을 무조건 위에 둔다"는 Dockerfile 작성의 절대 법칙을 뜯어봅니다.
- 1단계: UnionFS (셀로판지 겹치기): 도커 이미지는 하나의 큰 파일이 아닙니다.
- Implement: 안 좋은 Dockerfile vs 훌륭한 Dockerfile 빌드 속도 비교.
- Bad:
COPY . .RUN pip install -r req.txt - Good:
COPY req.txt .RUN pip install -r req.txtCOPY . .소스 코드를 살짝 고친 뒤 두 번째 빌드(Re-build)를 돌렸을 때, Good 버전이[CACHED]를 띄우며 1초 만에 빌드되는 기적을 터미널 로그로 증명.
- Bad:
Advanced
Core Topic 04: 불변의 인프라와 껍데기 벗기기 (Multi-stage & Volumes)
- Why to Learn: 불변성(Immutable)을 지키기 위해 컨테이너 내부 데이터를 포기할 것인지, 영속성(Volume)을 위해 구멍을 뚫어줄 것인지 통제하고, 프로덕션 배포 이미지의 용량을 극한으로 깎아내리기 위함입니다.
- What to Learn:
- Concepts: Multi-stage Build (다단계 빌드), Docker Volumes (Bind mount, Named volume), Immutable Infrastructure (불변 인프라).
- Skills: 빌드 도구와 런타임 환경을 분리하여 초경량(Alpine) 프로덕션 이미지를 추출하는 Multi-stage 작성.
- How to Learn:
- 1단계: Multi-stage Build (쓰레기 버리기): Go 언어로 코드를 짭니다. 빌드하려면 1GB짜리
golang이미지가 필요합니다. 하지만 빌드가 끝나면 남는main실행 파일은 단 10MB입니다. 1단계(Builder)에서 1GB 이미지로 컴파일만 싹 하고, 2단계에서 깨끗한 5MB짜리alpine이미지에 실행 파일 10MB만 쓱 넘겨 담아 총 15MB짜리 프로덕션 이미지를 뽑아내는 다이어트 기법을 해부합니다. - 2단계: Volume (영속성의 구멍): 컨테이너는 불변해야 하므로 내부에서 쌓이는 DB 데이터는 컨테이너가 죽으면 날아갑니다. 이를 막기 위해 컨테이너의
/var/lib/mysql디렉토리에 호스트 OS의 디스크를 연결(Mount)하여, 컨테이너를 지워도 데이터는 호스트에 안전하게 살아남는 볼륨의 역학을 뜯어봅니다.
- 1단계: Multi-stage Build (쓰레기 버리기): Go 언어로 코드를 짭니다. 빌드하려면 1GB짜리
- Implement: Multi-stage Dockerfile 작성 및 Size 비교.
AS builder구문을 사용하여 자바 소스 코드를maven이미지에서mvn package로 컴파일하고, 아래에서FROM openjdk:jre를 새로 열어.jar파일만 복사(COPY --from=builder)해 오는 데모. 기존 500MB 이미지와 최적화된 100MB 이미지의 크기(docker images) 콘솔 출력 비교.
7. Terminology
8. References
Primary
- [P1] CS2023 - Software Engineering (SE) - Software Architecture and Containerization
- [P5] SFIA - IT Infrastructure (ITOP) - Systems Installation and Removal
Secondary
- [Docker Deep Dive] Nigel Poulton - Containers vs VMs, Images, and Architecture
- [The Docker Book] James Turnbull - Building and Managing Images
Industry
- [Docker Official Documentation] - Best practices for writing Dockerfiles
- [Red Hat] - What is a Linux container? (Namespaces and cgroups)
9. Final Checklist
Primary
- 하드웨어 하이퍼바이저 위에서 무거운 Guest OS를 여러 개 부팅하는 가상 머신(VM)과, 호스트 OS 커널 하나를 공유하며 프로세스만 격리하는 컨테이너(Container)의 성능 및 오버헤드 차이를 설명할 수 있는가?
- 도커 컨테이너 안에서 돌아가는 프로세스들이 어떻게 호스트 서버의 다른 프로세스나 파일 시스템에 접근하지 못하는지, 리눅스 네임스페이스(Namespaces)의 역할을 증명할 수 있는가?
Secondary
- 컨테이너가 무한 루프에 빠져 메모리 누수가 발생했을 때, 호스트 OS 전체가 뻗지 않고 해당 컨테이너만 메모리 초과(OOM)로 깔끔하게 죽여버리는 리눅스 컨트롤 그룹(cgroups)의 통제 역학을 해부할 수 있는가?
-
Dockerfile을 작성할 때, 소스 코드 복사(COPY . .) 명령어와 라이브러리 설치(RUN npm install) 명령어의 순서가 도커 이미지 레이어 캐싱(Layer Caching)과 빌드 속도에 미치는 치명적 영향을 논증할 수 있는가?
Industry
- 프로덕션에 배포할 도커 이미지 용량을 1GB에서 50MB로 줄이고 보안 취약점(Attack Surface)을 최소화하기 위해, 멀티 스테이지 빌드(Multi-stage Build) 패턴과 경량화된 Alpine 이미지를 결합할 수 있는가?
- 도커 컨테이너는 불변(Immutable)하고 언제든 삭제될 수 있는 휘발성(Ephemeral)을 가짐을 인지하고, 데이터베이스 컨테이너의 유저 데이터를 보호하기 위해 호스트 디스크를 마운트하는 도커 볼륨(Docker Volume) 아키텍처를 설계할 수 있는가?