[Container] 도커없이 컨테이너 만들기 3
전용 루트 파일시스템과 오버레이 파일시스템이 있더라도 문제가 남아 있었다.
컨테이너에서 호스트의 다른 프로세스들이 다 보이고, 컨테이너가 호스트의 네트워크를 여전히 사용하고(80 포트로 nginx에 접속한 것처럼), 컨테이너에 루트 권한이 여전히 있다는 문제다.
그래서 마운트 네임스페이스를 만든 것처럼 다양한 네임스페이스를 만들었다.
모든 프로세스는 타입별로 네임스페이스에 속한다. 자식 프로세스는 부모의 것을 상속한다.
네임스페이스는 unshare [옵션] [프로그램...]으로 사용할 수 있다.
네임스페이스를 확인해볼 수 있다.
마운트를 격리하고 실행해보면 마운트 네임스페이스만 다른 것을 확인할 수 있다.
UTS 네임스페이스
UTS(Unix Time Sharing)는 호스트 네임을 격리하는 거다.
IPC 네임스페이스
IPC(Inter Process Communication)는 IPC를 격리하는 거다. Shared Memory, Semaphore, Message Queue 같은 것. 공유하는 프로세스끼리만 통신할 수 있다고 보면 된다.
PID 네임스페이스
PID(Process ID) 넘버스페이스를 격리한다. 다른 네임스페이스와 좀 다르게 부모 네임스페이스와 자식 네임스페이스의 중첩 구조를 가지는데, 부모는 자식의 PID를 다 볼 수 있다. 자식은 두 개의 PID를 가진다. 자식 네임스페이스에서의 PID와 부모 네임스페이스에서의 PID다.
같은 /bin/sh가 자식 네임스페이스에서는 PID 1, 부모 네임스페이스에서는 PID 1150012
PID 1번은 init 프로세스다. 커널이 생성한다. 커널 프로세스는 커널 레이어에서 0번으로 존재한다. 0이 1을 만들어서 시작한다. 나머지는 모두 1의 자식이다.
1번 프로세스는
- 커널의 시그널을 자식에게 전파하고
- 좀비, 고아 프로세스를 처리한다.
- 1번이 죽으면 커널 패닉이 나서 시스템을 리부트해야 한다.
그럼 컨테이너에서 1번은? 네임스페이스를 격리할 때 다른 것들은 그냥 바로 복사하고 거기에 속하는데, PID ns는 unshare할 때 fork를 해서 자식 프로세스를 1번으로 실행시킨다. 얘는 시그널을 처리하고 좀비·고아를 처리하고, 죽으면 컨테이너를 종료한다. 시그널과 좀비·고아 처리는 구현하는 사람이 만들어 줘야 한다. 1번이 죽으면 컨테이너가 죽는다. 이게 컨테이너 라이프사이클이다.
ps로 나오는 PID는 다르게 보이지만, ns를 찍어보면 같은 것을 확인할 수 있다. 부모인 호스트 프로세스에서는 자식이 보이는 셈이다. 호스트에서 시그널을 보내는 것도 보인다.
네트워크 네임스페이스
네트워크 네임스페이스는 컨테이너 네트워크를 호스트와 격리하고 네트워크를 가상화해준다. 네트워크 가상 장치는 물리 장치를 다루듯 꽂아 줄 수 있다. 어떤 네임스페이스에 있던 가상 네트워크 장치 veth0을 다른 네임스페이스에 꽂아줄 수 있는 셈이다.
가상 인터페이스는 네임스페이스가 삭제될 때 같이 삭제되고, 물리 인터페이스는 기존 네임스페이스로 복원되는 특징이 있다.
네트워크 네임스페이스 RED, BLUE를 추가했다. 가상 veth1 / veth1-peer 두 개를 생성하고 각각의 네임스페이스에 꽂아줬다. 전원을 켜줘야 한단다 ㅋㅋ 호스트에서 각각의 네트워크 네임스페이스에 접속해서 ip를 살펴보면 호스트 / RED / BLUE에서 모두 다른 걸 확인할 수 있다.
RED와 BLUE에서 서로를 향해 핑을 쏴보면 잘 가는 것까지 확인했다.
분산 노드와 여러 컨테이너 간의 통신도 심화로 살펴보면 좋겠다.
USER 네임스페이스
유저 네임스페이스는 UID/GID를 격리하는데, 컨테이너 루트 권한 문제를 해결한다. PID처럼 부모-자식 중첩 구조를 가지는데, 프로세스와 연관되어서 그렇다. 프로세스가 가지고 있는 UID/GID와 사용하려는 파일의 UID/GID를 비교한다.
도커를 일반 계정으로 실행해봤는데, 컨테이너 안에서 계정이 루트로 나온다. 실제 호스트에서 컨테이너 계정을 확인했더니 루트로 나온다. 컨테이너와 호스트의 네임스페이스를 비교했더니 똑같다. 그럼 일반 계정으로 실행한 도커 컨테이너 안의 계정이 실제 호스트의 계정과 같다는 게 된다.
도커는 초창기에 편의를 위해서 이랬다고 한다.
user ns를 격리하면서 실행해봤다. 근데 내 우분투 버전에서는 일반 계정으로는 실행이 안 되길래 루트로 실행했다. 그래서 컨테이너 안이랑 호스트에서 보면 모두 root로 나오긴 하는데, 컨테이너 안의 root는 다른 ns의 루트다.
근데 여기에는 문제가 있다. 호스트의 실행 계정을 컨테이너 안의 root로 매핑해서 주는 건데, 컨테이너 안의 유저가 밖으로 나오면 진짜 루트로 매핑되어 있는 문제다. 우분투 24에서는 따로 설정이 필요한 것 같다.
정리
지금까지 네임스페이스를 정리해보자면
| NS Type | 무엇을 격리하는가 |
|---|---|
| 마운트 네임스페이스 | 마운트 포인트 |
| UTS 네임스페이스 | hostname, domain name |
| IPC 네임스페이스 | IPC |
| PID 네임스페이스 | pid |
| 네트워크 네임스페이스 | 네트워크 스택 & 가상화 |
| USER 네임스페이스 | UID/GID |





