본문 바로가기

4-1. 2026-2 심화 스터디/컨테이너 보안

컨테이너 보안 2주차 (ft. 내 컴퓨터에서는 되는데?)

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요소 ]

  1. Docker Engine (Server): 호스트 OS 위에서 실제로 이미지 빌드, 컨테이너 생성 및 구동을 담당하는 핵심 엔진(Daemon).
  2. Docker CLI (Client): 사용자가 터미널에 명령어를 입력하여 도커 엔진과 소통하는 창구.
  3. 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 부팅 없이 필요한 앱만 가볍게 실행하여 하드웨어 성능을 극대화.
  • 신속한 확장성: 동일 이미지를 기반으로 여러 컨테이너를 즉시 생성할 수 있어, 갑작스러운 사용자 증가에도 유연하게 대응 가능.