아래 실습은 macOS(v11.1)에서 진행되었습니다.
VirtualBox를 통해 VM을 프로비저닝하기 위해 Vagrant를 설치한다.
# brew를 이용하여 설치
$ brew install --cask vagrant
# 설치 확인
$ vagrant --version
Mac에서 6.1.28
버전 이후에서는 host-only network 사용 대역 제약이 있으니, 6.1.26
버전 사용을 권장한다.
https://download.virtualbox.org/virtualbox/6.1.26/
Vagrant에서는 Vagrantfile을 통해 VM을 프로비저닝하는데, Vagrantfile에는 어떤 box 파일을 사용할 것인지, VM에 대한 하드웨어 설정(CPU,메모리 사이즈,네트워크 등) 등을 정의한다.
Vagrantfile을 프로비저닝 한 후, vagrant ssh 명령어를 통해 접속한다.
| Vagrantfile은 가시다님께서 제공한 것을 사용 🙏
# Ubuntu 배포 관련 Vagrantfile 파일 다운
$ curl -O https://raw.githubusercontent.com/gasida/NDKS/main/1/Ubuntu/Vagrantfile
# vagrant 프로비저닝
$ vagrant up
# Ubuntu SSH 접속
$ vagrant ssh
VM에 접속 후, 계정 정보 및 버전을 확인해본다.
# 현재 사용 계정 정보 확인
$ whoami
# 버전 확인
$ lsb_release -a
설치 후, 프로세스, 네트워크 정보 등을 확인해본다.
# 프로세스 확인
$ ps -ef
# 네트워크 정보 확인
$ ip -c addr
# 이더넷 브리지 정보 확인
$ brctl show
네임스페이스는 프로세스를 실행할 때 시스템의 리소스를 분리해서 실행할 수 있도록 도와주는 기능이다.
단일 네임스페이스에서는 한 시스템의 프로세스들이 기본적으로 시스템의 리소스들을 공유해서 실행된다. 실제로 리눅스에서는 1번 프로세스(init)에 할당되어있는 네임스페이스들을 자식 프로세스들이 모두 공유해서 사용하는 구조로 이루어져있다.
네임스페이스를 살펴보면 아래와 같다.
(O'REILLY - Networking and Kubernetes 책)
위 그림을 보면 Node가 Ubuntu 호스트이고, 파란 네모가 컨테이너를 나타낸다. 그림처럼 UID, PID, NET, IPC의 네임스페이스가 호스트와 격리되어 있는 것을 볼 수 있다.
다양한 네임스페이스 중 PID를 예시로 살펴본다.
PID 네임스페이스는 프로세스의 ID를 격리할 수 있는 네임스페이스이다. 리눅스에서 PID는 init 프로세스 1을 시작하며 그 외에 모든 프로세스는 항상 1보다 큰 PID를 부여받는다.
❓ 만약 컨테이너와 같이 새로운 PID 네임스페이스로 분리하면 어떻게 될까?
👉 PID가 다시 1부터 시작합니다. 단, 이 프로세스는 디폴트 네임스페이스와 분리된 PID 네임스페이스에 동시에 속하게 되며, 분리된 새로운 네임스페이스에서는 PID가 1부터 시작하지만, 디폴트 네임스페이스 관점에서는 어떤 한 프로세스에서 fork되었기 때문에 1보다 큰 PID 값을 가지게 된다.
(https://netpple.github.io/docs/make-container-without-docker/container-internal-2)
pstree -p
명령어를 통해 확인 가능하다.
더 자세한 내용은 여기
# Ubuntu 컨테이너 bash 접속 후 명령어 실행
$ ![](https://velog.velcdn.com/images%2Fdojun527%2Fpost%2Feca517ce-ae3b-4aa6-b9ff-757e1d9106b1%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.58.28.png)
# 현재 bash 쉘의 프로세스 ID
$ ps $$
# 컨테이너 내부의 네임스페이스 정보
$ ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 Jan 12 14:59 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 ipc -> 'ipc:[4026532260]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 mnt -> 'mnt:[4026532258]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 net -> 'net:[4026532263]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 pid -> 'pid:[4026532261]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 pid_for_children -> 'pid:[4026532261]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Jan 12 14:59 uts -> 'uts:[4026532259]'
# 호스트 shell의 네임스페이스 정보
$ ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 Jan 12 15:01 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 net -> 'net:[4026531992]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Jan 12 15:01 uts -> 'uts:[4026531838]'
📍 위의 두 네임스페이스를 비교해보면 ipc,mnt,net,pid,uts가 다른 것을 볼 수 있다. -> 호스트 환경과 격리된 환경이다.
위에서 PID를 봤듯이 컨테이너는 호스트로부터 격리는 되었지만 하나의 프로세스에서 fork되어 생성되었기 때문에, 호스트에서 컨테이너 내의 프로세스에 접근하여 종료할 수 있다.
# 터미널 1(컨테이너) : Ubuntu 컨테이너 bash 접속 후 명령어 실행
$ sleep 1000
# 터미널 2(호스트)
$ ps -C sleep
PID TTY TIME CMD
4912 pts/0 00:00:00 sleep
# 컨테이너 내부에서 실행되고 있는 sleep 프로세스 kill
$ kill -9 4912
컨테이너와 호스트의 네임스페이스를 비교했을 때 Cgroup은 같았는데, 이는 호스트의 커널을 공유해서 사용하기 때문이다.
👉 컨테이너는 하나의 독립적인 운영체제가 아닌, 호스트의 커널을 공유하여 동작하는 리눅스 프로세스이다.
https://www.44bits.io/ko/keyword/linux-namespace
https://www.44bits.io/ko/post/is-docker-container-a-virtual-machine-or-a-process