LabHub

컨테이너 내부 원리 · 네임스페이스 — 무엇을 볼 수 있는가 · 실습

네임스페이스를 눈으로 확인하기

LabHub 에서 이어서 보기

이 실습은 진짜 VM 에서 돕니다

이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker execdocker logs 도 그대로 동작합니다.

예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라
컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어
보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.

알아 둘 것이 둘 있습니다.

목표

네임스페이스 7종 중 pid, uts, mnt, net, user 다섯 가지를 직접 재어 보고, 컨테이너가
'상자'가 아니라 시야가 제한된 평범한 프로세스라는 것을 inode 번호로 증명합니다.
마지막에는 컨테이너 둘이 네트워크 네임스페이스를 공유하는 쿠버네티스 파드 구조를
도커만으로 재현합니다.

왜 중요한가

컨테이너 트러블슈팅이 막히는 지점은 대부분 "이건 분리된 건가 아닌가"를 몰라서
생깁니다. 포트가 왜 충돌하는지, 컨테이너 안에서 본 파일이 호스트 어디에 있는지,
사이드카가 왜 localhost 로 앱에 붙는지 — 답은 전부 "그 자원이 어느 네임스페이스에
속하는가" 한 줄입니다. 네임스페이스에는 inode 번호가 붙고 /proc/<pid>/ns/*
읽을 수 있으므로, 이 질문은 추측이 아니라 측정으로 답할 수 있습니다.
같은 번호면 같은 네임스페이스, 다른 번호면 다른 네임스페이스. 그게 전부입니다.

단계

1. /root/int1 디렉터리를 만들고, 호스트에서 /proc/self/ns/pid 링크가 가리키는 값을 /root/int1/host-pid-ns.txt 에 저장합니다. 파일 내용은 pid:[숫자] 한 줄이어야 합니다.
2. alpine:3.20 이미지로 dk-ns 라는 이름의 컨테이너를 --hostname labhub-uts 를 붙여 sleep infinity 로 백그라운드 실행하고, 그 컨테이너 안에서 읽은 /proc/self/ns/pid 값을 /root/int1/ctr-pid-ns.txt 에 저장합니다. 1단계 값과 달라야 합니다.
3. dk-ns 안에서 프로세스 목록을 PID 열이 보이는 형식으로 뽑아 /root/int1/pid1.txt 에 저장합니다 (docker exec dk-ns ps -o pid,comm). PID 1 이 sleep — 그 컨테이너를 띄울 때 준 명령 — 이어야 합니다. systemd 도 init 도 아니라는 것이 요점입니다. 이 VM 에서 그냥 ps -e 를 하면 PID 1 은 systemd 라서 대조가 됩니다.
4. dk-ns 의 호스트명을 /root/int1/uts.txt 에 저장합니다. 내용은 labhub-uts 한 줄이어야 합니다.
5. 이 상자의 /etc/os-release 와 alpine 이미지 쪽 /etc/os-release한 파일에 이어서 /root/int1/mnt-proof.txt 에 저장합니다. 파일 안에 호스트 쪽 ubuntu 와 컨테이너 쪽 alpine 이 둘 다 보여야 합니다.
docker run --rm alpine:3.20 cat /etc/os-release 와 이 VM 의 같은 파일을 한 파일에 이어 붙이면 됩니다. 함께 uname -r 도 찍어 보세요 — 커널은 같고 파일 트리만 다릅니다. 마운트 네임스페이스가 하는 일이 결국 프로세스의 / 를 다른 트리로 바꿔치는 것뿐이라는 사실이 그 두 줄에 들어 있습니다.
6. dk-ns 안에서 읽은 /proc/net/dev/root/int1/ctr-net.txt 에 저장합니다. lo: 줄이 있어야 하고, 호스트의 같은 파일과 내용이 달라야 합니다 — 인터페이스 구성과 송수신 통계는 네임스페이스마다 따로 관리됩니다.
7. dk-ns 의 네트워크 네임스페이스에 합류하는 dk-sidecar 컨테이너를 백그라운드로 띄우고, dk-ns 안에서 읽은 /proc/self/ns/net/root/int1/ns-a.txt 에, dk-sidecar 안에서 읽은 같은 값을 /root/int1/ns-b.txt 에 저장합니다. 두 값은 net:[숫자] 형식이면서 서로 같아야 합니다.
8. 호스트의 /proc/self/uid_map/root/int1/host-uidmap.txt 에, dk-ns 안의 /proc/self/uid_map/root/int1/ctr-uidmap.txt 에 저장합니다. 두 매핑 내용이 서로 달라야 합니다.

참고

단계 8개

  1. 호스트의 PID 네임스페이스 식별자 읽기
  2. 컨테이너의 PID 네임스페이스와 비교
  3. 컨테이너 안의 PID 1 확인
  4. UTS 네임스페이스로 분리된 호스트명
  5. 마운트 네임스페이스 — 같은 커널, 다른 파일 트리
  6. 네트워크 네임스페이스의 인터페이스 목록
  7. 두 컨테이너가 네임스페이스를 공유하게 하기
  8. 유저 네임스페이스의 UID 매핑