플랫폼, 데브옵스와 클라우드

컨테이너 런타임과 보안

meellon 2026. 6. 21. 07:00

학습 목표

Docker CLIcontainerd·runcOCI 런타임 계층을 설명할 수 있다.

Linux namespacecgroup이 격리·자원 제한에 어떻게 쓰이는지 설명할 수 있다.

capabilities, rootless, 최소 권한 이미지로 공격 면을 줄이는 방법을 설명할 수 있다.

컨테이너가 VM만큼 격리되지 않는다는 전제에서 보안을 설계할 수 있다.

문제 상황

  • docker run 한 줄이면 되는데, 컨테이너 안 프로세스가 호스트와 뭐가 다른지 모른다
    • ps를 호스트에서 보면 컨테이너 PID도 보인다
  • --privileged로 문제를 풀었다가 호스트 탈출 이슈를 본다
    • 컨테이너 = 가벼운 VM이 아니다
  • 이미지가 root로 돌고, latest 베이스에 쓸데없는 패키지가 잔뜩
    • CVE 스캔할 때마다 수백 건 경고
  • 메모리 제한 없이 배포했다가 OOM으로 노드 전체가 흔들린다

Dockerfile·run 옵션을 봤다. 이번 편은 엔진 아래—커널이 프로세스를 어떻게 감싸는지와 보안 기본값이다.

1. OCI 런타임 스택

docker run은 단일 바이너리가 아니다. 이미지 풀 → 스냅샷 → 프로세스 생성을 여러 계층이 나눈다.

계층 역할
Docker CLI 사용자 명령 (run, build, push)
dockerd API, 이미지·네트워크·볼륨 관리
containerd 컨테이너 생명주기, 이미지 레이어 스냅샷
runc (OCI runtime) config.json대로 namespace·cgroup 설정 후 프로세스 exec
Linux kernel 실제 격리·자원 제한
  • Kubernetes도 노드에서 containerd/CRI-O + runc 조합이 흔하다
  • 표준은 OCI (Open Container Initiative) — 이미지·런타임 스펙

2. Namespace — 무엇을 가리는가

Namespace는 프로세스가 보는 시스템 뷰를 분리한다. OS 시리즈의 프로세스·주소 공간과 같은 축.

Namespace 격리 대상 컨테이너에서
PID 프로세스 ID 컨테이너 안 PID 1 = 앱, 호스트 PID는 다름
NET 네트워크 스택 자체 eth0, IP, 포트 공간
MNT 마운트 트리 이미지 레이어 + writable layer
UTS hostname --hostname
IPC 공유 메모리·세마포어 컨테이너 간 기본 분리
USER UID/GID 매핑 rootless·user namespace
  • 격리는 분리 — 커널은 공유
  • --privileged는 대부분의 namespace·device 제한을 풀어버림 → 최후 수단

3. Cgroup — 자원 한도

Cgroup은 CPU·메모리·I/O 등 사용량 상한과 accounting.

docker run -d --memory=512m --cpus=1.5 my-app:1.0
리소스 옵션 예 없을 때
메모리 --memory, --memory-swap 호스트 RAM까지 사용 → OOM
CPU --cpus, --cpu-shares 호스트 CPU 독점 가능
PID --pids-limit fork bomb에 취약
  • K8s의 requests/limits도 결국 cgroup으로 적용
  • limit만 주고 request 없으면 스케줄링·노이즈 이웃 문제 (K8s 편에서 확장)

4. Capabilities와 root

Linux root는 모든 권한. 컨테이너는 기본적으로 일부 capability만 부여한다.

기법 설명
Drop capabilities NET_BIND_SERVICE만 필요하면 나머지 제거
Non-root user Dockerfile USER app — 파일·소켓 권한 설계 필요
Read-only rootfs docker run --read-only + tmpfs for /tmp
seccomp / AppArmor syscall·프로파일 제한 (엔진 기본 프로파일)
Minimal base image distroless, alpine — 공격 면 축소
FROM python:3.12-slim
RUN useradd -m app
USER app
WORKDIR /home/app
COPY --chown=app:app . .
CMD ["python", "main.py"]
  • root 컨테이너 + 취약점 = 호스트 침해 가능성 상승
  • --privileged, hostPID, hostNetwork의도적 예외

5. Rootless Docker

Rootless — 데몬·컨테이너가 비 root 사용자로 동작. user namespace로 컨테이너 root를 unprivileged UID에 매핑.

  일반 모드 Rootless
데몬 root 일반 사용자
컨테이너 내 root 실제 root에 가까움 user ns 매핑
포트 1024 미만 허용(권한 있으면) 추가 설정 필요
  • 개발·CI 워크스테이션에서 호스트 보호에 유리
  • 프로덕션은 보통 rootful 노드 + Pod Security (K8s)로 정책화

6. 이미지·공급망 보안

  • 고정 태그python:3.12-slim 또는 digest pin
  • 멀티 스테이지 — 빌드 도구를 런타임 이미지에 넣지 않음
  • 스캔 — Trivy, Docker Scout 등으로 CVE 확인
  • 서명 — cosign 등으로 이미지 출처 검증 (CI/CD 편)

컨테이너 보안은 런타임 설정 + 이미지 내용 + 권한 최소화 세 축이다.

7. 정리

  • docker run 끝은 runc + kernel — namespace로 뷰 분리, cgroup으로 자원 제한
  • 컨테이너는 프로세스 격리이지 VM이 아니다 — --privileged 남용 금지
  • capabilities drop, non-root, read-only, 최소 이미지가 기본선
  • 다음은 오케스트레이션 — Kubernetes가 이 단위를 클러스터로 다룬다

다음에 다룰 것

  • Kubernetes 개요
  • control plane, worker, 선언적 API, desired state

해당 내용은 Docker 공식 문서(https://docs.docker.com) 및 OCI runtime-spec 을 기반으로 합니다.

'플랫폼, 데브옵스와 클라우드' 카테고리의 다른 글

Pod와 Deployment  (0) 2026.06.23
Kubernetes 개요  (0) 2026.06.22
Docker 기초  (0) 2026.06.20
컨테이너란 무엇인가  (0) 2026.06.19
플랫폼 오리엔테이션  (0) 2026.06.18