Context
현재 mini-container/main.go의 child()는 mount namespace를 만든 뒤 chroot로 rootfs를 바꾼다.
must(syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, ""))
must(syscall.Chroot("/home/vanillab/container/rootfs"))
must(os.Chdir("/"))
이 방식은 프로세스의 path lookup 기준만 새 rootfs로 제한한다. 하지만 mount namespace의 root mount 자체를 새 rootfs로 교체하지 않고, 기존 root mount를 명시적으로 밀어내거나 unmount하는 흐름도 없다.
그 결과 이 코드는 실제 컨테이너 런타임의 rootfs 전환 모델을 제대로 표현하지 못한다. 특히 old root를 어디에 둘지, 언제 분리할지, /proc 같은 pseudo filesystem을 새 root 기준으로 언제 mount해야 하는지 같은 핵심 lifecycle이 코드에 드러나지 않는다.
따라서 rootfs 전환을 pivot_root 기반으로 바꿔서 새 rootfs를 mount namespace의 실제 /로 만들고, 이전 root를 컨테이너 내부에서 분리하는 흐름을 명시해야 한다.
Goal
컨테이너 child 프로세스가 chroot 대신 pivot_root로 rootfs를 전환한다.
완료 후에는 컨테이너 내부의 /가 새 rootfs mount를 기준으로 동작하고, 이전 host root는 컨테이너 내부에서 접근 가능한 mount로 남지 않아야 한다.
Scope
mini-container/main.go의 rootfs 전환 흐름을 pivot_root 기반으로 바꾼다.
- 새 rootfs가 mount point가 되도록 bind mount 단계를 추가한다.
- old root를 둘 디렉터리를 새 rootfs 내부에 만들고
pivot_root(newRoot, putOld)를 호출한다.
pivot_root 이후 /로 이동한다.
- old root를 lazy unmount하고 임시 디렉터리를 제거한다.
/proc mount는 새 root 전환 이후에 수행한다.
- rootfs 경로 하드코딩 문제는 이 이슈에서 다루지 않는다.
Acceptance Criteria
child() 흐름에서 syscall.Chroot(...)를 사용하지 않는다.
pivot_root 호출 전 새 rootfs가 mount point로 준비된다.
pivot_root 이후 old root가 컨테이너 내부에서 접근 가능한 mount로 남지 않는다.
- 컨테이너 내부에서
pwd, mount, ls / 등으로 새 rootfs 기준의 /를 확인할 수 있다.
/proc이 컨테이너 rootfs 안에서 정상적으로 mount된다.
- 변경 후
go test ./...가 통과한다.
Notes
구현하면서 확인해야 할 핵심은 chroot와 pivot_root의 API 차이가 아니라, rootfs 전환 lifecycle의 차이다.
chroot는 root path를 바꾸지만 mount tree의 root를 교체하지 않는다.
pivot_root는 mount namespace 안에서 새 root와 old root의 위치를 재배치한다.
- old root를 unmount하지 않으면 컨테이너 내부에 host root로 이어지는 mount가 남을 수 있다.
/proc은 rootfs 전환 후 새 /proc 위치에 mount되어야 한다.
Context
현재
mini-container/main.go의child()는 mount namespace를 만든 뒤chroot로 rootfs를 바꾼다.이 방식은 프로세스의 path lookup 기준만 새 rootfs로 제한한다. 하지만 mount namespace의 root mount 자체를 새 rootfs로 교체하지 않고, 기존 root mount를 명시적으로 밀어내거나 unmount하는 흐름도 없다.
그 결과 이 코드는 실제 컨테이너 런타임의 rootfs 전환 모델을 제대로 표현하지 못한다. 특히 old root를 어디에 둘지, 언제 분리할지,
/proc같은 pseudo filesystem을 새 root 기준으로 언제 mount해야 하는지 같은 핵심 lifecycle이 코드에 드러나지 않는다.따라서 rootfs 전환을
pivot_root기반으로 바꿔서 새 rootfs를 mount namespace의 실제/로 만들고, 이전 root를 컨테이너 내부에서 분리하는 흐름을 명시해야 한다.Goal
컨테이너 child 프로세스가
chroot대신pivot_root로 rootfs를 전환한다.완료 후에는 컨테이너 내부의
/가 새 rootfs mount를 기준으로 동작하고, 이전 host root는 컨테이너 내부에서 접근 가능한 mount로 남지 않아야 한다.Scope
mini-container/main.go의 rootfs 전환 흐름을pivot_root기반으로 바꾼다.pivot_root(newRoot, putOld)를 호출한다.pivot_root이후/로 이동한다./procmount는 새 root 전환 이후에 수행한다.Acceptance Criteria
child()흐름에서syscall.Chroot(...)를 사용하지 않는다.pivot_root호출 전 새 rootfs가 mount point로 준비된다.pivot_root이후 old root가 컨테이너 내부에서 접근 가능한 mount로 남지 않는다.pwd,mount,ls /등으로 새 rootfs 기준의/를 확인할 수 있다./proc이 컨테이너 rootfs 안에서 정상적으로 mount된다.go test ./...가 통과한다.Notes
구현하면서 확인해야 할 핵심은
chroot와pivot_root의 API 차이가 아니라, rootfs 전환 lifecycle의 차이다.chroot는 root path를 바꾸지만 mount tree의 root를 교체하지 않는다.pivot_root는 mount namespace 안에서 새 root와 old root의 위치를 재배치한다./proc은 rootfs 전환 후 새/proc위치에 mount되어야 한다.