Im Changsu
컨테이너 톺아보기
컨테이너 관련 자료 모음

거두절미

생각보다 컨테이너는 간단한 게 아닙니다. 컨테이너를 쉽게 생성하고 삭제할 수 있었던 이유는 도커와 같은 컨테이너 관리 도구가 복잡한 것들을 꽁꽁 감췄기 때문입니다. 컨테이너를 공부하면 할수록 알아야 할 게 더 늘어나고 있지만 이쯤에서 유익했던 자료들을 모아 보려 합니다.

참고 자료

리눅스 컨테이너

“A Linux container is a set of 1 or more processes that are isolated from the rest of the system.” Red Hat

리눅스 컨테이너(Linux Container)는 시스템의 다른 부분과 격리된 하나 이상의 프로세스 집합입니다. 즉, 어떤 응용 프로그램이나 프로세스를 일컫는 것이 아니라 그저 리눅스 자원이 격리된 것입니다(‼️).

user-space-vs-kernel-space-simple-container

출처: 레드햇 블로그 “Architecting Containers Part 1: Why Understanding User Space vs. Kernel Space Matters” - Scott McCarty (fatherlinux)

user-space-vs-kernel-space-virtualization-vs-containerization

출처: 레드햇 블로그 “Architecting Containers Part 2: Why the User Space Matters” - Scott McCarty (fatherlinux)

컨테이너 엔진

컨테이너 엔진(Container Engine)은 컨테이너를 관리하기 위한 API나 CLI 도구를 제공하는 소프트웨어입니다. 도커 엔진(docker-ce)부터 레드햇의 파드맨(Podman), 로켓 컴퍼니의 rkt 등이 컨테이너 엔진에 해당합니다. 컨테이너 엔진은 사용자 입력을 받고, 컨테이너 이미지를 꺼내고(pull), 컨테이너 실행 방법을 명시한 메타데이터를 만든 다음, 컨테이너 런타임에 이 정보들을 전달합니다.

컨테이너 런타임

컨테이너 런타임(Container Runtime)은 루트 파일시스템과 메타 데이터(spec file)를 받아 컨테이너를 실행하는 도구입니다. 가장 일반적으로 쓰이는 런타임은 OCI를 준수하는 runC입니다. 흔히 쓰이는 컨테이너-디 (containerd), 크라이-오 (cri-o)도 실제로는 runC에 의존합니다.

docker-containerd-runc

출처: Docker Leads OCI Release of v1.0 Runtime and Image Format Specifications

최근 쿠버네티스 블로그에 업로드된 Dockershim 제거에 대한 글12로 도커를 못 쓰게 된 건지 혼란이 있었습니다. 도커가 워낙 만능이다보니 “컨테이너 엔진==컨테이너 런타임==CRI==도커"라는 오해에서 비롯되었습니다. 자세한 내용은 서비큐라님 글, 조훈님과 심근우님 글을 참고해주세요.

simple-orchestration-node

출처: Linux Container Internals - Scott McCarty

컨테이너 오케스트레이션

컨테이너 오케스트레이션(Container Orchestration)은 컨테이너 배포, 관리, 확장, 네트워킹 등을 자동화합니다. 대표적으로 CNCF에서 관리하고 있는 쿠버네티스가 있습니다.

컨테이너를 만드는 리눅스 커널 기능

처음에는 리눅스 커널까지 깊게 알아야 하나 싶었는데 사라진 메모리를 찾아가는 Luavis님 글을 읽어보니 반드시 알아야겠더라구요. 대표적으로 쓰이는 리눅스 커널 기능은 네임스페이스와 컨트롤 그룹 등이 있습니다.

docker-with-linux-kernel

출처: educative

네임스페이스: What you can see

리눅스 네임스페이스(Namespace)는 프로세스 실행 시 시스템 자원을 격리시켜주는 기능입니다.

namespaces(7)

  • 네임스페이스 유형
네임스페이스 플래그 경로 매뉴얼 격리 대상
Cgroup CLONE_NEWCGROUP /proc/[pid]/ns/cgroup cgroup_namespaces(7) Cgroup root directory
IPC CLONE_NEWIPC /proc/[pid]/ns/ipc ipc_namespaces(7) System V IPC, POSIX message queues
Network CLONE_NEWNET /proc/[pid]/ns/net network_namespaces(7) Network devices, stacks, ports, etc.
Mount CLONE_NEWNS /proc/[pid]/ns/mnt mount_namespaces(7) Mount points
PID CLONE_NEWPID /proc/[pid]/ns/pid, /proc/[pid]/ns/pid_for_children pid_namespaces(7) Process IDs
Time CLONE_NEWTIME /proc/[pid]/ns/time, /proc/[pid]/ns/time_for_children time_namespaces(7) Boot and monotonic clocks
User CLONE_NEWUSER /proc/[pid]/ns/user user_namespaces(7) User and group IDs
UTS (UNIX Time Sharing) CLONE_NEWUTS /proc/[pid]/ns/uts uts_namespaces(7) Hostname and NIS domain name
  • 네임스페이스 관련 API
시스템 호출 설명
clone 새로운 자식 프로세스를 생성합니다. 위의 표에서 CLONE_NEW* 플래그를 인수로 지정합니다.
setns 시스템 호출한 프로세스가 /proc/[pid]/ns를 참조해 기존 네임스페이스에 할당됩니다.
unshare 시스템 호출한 프로세스가 새로운 네임스페이스에 할당됩니다. 마찬가지로 CLONE_NEW* 플래그를 인수로 지정합니다.
ioctl 네임스페이스 관련 정보를 찾기 위한 다양한 기능을 제공합니다. 기본적으로 디바이스 제어 API입니다.

컨트롤 그룹: What you can use

보통 씨-그룹이나 컨트롤-그룹이라고 발음합니다.

컨트롤 그룹(cgroup, control group)은 프로세스에서 사용 가능한 CPU, 메모리, 네트워크 대역폭, 디스크 I/O 등을 그룹 단위로 제어하는 리눅스 커널의 기능입니다. 원래는 프로세스 컨테이너라는 이름으로 제안되었지만, 나중에 컨트롤 그룹이 되었습니다. 컨트롤 그룹은 컨테이너에서만 사용되는 기능은 아니고 리눅스 시스템에서 프로세스 관리를 위해 일반적으로 사용되고 있습니다.

Control Group 드라이버

  • cgroupfs
  • systemd
sudo docker info -f '{{json .}}' | jq '. | .CgroupDriver'
# "cgroupfs"

cgroupfs (컨트롤 그룹 파일 시스템)

tasks attach a task(thread) and show list of threads
cgroup.procs show list of processes
cgroup.event_control an interface for event_fd()
memory.stat show various statistics
memory.limit_in_bytes set/show limit of memory usage
memory.usage_in_bytes show current usage for memory (See 5.5 for details)
memory.max_usage_in_bytes show max memory usage recorded
memory.numa_stat show the number of memory usage per numa node
memory.kmem.tcp.max_usage_in_bytes show max tcp buf memory usage recorded

Control Group v1 컨트롤러

컨트롤러 커널 설정 옵션 설명
blkio CONFIG_BLK_CGROUP 블록 IO 제어
cpuacct CONFIG_CGROUP_CPUACCT 프로세스 그룹 CPU 사용량 계산
cpuset CONFIG_CPUSETS 특정 CPU나 NUMA 노드 할당
devices CONFIG_CGROUP_DEVICE mknod를 통해 디바이스를 관리할 수 있는지 결정
freezer CONFIG_CGROUP_FREEZER 프로세스 일시 정지-재개
memory CONFIG_MEMCG 사용중인 프로세스 메모리, 커널 메모리, 스왑 메모리 관리
net_cls CONFIG_CGROUP_NET_CLASSID 트래픽 제어에 쓰이는 classid 관리
net_prio CONFIG_CGROUP_NET_PRIO 네트워크 인터페이스 우선순위(priorities) 관리
pids CONFIG_CGROUP_PIDS 생성할 수 있는 프로세스 수 관리

Control Group v2

cgroups v2가 Linux 커널 4.5부터 공식적으로 포함되었습니다. 자세한 내용은 Akihiro Suda의 글커널 문서를 참고해주세요.

루트 파일시스템

루트 파일시스템(Root File System)이란 ramfstmpfs의 특수 인스턴스로 루트 디렉토리(/)에 마운트되는 파일 시스템을 말합니다. rootfs은 커널이 동작하기 위한 필수 파일들이 있기 때문에 마운트를 해제할 수 없습니다. chrootpivot_root 명령어로 rootfs 경로를 변경(chroot jail)하여 파일 시스템을 격리할 수 있습니다.

유니온 마운트

유니온 마운트(Union Mount)란 여러 파일 시스템을 단일 포인트로 마운트하는 것을 말합니다. 컨테이너에 필수적인 기능은 아니지만 이미지 레이어 구현에 사용되면서 필수적인 기능으로 자리잡았습니다. 예를 들면 도커가 사용하는 AUFS, OverlayFS 등이 있습니다.

aufs

출처: Use the AUFS storage driver - docker docs

overlay-constructs

출처: Use the OverlayFS storage driver - docker docs

리눅스 캐퍼빌리티

POSIX capabilities 개념으로 루트 프로세스 권한을 세부적으로 제어하기 위한 속성입니다. ‘자격’, ‘능력’ 등으로 번역됩니다.

캐퍼빌리티가 없을 때 프로세스는 두 가지로만 나뉘었습니다.

  • (User ID가 0인, superuser라 불리는) 루트 사용자가 소유한 특권(privileged) 프로세스
  • (User ID가 0이 아닌) 일반 사용자가 소유한 비특권(unprivileged) 프로세스.

이 중 루트 권한을 세분화해서 프로세스마다 다르게 적용할 수 있도록 만든 기능이 바로 리눅스 캐퍼빌리티입니다. 컨테이너 런타임에서 루트 권한 일부분만 필요할 경우 리눅스 캐퍼빌리티를 사용합니다.

샌드박싱 솔루션

샌드박싱이란? 자원 접근이 제한되도록 응용 프로그램을 격리하는 것 - <컨테이너 보안> 참조

  • seccomp
  • AppArmor
  • SELinux

  1. Don’t Panic: Kubernetes and Docker ↩︎

  2. Dockershim Deprecation FAQ ↩︎