콘텐츠로 바로가기

Docker & Containerization

애플리케이션과 모든 의존성을 격리된 컨테이너로 패키징하여 "내 로컬에서는 됐는데" 문제를 제거하는 기술.

Article
M

Me

hyunyoun's Blog

software-engineering-devopssoftware-engineeringdev-opsreliabilitydocker-containerizationdockercontainerizationci10 min read

1. Overview

도커와 컨테이너 역학(Docker & Containerization)은 "내 컴퓨터에서는 잘 도는데요?"라는 개발자의 변명을 영원히 박살 내고, 애플리케이션과 그 생태계 전체를 얼음처럼 얼려버린 뒤 어느 서버에든 똑같이 해동시켜 실행하는 불변성(Immutability)의 물리학을 해부합니다.

학습자는 무거운 운영체제(Guest OS)를 통째로 띄우던 가상머신(VM)의 낭비를 뜯어보고, 리눅스 커널을 공유하며 프로세스 격리벽(cgroup, namespace)만 치는 컨테이너의 초경량 구조를 장악합니다. 나아가 Dockerfile을 작성하여 레이어(Layer) 캐시를 극한으로 뽑아먹는 이미지 빌드 최적화를 익히고, 마지막으로 데이터를 영속화하는 볼륨(Volume)과 컨테이너 간의 통신(Network)을 연결하는 컨테이너 생태계 엔지니어링 역량을 확보합니다.

2. Scope & Boundaries

In-Scope

  • VM vs Container Physics: 하이퍼바이저(Hypervisor) 구조와 리눅스 네임스페이스(Namespace) 기반 격리의 무게 차이.
  • Docker Image Layering: Union File System (읽기 전용 레이어 스택)과 캐싱 메커니즘 최적화.
  • Dockerfile Best Practices: Multi-stage Build, 패키지 설치 최적화, 경량 베이스 이미지 사용.
  • State Management: 상태를 가지지 않는(Stateless) 컨테이너의 휘발성과 Bind Mount, Volume을 통한 데이터 영속화.

Out-of-Scope

  • Kubernetes(k8s) 오케스트레이션: 수백 대의 도커 컨테이너를 스케줄링하고 자동 복구하는 기술 \rightarrow 09-05-03 Kubernetes Pod 모듈로 분리.
  • 컨테이너 보안(하드닝): Root-less 컨테이너, 디폴트 포트 제한 등의 보안 설정 \rightarrow 09-04-03 Hardening Pattern으로 위임.

Boundaries

  • VM vs Container: VM은 아파트를 지을 때마다 정수기, 보일러, 발전기를 새로 설치(Guest OS)하는 무식한 짓입니다. 컨테이너는 건물(Host OS)의 정수기와 보일러(Kernel)를 그대로 쓰면서 얇은 벽돌(Namespace)만 쳐서 방을 나누는 것입니다. 무겁고 느린 인프라 할당 패러다임에서, 가볍고 즉각적인 '프로세스 격리' 패러다임으로의 이주임을 명확히 긋습니다.

3. Counterexample

  • 캐시 파괴 (Layer Cache Miss): 주니어 개발자가 Dockerfile을 짤 때 맨 윗줄에 COPY . .(모든 소스 복사)를 넣고, 그 아랫줄에 RUN npm install을 넣었습니다. 소스코드의 주석 글자 하나만 바꿔도 캐시가 전부 깨져서, 빌드할 때마다 패키지를 새로 10분씩 다운로드합니다. 레이어 구조의 물리학을 이해하지 못해 발생한 빌드 속도의 재앙입니다.
  • 휘발되는 데이터 (Stateless): MySQL 데이터베이스를 도커로 띄웠습니다. 볼륨(Volume)을 연결하지 않았습니다. 잘 쓰다가 컨테이너를 업데이트하려고 내렸다가 다시 띄웠더니, 저장된 사용자 데이터가 100% 날아갔습니다. 컨테이너 내부의 파일 시스템은 컨테이너가 죽을 때 함께 소멸(휘발)한다는 상태 관리 법칙을 무시한 치명적 사고입니다.

4. Prerequisites

  • 운영체제 커널 (Basic): OS 커널의 역할, 프로세스 격리. (03. Operating Systems)
  • 리눅스 기초 (Basic): 리눅스 파일 시스템, 환경변수, 포트 포워딩. (03. Operating Systems)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 The Physics of Isolation 수 기가바이트의 VM을 버리고, 호스트의 심장(커널)을 공유하며 5초 만에 부팅되는 컨테이너의 가벼운 물리 법칙을 쥡니다. P1
2 Layer Cake Architecture 한 겹 한 겹 얼려진 읽기 전용 레이어(Image) 위에 투명한 쓰기 셀로판지(Container)를 덧대는 유니온 파일 시스템을 뜯어봅니다. P5
3 Dockerfile Physics 빈번하게 바뀌는 소스 코드는 밑으로, 잘 안 바뀌는 라이브러리 설치는 위로 올려 캐시를 100% 재사용하는 최적화 빌드술을 장악합니다. Industry
4 Stateless vs Stateful 죽으면 모든 기억이 날아가는 컨테이너의 뇌세포(데이터)를 살리기 위해, 외부 디스크(Volume)에 탯줄을 연결하는 상태 관리법을 확보합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 커널의 공유 (The Physics of Isolation)

  • Why to Learn: "서버 안에 서버를 띄우면 느리지 않을까?"라는 가상머신(VM) 시대의 고정관념을 부수고, 성능 저하(Overhead)가 0%에 수렴하는 컨테이너의 격리 구조를 이해하기 위함입니다.
  • What to Learn:
    • Concepts: Virtual Machine (VM), Hypervisor, Guest OS, Container, Linux Namespaces (PID, NET), Cgroups.
    • Skills: VM이 1GB의 RAM을 무조건 예약(할당)해 버리는 낭비와 비교하여, 컨테이너가 호스트 OS의 자원을 필요한 만큼만 나눠 쓰는 유연성을 증명하기.
  • How to Learn:
    • 1단계: VM의 무거움: VM은 하드웨어부터 커널(OS)까지 전부 가짜로 만들어냅니다. 그래서 앱 하나 돌리려 해도 무거운 우분투를 매번 새로 띄워야(부팅 3분) 합니다.
    • 2단계: 컨테이너의 꼼수: 도커는 커널을 새로 띄우지 않습니다. 현재 깔린 리눅스의 심장(커널)을 그냥 씁니다. 대신 프로세스 주변에 눈가리개(Namespace)를 씌웁니다. 해당 프로세스는 자기가 1번 프로세스(PID 1)인 줄 착각합니다.
    • 3단계: 물리적 차이: 커널이 없으니 컨테이너 이미지는 5MB(Alpine)까지 작아지고, 부팅은 0.1초 만에 끝납니다. 앱의 성능을 갉아먹지 않으면서도 완벽하게 격리된 '환상'을 만들어내는 리눅스 커널의 예술을 해부합니다.
  • Implement: VM vs Container 자원 점유 렌더링. 과제: 10MB짜리 Node.js 앱 10개 띄우기. VM: 1GB짜리 Ubuntu 10개 구동 = 총 RAM 10GB 소모. 부팅 5분. Docker: 호스트 커널 공유, 10MB 앱 10개만 메모리에 상주 = 총 RAM 100MB 소모. 부팅 1초. 인프라 비용을 1/100로 압살하는 효율성 시각화.

Core Topic 02: 레이어 케이크 (Layer Cake Architecture)

  • Why to Learn: "우분투 이미지 1GB를 10개 띄우면 용량이 10GB가 차는가?"라는 질문에 "아니오, 1GB만 찹니다"라고 답할 수 있는, 도커 최강의 무기인 '레이어 재사용(Union File System)'을 깨닫기 위함입니다.
  • What to Learn:
    • Concepts: Docker Image, Docker Container, Layer, Union File System (UFS), Read-only Layer, Copy-on-Write (CoW).
    • Skills: ubuntu 이미지 베이스에 nginx를 깐 이미지 레이어가 어떻게 쌓여있는지 분석하고, 컨테이너가 켜질 때 최상단에 얇은 '쓰기 가능(Writable)' 레이어가 덮어씌워지는 구조 이해하기.
  • How to Learn:
    • 1단계: 얼어붙은 케이크 (Image): 도커 이미지는 한 덩어리가 아닙니다. [우분투] 레이어 위에 [파이썬] 레이어, 그 위에 [내 소스코드] 레이어가 쌓인 케이크입니다. 이 레이어들은 돌처럼 얼어있어(Read-only) 절대 수정할 수 없습니다.
    • 2단계: 투명 셀로판지 (Container): 이미지를 실행(Run)하면 도커는 얼어붙은 케이크 맨 위에 투명하고 얇은 '셀로판지(Writable Layer)' 하나를 깔아줍니다. 이게 바로 컨테이너입니다.
    • 3단계: Copy-on-Write: 컨테이너 안에서 우분투의 기본 파일을 '수정'하려고 하면, UFS는 원본(얼어있는 레이어)을 건드리지 않고, 그 파일을 투명 셀로판지로 '복사(Copy)'해 와서 수정합니다. 원본 이미지의 100% 재사용성을 보장하는 파일 시스템의 기적을 뜯어봅니다.
  • Implement: 디스크 용량 계산 시뮬레이션. 상황: 1GB짜리 우분투 이미지를 기반으로 100개의 컨테이너 실행. 디스크 용량: 1GB * 100 = 100GB? (X). 진실: 100개의 컨테이너는 1GB 우분투 레이어를 100% 공유함. 추가로 소모되는 디스크는 오직 100개의 셀로판지(수 MB)뿐. 극강의 디스크 효율성 시각화.

Practical

Core Topic 03: 캐시를 지배하는 자 (Dockerfile Physics)

  • Why to Learn: 빌드할 때마다 npm install이나 apt-get을 5분씩 새로 다운로드하며 커피를 타러 가는 악습을 끊고, 캐시(Cache)를 폭발적으로 재사용하여 빌드 시간을 3초로 단축하기 위함입니다.
  • What to Learn:
    • Concepts: Dockerfile, Cache Invalidation, Command Ordering, Multi-stage Build.
    • Skills: 빈번하게 코드가 바뀌는 COPY . . 명령어는 파일의 맨 밑으로 내리고, 패키지를 다운받는 RUN npm install은 위로 올려 빌드 캐시 힛(Hit) 100% 달성하기.
  • How to Learn:
    • 1단계: 캐시 붕괴의 원리: Dockerfile은 위에서 아래로 한 줄씩 실행됩니다. 만약 3번째 줄의 레이어에서 파일이 조금이라도 변경(Cache Miss)되면, 그 아래 4, 5, 6번째 줄의 캐시는 무조건 연쇄적으로 다 깨집니다(다시 빌드됨).
    • 2단계: 순서의 미학: 소스코드는 1분마다 바뀝니다. 라이브러리(package.json)는 1달에 1번 바뀝니다. 따라서 안 바뀌는 놈을 윗줄로, 훅훅 바뀌는 놈을 아랫줄로 배치해야 캐시가 살아남습니다.
    • 3단계: 멀티 스테이지 (Multi-stage): gcc 같은 컴파일러는 앱을 '빌드'할 때만 필요하고, 실제로 '실행'할 때는 무거우니까 버려야 합니다. FROM을 두 번 써서 첫 번째 무대(Stage)에서 빌드만 하고, 결과물(실행파일)만 날씬한 두 번째 무대로 쏙 빼오는 다이어트 기법을 해부합니다.
  • Implement: Dockerfile 캐시 최적화 렌더링. Before (캐시 지옥): COPY . . \rightarrow RUN npm install (소스 고칠 때마다 npm 5분 재다운로드). Action: 명령어 재배치. After (캐시 천국): COPY package.json . \rightarrow RUN npm install (캐시 적중! 0.1초 컷) \rightarrow COPY . . (마지막에 소스만 덮어씀). 생각의 순서가 빌드 속도를 지배하는 시각화.

Advanced

Core Topic 04: 기억 상실증의 치료 (Stateless vs Stateful)

  • Why to Learn: 도커 컨테이너는 삭제되는 순간 내부에 저장했던 파일과 데이터를 모두 안고 자폭하는 휘발성(Stateless)을 가지므로, 절대 유실되면 안 되는 DB 데이터를 안전하게 바깥으로 빼내기 위함입니다.
  • What to Learn:
    • Concepts: Stateless, Bind Mounts, Docker Volumes, Data Persistence.
    • Skills: MySQL 컨테이너를 띄울 때 내부의 /var/lib/mysql 디렉토리를 내 맥북(호스트)의 특정 폴더와 탯줄(Volume)로 연결하여, 컨테이너를 날려버려도 데이터는 영원히 살아남게 세팅하기.
  • How to Learn:
    • 1단계: 소멸의 미학: 컨테이너는 '소모품'입니다. 에러가 나면 고치는 게 아니라 지우고 새 컨테이너를 띄우는 게 룰입니다(Pet vs Cattle). 이때 컨테이너 내부의 셀로판지(Writable Layer)에 쓴 파일은 컨테이너 삭제와 함께 완벽히 휘발됩니다.
    • 2단계: 바인드 마운트 (Bind Mount): 내 맥북의 바탕화면 폴더를 컨테이너 내부의 /app 폴더에 강제로 뚫어(Mount) 연결합니다. 개발할 때 코드를 고치면 컨테이너 내부에 실시간으로 반영되는 핫 리로드(Hot-reload)의 원리입니다.
    • 3단계: 볼륨 (Volume): 바인드 마운트와 달리, 도커 엔진이 꽁꽁 숨겨둔 비밀스러운 안전 구역에 데이터를 저장합니다. DB 데이터를 영속화(Persist)할 때는 권한 문제가 없는 Volume을 사용하는 것이 표준입니다. 컨테이너의 기억 상실증을 완치하는 데이터 탯줄을 뜯어봅니다.
  • Implement: 도커 Volume 연결 구조 모사. 명령어: docker run -v my_db_data:/var/lib/mysql mysql:8 사고 발생: 주니어가 실수로 docker rm -f mysql 입력 (컨테이너 완전 삭제). 복구: docker run -v my_db_data:/var/lib/mysql mysql:8 다시 실행. 결과: 기존 회원의 데이터가 100% 그대로 남아있음. 컨테이너는 죽어도 데이터는 죽지 않는 영속성의 시각화.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Container (컨테이너) OS를 통째로 에뮬레이팅하는 VM과 달리, 리눅스 커널을 공유하면서 프로세스 주변에 눈가리개(Namespace)만 씌워 완벽하게 격리된 '독방'을 만들어내는 초경량 기술입니다. 기본 애플리케이션과 의존성의 패키징 및 격리 VM / Namespace / Image VM (가상머신) 컨테이너 안에는 리눅스 커널이 없음. Mac이나 Windows에서 리눅스 컨테이너가 도는 이유는 백그라운드에 눈에 안 띄게 아주 작은 리눅스 VM을 하나 숨겨두었기 때문임 P1:CS2023 core
Image (이미지) "내 컴퓨터에서는 되는데?"라는 핑계를 박살 내기 위해, 코드, 라이브러리, 환경변수까지 앱 구동에 필요한 100% 모든 것을 찰칵 찍어 돌처럼 굳혀버린(Read-only) 스냅샷입니다. 권장 환경 불일치 해소 및 불변성(Immutability) 보장 Dockerfile / Layer / Container Container (실행 인스턴스) 이미지는 '붕어빵 틀'이고, 컨테이너는 그 틀로 찍어낸 '실제 붕어빵'임. 하나의 이미지로 100개의 컨테이너를 복제해 낼 수 있음 P5:SFIA core
Layer Cache (레이어 캐시) Dockerfile의 명령어 한 줄 한 줄을 레이어 단위로 캐싱하여, 변경되지 않은 윗부분의 레이어는 다운받지 않고 재사용함으로써 빌드 시간을 0초로 압축하는 최적화 메커니즘입니다. 실무 빌드 속도 최적화 및 네트워크 비용 감소 Dockerfile / Union File System Cache Invalidation 소스코드 복사(COPY . .)를 윗줄에 쓰면 소스 1글자만 고쳐도 그 아래 줄의 모든 캐시가 무효화되므로 반드시 맨 아래로 내려야 함 Industry core
Volume (볼륨) 삭제되면 모든 파일이 날아가는 컨테이너의 기억 상실증(Stateless)을 극복하기 위해, 컨테이너 바깥(도커 엔진 내부)에 안전하게 만들어 탯줄처럼 꽂아 쓰는 데이터 저장소입니다. 심화 데이터 영속화(Persistence) 및 컨테이너 간 데이터 공유 Bind Mount / Stateless Bind Mount (바인드 마운트) 바인드 마운트는 "내 바탕화면 폴더"를 꽂는 거라 권한 꼬임(Permission Denied)이 흔하지만, Volume은 도커가 관리하는 전용 공간이라 DB 구동에 가장 안전함 Industry core

8. References

Primary

  • [P1] CS2023 - Software Engineering (SE) - Software Architecture (Containerization and Virtualization)
  • [P5] SFIA - IT Operations (ITOP) - Deployment and provisioning (Containers)

Secondary

  • [Docker in Action] Jeff Nickoloff - Container architecture, Images, Volumes
  • [Operating System Concepts] Silberschatz - Processes, Linux Namespaces and cgroups

Industry

  • [Docker Documentation] - Best practices for writing Dockerfiles, Volumes
  • [MartinFowler.com] - ImmutableServer, Containerization

9. Final Checklist

Primary

  • 운영체제(Guest OS)를 통째로 복제하는 가상머신(VM)과, 커널(Kernel)을 공유하고 프로세스만 격리하는 컨테이너(Container)의 구조적 차이를 메모리 오버헤드 관점에서 비교할 수 있는가?
  • 도커 이미지(Image)가 얼어붙은 읽기 전용(Read-only) 레이어들의 스택이며, 컨테이너(Container)가 실행될 때 그 위에 얇은 쓰기 가능(Writable) 레이어를 덮어씌워 데이터를 조작하는 유니온 파일 시스템(UFS)의 원리를 설명할 수 있는가?

Secondary

  • Dockerfile을 작성할 때 잦은 빈도로 변경되는 소스코드 복사(COPY . .) 명령어를 패키지 설치(RUN npm install)보다 먼저 작성했을 때 캐시가 붕괴되는 현상을 지적하고, 캐시 힛(Hit)을 100%로 끌어올리는 명령어 재배치를 수행할 수 있는가?
  • 빌드에만 필요한 무거운 도구(예: gcc 컴파일러)가 최종 도커 이미지 용량을 낭비하지 않도록, FROM 지시어를 두 번 사용하는 멀티 스테이지 빌드(Multi-stage Build)를 적용해 프로덕션 이미지 크기를 수 MB 수준으로 깎아낼 수 있는가?

Industry

  • 데이터베이스(MySQL) 컨테이너가 런타임에 죽거나 재생성될 경우 컨테이너 내부의 데이터가 100% 휘발(Stateless)되는 파멸적 현상을 막기 위해, 도커 볼륨(Volume)을 마운트하여 데이터를 호스트 디스크에 영속화(Persist)할 수 있는가?
  • 1GB짜리 우분투 베이스 이미지를 기반으로 100개의 컨테이너를 동시에 실행했을 때, 디스크 용량이 100GB가 차는 것이 아니라 Copy-on-Write 메커니즘에 의해 원본 이미지 1GB만 재사용됨을 물리적으로 논증할 수 있는가?

CI/CD & Delivery Platform

3 / 4