리눅스 namespace 이해하기

junto·2024년 6월 2일
0

docker

목록 보기
1/2
post-thumbnail

컨테이너

컨테이너는 과거 값비싼 서버를 나눠 쓰는 고민에서 출발하여 오랜 기간 동안 리눅스 기술 토대 위에 잘 쌓아 올려져 왔습니다. 이러한 점에서 컨테이너를 공부하는 것은 단순히 새로운 기술을 배우는 것 이상으로 리눅스나 전산 기초를 더 깊이 이해하는 과정에 가깝습니다.

  • 컨테이너란 격리된 환경과 제한된 자원으로 제어되는 프로세스를 의미한다.
  • 격리된 환경은 배포에 장점이 있다.

VM과 컨테이너

  • VM은 컨테이너보다 훨씬 강력한 격리를 제공한다.
  • 하이퍼바이저 라는 소프트웨어가 하드웨어 자원을 가상화하고, 그 위에 별도의 운영체제가 설치된다.
    • 이 운영체제는 서버의 호스트OS와 구분해서 게스트OS(이하, GuestOS)라고 부른다. 하이퍼바이저는 서버 위에 여러 종류의 GuestOS를 VM으로 실행한다.
  • 테이너는 VM에 비해 작고 빠르다. 컨테이너는 호스트 커널에서 바로 처리되고 하드웨어를 직접 관리하는 반면에 VM은 GuestOS가 하드웨어 사용 시 하이퍼바이저의 처리를 기다려야 한다.

사실, 컨테이너는 어느 하루 아침에 docker run 명령어로 바로 실행할 수 있게 나온 것이 아닙니다. 컨테이너는 프로세스 격리라는 문제를 오랜 세월에 걸쳐 풀어오면서 필요한 요건들이 하나 둘 씩 생겨났고 그것들을 구현해 온 결과입니다.

chroot로 컨테이너 이해하기

  • Change Root Directory, chroot에 갇힌 프로세스는 현재 디렉터리를 루트로 인지하여 동작하기에 프로세스를 실행할 때 필요한 커맨드 프로그램, 라이브러리 등을 chroot에 함께 넣어야 한다.
    • 새로운 루트 경로에서 /bin/bash를 실행한다
      • cp /bin/bash new-root
      • chroot new-root /binbash → command not found (의존성 없음)
    • 필요한 의존성을 확인하고 추가한다. (ldd /bin/bash)
      • mkdir -p new-root{lib/x86_64{linx-gnu, lib64}
      • cp /lib/x86_64-linux-gnu/{libtinfo.so.5,libdl.so.2,libc.so.6} new-root/lib/x86_64-linux-gnu
      • cp /lib64/ld-linux-x86-64.so.2 new-root/lib64
    • chroot를 실행한다.
      • chrrot new-root /bin/bash
  • 즉, 새로운 루트 경로(new-root)를 만들고, 실행할 커맨드와 의존성 라이브러리(ldd)을 새로운 경로에 복사하여 새로운 경로에서 커맨드를 실행하는 것이다.
  • 이러한 실행할 커맨드와 필요한 의존성 라이브러리를 쓰기 편하게 모아둔 것을 이미지라고 한다.

chroot의 한계

  • 탈옥이 가능하다. (파일 시스템 독립성 훼손)
  • 격리되지 않는다. 프로세스가 루트 권한만 있으면 chroot 경로에 접근할 수 있어 다른 프로세스 및 시스템 정보를 볼 수 있다.
  • 루트 권한 제어 필요하다. chroot를 쓰려면 루트 권한이 필요하고, chroot로 실행된 프로세스도 루트 권한을 가진다. (루트 권한 없이도 컨테이너를 동작시키기 위한 적절한 권한 부여 방법이 필요)
  • 자원 격리가 필요하다. chroot를 쓰더라도 호스트의 자원을 제한 없이 사용할 수 있다.

pivot_root

  • pivot_root는 실제로 루트 파일 시스템 자체를 바꿔, 컨테이너가 전용 루트 파일 시스템을 가지도록 한다. 컨테이너는 별도의 루트 파일시스템인 마운트 네임 스페이스가 필요하다!
  • pivot_root [new_root] [old_root]
    • 기존의 루트 시스템을 새로운 루트 파일 시스템으로 변경하는 명령어이다.
  • 마운트 네임스페이스를 격리한 상태에서 pivot_root하기 때문에 호스트에는 영향을 주지 않으면서도 컨테이너는 호스트와 격리된 루트 파일시스템을 갖는다.

리눅스 네임스페이스

  • 리눅스 네임스페이스는 프로세스에 격리된 환경과 자원을 제공한다.
  • 네임스페이스 규칙이 존재한다.
    • 네임스페이스 안에서의 변경은 내부 프로세스에서만 보이고, 다른 프로세스에서는 보이지 않는다.
    • 네임스페이스와 관련된 프로세스는 부모 자식의 특징을 갖는다.
      • 모든 프로세스들은 네임스페이스 타입별로 특정 네임스페이스에 속한다.
      • 자식 프로세스는 부모 프로세스의 네임스페이스를 상속받는다.
  • 격리하는 자원에 따라 다양하게 구분되어 있다.

1. 마운트 네임스페이스

  • pivot_root를 사용하기 위해서 호스트 파일시스템에 영향을 주지 않는 방법이 필요하다.
  • 마운트 네임스페이스는 마운트 포인트를 격리하여 호스트 파일시스템에 영향을 주지 않고 컨테이너 전용 파일시스템을 구성할 수 있도록 도와준다.
    • unshare --mount /bin/bash
      • 마운트 네임스페이스를 격리하여 bash를 실행
  • 컨테이너가 마운트 네임스페이스로 격리되면 호스트에서는 해당 컨테이너 안에서 마운트된 것이 보이지 않는다.
  • 다음 명령어를 통해 특정 프로세스의 네임스페이스 정보를 알 수 있다. 호스트와 비교하면 같다.
    • readlink /proc/$$/ns/ment

2. UTS 네임스페이스

컨테이너의 문패, 어떤 게 우리 컨테이너인지 표시

  • UTS 네임스페이스는 호스트명을 서버와 다르게 설정하여 사용할 수 있도록 한다.
  • UTS는 Unix Time-Sharing의 약자로 여러 사람이 한 대의 서버를 나누어 쓸 때 사용자 환경별로 호스트명이나 도메인명을 구분할 수 있도록 격리를 제공한다.
  • uts 네임스페이스 사용
    • unshare --uts /bin/bash
    • hostname 명령어를 통해 호스트 명을 확인하면 호스트와 동일하게 출력되고(부모 상속), 컨테이너 안에서 자신만의 hostname을 가질 수도 있다.

3. IPC 네임스페이스

직통 전화를 한 대 설치

  • 리눅스에는 IPC(Inter Process Communication)을 지원하는 pipe, message queue, shared memory, socket 등 다양한 자원이 존재한다.
  • 컨테이너 터미널에서 ipc 네임스페이스를 격리하여 셸을 실행하고, 공유 메모리를 생성하고 확인한다.
    • unshare —ipc /bin/bash
    • ipcmk -M 2000
    • icps -m
  • 호스트 터미널에서 공유 메모리를 생성하고 확인한다.
    • ipcmk -M 1000
    • icps -m
  • 컨테이너와 호스트는 서로 다른 IPC 네임스페이스로 격리되어 있어 서로의 IPC 자원이 보이지 않는다.

4. PID 네임스페이스

가문의 족보와 같이 관계와 계통 표시

  • PID 네임스페이스는 pid 자원을 격리한다. 이때 부여되는 pid는 PID 네임스페이스 안에서 unique하다.
  • PID 네임스페이스를 격리하면 컨테이너 안에서도 pid 1로 시작하는 자체적인 트리구조를 가지게 된다.

  • 위의 그림에서 PID 네임 스페이스를 생성하면, 커널은 child 프로세스 pid 6을 만든다.
  • pid 6을 init process로 하여 PID 네임스페이스를 생성한다. pid 1은 init process로 pid 1이 죽으면 PID 네임스페이스도 사라진다.
  • PID 네임스페이스 생성하기
    • echo $$ (현재 프소세스 PID)
    • unshare --pid --fork --mount-proc /bin/bash
    • echo $$ (앞에서 출력한 pid값과 비교)

5. cgroup 네임스페이스

자원 계량기

  • croup(Control Group)은 프로세스에 할당된 시스템 자원(CPU, Memory, Network …)에 대한 제어를 제공한다.
  • cgroup이 시스템 자원을 할당하고 제어하는 방식은 파일 시스템을 기반으로 하며, 특수한 파일시스템에서 디렉터리를 만들고 파일을 수정하는 방식으로 시스템 자원들을 설정하고 관리한다.
  • 컨테이너에서 cgroup이 관리하는 파일시스템에 접근하면 다른 컨테이너는 물론 호스트 시스템 자원까지 접근할 수 있다. 따라서 cgroup 네임스페이스를 이용해 컨테이너가 속한 cgroup만 보이게 한다.
  • cgroup에서는 디렉토리 각 항목을 subsystem이라고 한다.
    • 각 subsystem 디렉토리에 들어가면 subsytem을 제어하기 위한 다양한 파일이 존재한다.
  • cgroup 파일 시스템 확인하기
    • tree -L 1 /sys/fs/cgroups

6. 네트워크 네임스페이스

  • 컨테이너의 네트워크 스택(OSI 7 Layer)를 격리한다. 이를 통해 호스트 안에서 컨테이너를 가상 네트워크상 별도의 노드로 취급할 수 있다.
  • 다음 명령어로 호스트와 컨테이너의 네트워크 인터페이스를 비교할 수 있다.
    • ip a (호스트)
    • unshare --net /bin/bash
    • ip a (컨테이너)
  • lsns 를 이용하면 네임스페이스 정보를 더 많이 알 수 있다.
    • lsns -t net -p $$ (현재 프로세스)
    • lsns -t net -p 1 (init 프로세스)

7. USER 네임스페이스

  • 컨테이너를 루트 유저로 실행하는 것은 보안상 매우 위험하다.
  • USER 네임스페이스를 이용하면 호스트에서는 권한이 최소화된 일반 유저지만, 컨테이너 안에서만 루트 유저로 부여할 수 있다.
  • USER 네임스페이스 적용이 까다로운 이유는 리눅스 배포판마다 구성 차이가 있고, 루트 권한을 제한하면 컨테이너 생성 자체가 어렵기 때문이다.
  • 이미지에 포함된 파일이나 호스트에서 컨테이너로 마운트한 파일, 디렉터리의 권한이 USER 네임스페이스의 권한과 상충하는 경우 등 해결해야 할 문제가 있다.
  • USER 네임스페이스는 uid, gid의 number space를 격리한다는 것을 보여주는 예시
    • 컨테이너 터미널
      • id uid=0(root) groups=0(root)
      • exit
    • 호스트 터미널
      • id uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant)
    • unshare로 USER 네임스페이스를 격리한 상태에서 컨테이너 id 확인하기
      • unshare —user /bin/bash
      • vagrant@ubuntu1804 → nobody@ubuntu1804
      • id 출력을 확인하면 컨테이너의 uid와 호스트의 uid가 다르다. 다른 USER 네임스페이스를 사용하기 때문이다.
      • 컨테이너를 일반 유저(vagrant)로 실행하면 UTS 네임스페이스를 만들 수 있는 권한이 없다.

8. Cgroups 네임스페이스

  • cgroup 네임스페이스는 cgroup 파일시스템 격리를 통해 컨테이너에서 함부로 호스트나 다른 컨테이너의 cgroups에 접근하지 못하게 한다.
  • cgroups(Control Groups)는 cgroup 파일시스템을 통해서 호스트의 하드웨어 자원을 그룹별로 관리하는 모듈이다.
    • 관리할 수 있는 그룹에는 CPU, Memory, Network, Disk IO, Devices 등 다양한 자원이 존재한다.
    • Cgroups는 하나 또는 복수의 장치를 묶어서 그룹을 만들 수 있고, 프로세스가 사용하는 자원 총량은 Cgroups의 통제를 받는다.
  • Cgroups를 이용해 CPU 사용률 제한해서 프로세스 기동하기
    • apt install -y cgroup-tools
    • apt install -y stress
    • stress -c 1 CPU 100%
  • 그룹에 CPU 사용률 제한하여 할당하기
    • cgcreate -a root -g cpu:mycgroup
    • cgset -r cpu.cfs_quota_us=30000 mycgroup
    • cgexec -g cpu:mycgroup stress -c 1
    • stress -c 1 CPU 30%

profile
꾸준하게

0개의 댓글