1. 왜 우리는 컨테이너를 배워야 하는가?
개발 환경을 구축하다 보면 누구나 한 번쯤 겪게 되는 당혹스러운 상황이 있다. 내 컴퓨터에서는 완벽하게 돌아가던 코드가 팀원의 컴퓨터나 실제 운영 서버에만 올라가면 에러와 함께 멈춰버리는 상황이다.
- 나: Python 3.12 설치 완료! 최신 Flask 라이브러리까지 세팅해서 실행 성공!
- 친구: 난 Python 3.9 이야. Flask도 설치 안 되어 있어서 앱이 실행조차 안 돼...
- 나: 어...?
이처럼 소프트웨어 버전, 필수 라이브러리 누락, OS 설정 차이 등 '개발 환경의 파편화'는 협업과 배포를 방해하는 가장 고질적인 문제이다. 컨테이너는 바로 이러한 문제를 뿌리 뽑기 위해 등장했다.
2. 컨테이너의 정의: 모든 것을 하나로 묶는 마법의 상자
- 컨테이너(Container)는 애플리케이션과 그 실행에 필요한 모든 환경을 하나로 묶어, 외부와 격리된 공간에서 실행하는 기술. 단순히 코드만 담는 것이 아니라, 실행에 필요한 5가지 핵심 요소를 빈틈없이 패키징함
- 애플리케이션(Application): 개발자가 작성한 프로그램 코드
- 의존성(Dependency): 프로그램 실행을 위해 필요한 도구 및 프레임워크
- 라이브러리(Library): 앱이 호출하여 사용하는 외부 기능 묶음
- 설정(Configuration): 환경 변수 및 시스템 세부 설정값
- 실행 환경(Runtime): 코드가 실제로 구동되는 엔진 환경
이렇게 모든 요소를 한 단위로 포장했기 때문에, 호스트의 OS 환경에 휘둘리지 않는 '이식성(Portability)'을 갖게 된다. 덕분에 개발자의 노트북에서 만든 컨테이너를 그대로 클라우드 서버로 옮겨도 별도의 추가 설정 없이 동일하게 작동한다.
3. 심층 비교: 가상 머신(VM) vs 컨테이너(Container)
컨테이너가 가벼우면서도 강력한 이유는 기존의 가상화 방식인 가상 머신(VM)과 구조적으로 다른 형태이기 때문이다. 핵심은 '운영체제(OS)의 커널을 공유하느냐'에 있다.
💡 커널(Kernel)이란? 하드웨어와 프로그램 사이를 연결하여 데이터 읽기/쓰기 등의 핵심 작업을 수행하는 운영체제의 심장

| 격리 단위 | 없음 (앱이 OS 위에서 직접 실행) |
Hypervisor 위의 개별 VM (각 VM마다 OS 포함) |
Container Runtime 위의 개별 컨테이너 |
| OS 포함 여부 | 호스트 OS 하나를 여러 앱이 공유 | VM마다 Guest OS를 별도로 가짐 | 호스트 OS 커널을 공유, 컨테이너별 OS 없음 |
| 자원 효율성 | 낮음 (자원 경합) | 무거움 (OS 중복으로 자원 소모 큼) | 가벼움 (OS 미포함, 필요한 바이너리/라이브러리만 포함) |
| 시작 속도 | - | 느림 (OS 부팅 필요) | 빠름 (프로세스 수준 실행) |
- VM은 하드웨어를 가상화(Hypervisor)하여 OS 단위로 격리하지만, Container는 OS 커널을 공유하면서 프로세스 단위로 격리한다.
- 이 때문에 컨테이너는 VM보다 훨씬 가볍고 빠르며, 하나의 호스트에서 더 많은 워크로드를 실행할 수 있다.
💡 어떻게 격리되는거죠? (Namespaces) 도커는 Go 언어로 작성되었으며, 리눅스 커널의 Namespaces(네임스페이스)라는 기술을 사용함. 이는 각 컨테이너에게 독립된 네트워크와 프로세스 공간을 제공하여, 마치 별도의 OS에서 돌아가는 것 같은 사적(Private)인 뷰를 만들어줌.
+ 환경별 차이점: 리눅스에서는 호스트 커널을 직접 공유하지만, macOS나 Windows는 리눅스 커널이 없음. 따라서 Docker Desktop은 내부적으로 아주 가벼운 리눅스 VM을 실행하고, 컨테이너들이 그 VM의 커널을 공유하도록 설계되어 있음.
4. 비유로 이해하는 핵심 개념 (아파트, 붕어빵, 그리고 항구)
🏢 아파트 비유 (독립된 서비스 격리)
컴퓨터 한 대를 하나의 '아파트 건물'이라고 가정해 보자. 컨테이너는 각각의 '개별 호실'이다.
- 101호(Web Server), 102호(Database), 103호(Redis Cache)는 같은 아파트(호스트 OS)에 살지만, 서로의 생활 공간은 철저히 분리되어 있음. 한 집에서 파티를 열어도(부하 발생) 옆집에는 영향을 주지 않는 독립된 환경을 의미함.
🐟 붕어빵 비유 (이미지와 컨테이너의 관계)
- 이미지(Image): 붕어빵을 굽기 위한 '틀'이자 '레시피'. 프로그램과 설정이 겹겹이 쌓인(Layered) 정적인 파일. 레이어 구조 덕분에 변경된 부분만 다시 쌓으면 되어 매우 효율적임.
- 컨테이너(Container): 틀에서 구워져 나온 실제 '붕어빵'. 이미지를 실행하여 메모리 위에서 살아 움직이는 인스턴스 상태를 뜻함. 하나의 이미지(틀)로 수많은 컨테이너(붕어빵)를 찍어낼 수 있음.
⚓ 물류 컨테이너와 크레인 (표준화된 플랫폼)
- 컨테이너: 규격화된 '해상 화물 컨테이너'. 내용물이 무엇이든 규격이 일정해 어떤 배나 트럭에도 실을 수 있듯, 소프트웨어를 어디서나 똑같이 실행되도록 표준화한 단위임.
- 도커(Docker): 이 컨테이너를 만들고, 배포하고, 관리하는 '항만 시스템과 종합 크레인' 역할을 하는 플랫폼.
5. 도커(Docker)의 구성 요소와 작동 원리
도커는 컨테이너 기술을 누구나 쉽게 다룰 수 있게 표준화한 플랫폼으로, 클라이언트-서버(Client-Server) 구조로 동작한다.
[ 도커의 핵심 3요소 ]
- Docker Engine (Server): 호스트 OS 위에서 실제로 이미지 빌드, 컨테이너 생성 및 구동을 담당하는 핵심 엔진(Daemon).
- Docker CLI (Client): 사용자가 터미널에 명령어를 입력하여 도커 엔진과 소통하는 창구.
- Docker Hub (Registry): 전 세계의 공식 이미지가 저장된 중앙 저장소. pull을 통해 이미지를 내려받고, push를 통해 공유함.

⚙️ 이미지 생성 및 실행 흐름
도커를 통한 애플리케이션 배포는 다음과 같은 표준 흐름을 따른다.
[Dockerfile] --(build)--> [Docker Image] --(run)--> [Container]
(설계도 작성) (정적 패키징) (격리 실행)
6. 꼭 알아야 할 도커 핵심 명령어
아래는 도커를 이용할 때 자주 사용되는 필수 명령어이다.
| 순서 | 명령어 | 기능 설명 |
| 1 | docker pull [이미지명] | Docker Hub 레지스트리에서 이미지를 로컬로 내려받음 |
| 2 | docker images | 현재 내 컴퓨터(로컬)에 저장된 이미지 목록을 확인 |
| 3 | docker run [이미지명] | 이미지를 컨테이너로 실행 (로컬에 이미지가 없으면 자동으로 pull 수행) |
| 4 | docker ps | 현재 실행 중인 컨테이너 목록 확인 (전체 목록은 -a) |
| 5 | docker stop [ID/명칭] | 실행 중인 컨테이너를 안전하게 중지 |
| 6 | docker rm [ID/명칭] | 정지된 컨테이너 삭제 |
| 7 | docker rmi [이미지명] | 로컬에 저장된 이미지 삭제 |
💡docker run -i -t는 뭐죠? 컨테이너 실행 시 -i(interactive)와 -t(tty) 플래그를 함께 사용하면, 컨테이너 내부의 터미널(예: /bin/bash)로 진입하여 키보드 입력을 전달하고 실행 로그를 실시간으로 확인할 수 있음
7. 컨테이너로 바뀐 개발 환경
도커와 컨테이너의 도입은 현대 소프트웨어 공학의 표준이 되었다. 이를 통해 얻을 수 있는 가치는 명확하다.
- 일관된 배포: "내 컴퓨터에선 되는데?"라는 논쟁을 종결하고, 개발부터 운영까지 동일한 환경을 유지.
- 자원 효율성: 불필요한 OS 부팅 없이 필요한 앱만 가볍게 실행하여 하드웨어 성능을 극대화.
- 신속한 확장성: 동일 이미지를 기반으로 여러 컨테이너를 즉시 생성할 수 있어, 갑작스러운 사용자 증가에도 유연하게 대응 가능.
'4-1. 2026-2 심화 스터디 > 컨테이너 보안' 카테고리의 다른 글
| 컨테이너 보안 3주차 (ft. 이미지부터 차근차근) (0) | 2026.10.02 |
|---|