TT Lab
블로그 시작하기
배우기 러닝패스 코스

리눅스 커널과 eBPF

컨테이너라는 커널 객체는 없다

TT Lab 에서 이어서 보기

한 줄 요약

컨테이너는 네임스페이스(무엇이 보이는가)와 cgroup(얼마나 쓰는가)과 루트 파일시스템(어디가 / 인가)을 한 프로세스에 함께 건 것입니다. 런타임은 이 셋을 한 번에 묶어 주는 도구일 뿐이고, 같은 일을 unshare 와 cgroup 파일로 손으로 할 수 있습니다.

왜 손으로 해 봐야 하나

장애가 나면 "컨테이너" 라는 낱말은 도움이 되지 않습니다. 파드 안에서 프로세스가 하나뿐이면 PID 네임스페이스를, 이름 해석이 안 되면 네트워크 네임스페이스의 resolv.conf 와 경로를, OOMKilled 면 cgroup 을 봐야 합니다. kubectl exec 이 안 될 때 노드에서 nsenter 로 들어가는 것도 네임스페이스를 알아야 할 수 있습니다. 런타임이 무엇을 대신 해 주는지 알면 무엇이 빠졌을 때 어디를 볼지도 알게 됩니다.

어떻게 동작하나

리눅스에는 네임스페이스가 여덟 종류 있습니다. 이 실습은 그중 다섯을 씁니다. uts 는 호스트 이름, ipc 는 System V IPC 와 POSIX 메시지 큐, net 은 장치·주소·라우팅·방화벽, pid 는 프로세스 번호, mnt 는 마운트 목록을 따로 갖게 합니다. 각 네임스페이스는 번호(inode)를 갖고, readlink /proc/<pid>/ns/net 이 net:[4026532461] 처럼 그 번호를 보여 줍니다. 번호가 같으면 같은 네임스페이스입니다.

unshare 는 새 네임스페이스를 만들고 그 안에서 명령을 실행합니다. PID 네임스페이스는 조금 특별해서, unshare 를 부른 프로세스 자신은 옮겨 가지 않고 그 자식이 새 네임스페이스의 PID 1 이 됩니다. 그래서 --fork 가 필요합니다. PID 1 이 죽으면 그 네임스페이스의 나머지 프로세스도 모두 끝납니다.

네임스페이스는 그것을 가리키는 것이 하나라도 있으면 살아 있습니다. 안에서 도는 프로세스, 그것을 연 파일 디스크립터, 그리고 바인드 마운트입니다. unshare --net=/run/x/net 처럼 파일을 주면 새 네임스페이스를 그 파일에 바인드 마운트해서, 프로세스가 끝나도 네임스페이스가 남습니다. ip netns add 가 /run/netns 에 하는 일이 이것입니다. 마운트 네임스페이스를 이렇게 고정하려면 그 파일이 있는 마운트가 shared 전파가 아니어야 합니다. 그래야 고정한 마운트가 다른 곳으로 퍼지며 자기 자신을 가리키는 고리가 생기지 않습니다.

이 실습이 쓰지 않는 두 종류도 알아 두면 좋습니다. user 네임스페이스는 사용자 번호를 바꿔 끼워, 상자 안의 root 가 바깥에서는 권한 없는 사용자가 되게 합니다. rootless 컨테이너가 이것으로 돕니다. cgroup 네임스페이스는 /proc/self/cgroup 이 보여 주는 경로의 뿌리를 바꿔, 상자 안에서 자기 그룹이 / 로 보이게 합니다. 쿠버네티스 파드 안에서 cat /proc/self/cgroup 이 0::/ 로 나오는 이유가 이것입니다.

cgroup 은 네임스페이스와 독립입니다. 상자를 띄운 뒤 그 PID 를 그룹의 cgroup.procs 에 써야 한도가 걸립니다. 루트 파일시스템은 chroot 로 바꿀 수 있지만, 실제 런타임은 옛 루트를 떼어 내는 pivot_root 를 씁니다. chroot 만 하면 root 권한으로 옛 루트로 빠져나갈 길이 남기 때문입니다.

현장에서 만나는 모습

노드에서 파드의 네트워크를 보고 싶으면 컨테이너의 PID 를 찾아 nsenter -t <pid> -n ip addr 을 씁니다. 파드 안에 디버깅 도구가 없어도 호스트의 도구를 그 네임스페이스에서 쓸 수 있습니다. kubectl debug 의 임시 컨테이너도 같은 원리로 대상의 네임스페이스에 들어갑니다.

CNI 플러그인은 파드마다 veth 한 쌍을 만들어 한 끝을 파드의 네트워크 네임스페이스에 넣고 eth0 으로 이름을 바꿉니다. 실습에서 손으로 할 일이 정확히 그것입니다. Cilium 은 그 호스트 쪽 veth 에 BPF 프로그램을 붙입니다. 뒤쪽 XDP 와 tc 단원에서 다시 만납니다.

English corner

메일링 리스트에서 패치를 리뷰할 때 쓰는 말들입니다.

다음 실습에서 할 것

호스트의 네임스페이스 번호를 적고, busybox 로 루트 파일시스템을 짓고, 다섯 네임스페이스를 파일에 고정해 상자를 띄웁니다. cgroup 으로 PID 와 메모리를 묶고, veth 로 바깥과 잇고, nsenter 로 들어가 상자 안의 ps 를 봅니다.