최소 컨테이너 런타임 완성
·
컨테이너/기초개념
최소 컨테이너 런타임 완성1주차부터 6주차까지, namespace 기초부터 시작해서 mount 격리, cgroup 리소스 제한, 네트워킹, OverlayFS, 그리고 이번 주 lifecycle 관리까지 붙이면서 "동작하는 최소 컨테이너 런타임" 하나를 완성했다. 이번 글에서는 지금까지 만든 게 정확히 뭘 할 수 있는지, 그리고 전체 기능을 이어서 돌려본 통합 테스트 결과를 정리한다.지금까지 쌓아온 것1주차: UTS/PID namespace로 hostname과 PID 격리2주차: pivot_root로 rootfs 격리 (chroot의 한계를 직접 탈출해보며 확인)3주차: cgroup v2로 memory/cpu/pids 제한4주차: veth + bridge + NAT로 컨테이너 네트워킹5주차: Overlay..
docker exec는 내부적으로 어떻게 동작하는가
·
컨테이너/기초개념
docker exec는 내부적으로 어떻게 동작하는가docker exec는 이미 떠 있는 컨테이너 안에 들어가서 명령을 실행하는, 아주 자주 쓰는 명령이다. 그런데 막상 "내부적으로 뭘 하는 거야?"라고 물으면 선뜻 답하기 어려웠다. 이번 주 직접 mycontainer_exec를 만들어보면서 정리한 내용을 적어본다. 왜 새 컨테이너를 하나 더 띄우면 안 되는가가장 먼저 든 의문은 이거였다. "그냥 clone()으로 새 프로세스를 하나 더 만들면 안 되나?"안 된다. clone()으로 완전히 새로운 namespace를 만들면, 그건 새 컨테이너를 하나 더 만드는 것이지 기존 컨테이너에 들어가는 게 아니다. 예를 들어 컨테이너 안에서 nginx가 어떤 파일을 서빙하고 있을 때, 새 namespace를 만들어서..
container state
·
컨테이너/기초개념
483718: state 파일에 적힌 원래 컨테이너의 PID (컨테이너 안 /bin/sh 또는 bash)483771: 아마 mycontainer_exec로 만든 자식(방금 들어간 셸)483717: mycontainer_run.c의 main()(관리자 프로세스) 자신. — join_cgroup()을 clone() 이전에 호출해서 관리자 프로세스 자신도 같은 cgroup에 들어가 있고, waitpid()로 블로킹 중이라 아직 살아있음. namespace483718 (원래 컨테이너)483771 (exec)결과mnt40265325584026532558동일 — mount namespace 재진입 성공net40265322844026532284동일 — network namespace 재진입 성공pid40265..
mycontainer CLI (overlayfs + usernamespace)
·
컨테이너/기초개념
이번 글은 mycontainer run CLI 하나로 통합하면서 겪은 과정을 정리한다. 결과부터 말하면, 하루 종일 걸렸고 가설을 최소 여섯 번은 세우고 틀렸다. 그 과정을 그대로 남긴다. 기존 코드에 무엇을 끼워 넣어야 했나이전 주차에 이미 pivot_root_container.c(cgroup 합류, netns 전환, pivot_root)와 run_container.sh(cgroup/네트워크 준비)를 만들어뒀다. 이번 목표는 여기에 두 가지를 새로 끼워 넣는 것이었다.overlay 마운트 (lower+upper+work → merged)user namespace 격리 (uid_map 매핑, 낮은 권한으로 root 흉내)문제는 순서였다. clone()으로 새 namespace를 만드는 자식은, 자기 자신..
OverlayFS + User Namespace 결합
·
컨테이너/기초개념
가설user namespace 안에서 CAP_SYS_ADMIN을 실질적으로 갖고 있다고 해도, 그 권한이 통하려면 "지금 조작하려는 mount namespace를, 지금 이 user namespace가 소유하고 있어야" 한다. --mount를 추가해서 mount namespace까지 새로 만들면, 그 새 mount namespace의 소유자가 바로 지금 만든 user namespace가 되니까, 이번엔 overlay 마운트도 가능해야 한다는 가설을 세웠다. 첫 시도 — AppArmor에 막히다 가설을 확인해보기도 전에 다른 데서 막혔다. 원인을 좁혀봤다. unprivileged_userns_clone은 1이라 일반 유저의 user namespace 생성 자체는 허용되어 있었다. 근데 apparmor..
user namespace
·
컨테이너/기초개념
namespace 안에서 나는 누구인가아무 매핑 없이 새 user namespace를 만들어보면 이렇게 나온다. nobody(65534)는 리눅스가 "이 UID를 어떻게 번역해야 할지 모르겠다"고 판단할 때 쓰는 안전한 기본값(overflow uid)이다. user namespace를 새로 만들면, 그 namespace의 uid_map(번역표)이 처음엔 텅 비어있다. 매핑표가 없으니 커널은 이 프로세스가 자기 자신을 namespace 관점에서 뭐라고 불러야 할지 계산을 못 하고, 그냥 nobody로 처리해버린다.여기서 흥미로운 건 이 상태를 바깥(호스트)에서 보면 다르게 보인다는 점이다. namespace 안에서 id를 치면 nobody인데, 호스트에서 ps로 같은 프로세스를 보면 dev로 나온다. ..