운영체제/LINUX

[Linux] 마운트 네임스페이스 (Mount namespace) 2

benjykim 2019. 10. 24. 11:22
반응형

마운트 네임스페이스

  • 시스템이 시작(booted)되면, 하나의 마운트 네임스페이스가 있고 이것은 "initial namespace"라고 불린다. 새로운 마운트 네임스페이스들은 clone() 또는 unshare() 시스템 콜 그리고 CLONE_NEWNS 플래그를 사용하여 만들어진다.
  • 새로운 마운트 네임스페이스가 생성되면, 그 새로운 네임스페이스는 clone() 또는 unshare()을 호출한 놈의 네임스페이스로 부터 (호출한 놈의)마운트 포인트 리스트의 복사본을 받는다.
    • 마운트 포인트 리스트 위치 - /proc/mounts
  • clone() 또는 unshare() 시스템 콜에 따르면, 마운트 포인트들은 각각의 네임스페이스에서 독립적으로 추가되거나 제거될 수 있다(mount(), umount()를 통해서).
  • 마운트 포인트 리스트의 변경사항들은 프로세스가 거주하는 마운트 네임스페이스의 프로세스들에만 보여진다. 다른 마운트 네임스페이스에서는 변경사항들이 보이지 않는다.

Shared subtress

  • 일단 마운트 네임스페이스의 구현이 완료되면, 유용성(usability) 문제를 맞닥뜨린다.
    • 마운트 네임스페이스는 네임스페이스간 너무 강력한 격리(isolation)를 제공한다.
    • 예를 들어, 새 디스크가 광디스크 드라이브에 로드된다고 하자. 원래 구현에서, 모든 마운트 네임스페이스에서 디스크를 보이게할 수 있는 유일한 방법은 각각의 네임스페이스에 따로 디스크를 마운트해야 한다.
    • 대부분의 경우, 시스템에서 모든 마운트 네임스페이스에서 디스크를 볼 수 있게 만드는 마운트 명령은 한번만 수행하는 것이 바람직하다.
  • 이러한 문제 때문에 shared subtrees featureLinux 2.6.15버전에 추가되었다. shared subtrees의 주요 이점은 네임스페이스간 mount, unmount 이벤트가 자동으로 제어되고 전파될 수 있도록 하는 것이다.
    • 예를 들어, 한 마운트 네임스페이스에서 광디스크를 마운트 하는 것이 다른 모든 네임스페이스에서 해당 디스크의 마운트를 발생시킬 수 있다.
  • shared subtrees feature 아래, 각 마운트 포인트에는 propagation type이 표시되어 이 마운트 포인트 하에서 생성 및 제거된 마운트 포인트가 다른 마운트 포인트로 전파되는지 여부를 결정한다.
  • 4개의 다른 propagation type이 존재한다.
    1. MS_SHARED: 이 마운트 포인트는 'peer group'의 멤버인 다른 마운트 포인트들과 mount와 unmount 이벤트를 공유한다. 마운트 포인트가 이 마운트 포인트 하에서 추가되거나 제거될 때, 이 변경사항은 peer 그룹으로 전파되어, mount 또는 unmount가 각각의 peer 마운트 포인트 하에서 발생하게 된다. 전파는 역방향으로도 발생하므로 peer 마운트의 mount, unmount 이벤트는 이 마운트 지점까지 전파될 것이다.
    2. MS_PRIVATE: 이것은 공유 마운트 포인트(shared mount point)의 반대이다. 마운트 포인트는 어떠한 peer에게도 이벤트를 전파하지 않으며, 어느 peer로부터로도 전파를 받지 않는다.
    3. MS_SLAVE: 이 전파 타입은 shared와 private의 중간이다. 슬레이브 마운트는 멤버가 mount, unmount 이벤트를 슬레이브 마운트로 전파하는 공유 peer 그룹(shared peer group)인 마스터가 있다. 그러나 슬레이브 마운트는 이벤트를 마스터 peer 그룹에게 전파하지 않는다.
    4. MS_UNBINDABLE: 이 마운트 포인트는 바인딩할 수 없다. private 마운트 포인트처럼, 이 마운트 포인트는 피어로 혹은 피어로부터 이벤트를 전파하지 않는다.
  • +a
    • propagation type은 마운트 포인트별 셋팅이다. 네임스페이스 내에서, 몇몇 마운트 포인트들은 shared로 표시될 수 있고 다른 마운트 포인트들은 private, slave, unbindable로 표시될 수 있다.
    • propagation type은 마운트 포인트 아래에서의 mount, unmount 이벤트의 전파를 결정한다. 따라서 shared마운트 X 아래에 하위(child) 마운트 Y를 생성하면 해당 하위 마운트가 peer 그룹의 다른 마운트 포인트로 전파된다. 하지만 X의 propagation type은 Y 아래서 생성되고 제거된 마운트 포인트에 대해 영향을 끼치지 않는다. Y에 따른 이벤트가 전파되는지 여부는 Y에 대해 정의된 propagation type에 따라 달라진다. 마찬가지로, X 마운트 포인트 그 자체가 unmount 될 때 unmount 이벤트가 전파될지 안될지는 X의 부모 마운트의 propagation type에 따라 달라진다.
    • 이벤트는 한 마운트 포인트의 몇몇 mount 또는 unmount 동작이 하나 또는 다른 마운트 포인트와 일치하는 동작을 유발(trigger)시켰다는 의미를 담고있다.

Peer groups

  • peer 그룹은 mount, unmount 이벤트들을 다른 마운트 포인트에 전파하는 마운트 포인트들의 셋이다.
  • peer 그룹은 propagation typeshare인 마운트 포인트가 새 네임스페이스 생성 중에 복제되거나 bind mount의 소스로 사용될 때 새로운 멤버들을 얻는다. 두 경우 모두 새로운 마운트 포인트가 기존 마운트 포인트와 동일한 peer 그룹의 멤버로 지정된다.
  • 반대로, 마지막 구성원(멤버) 프로세스가 종료되거나 다른 네임 스페이스로 이동하여 마운트 네임 스페이스가 종료될 때 peer 그룹이 unmount 하면, 마운트 포인트가 peer 그룹의 멤버를 그만둔다.
  • 예제
    • 초기 마운트 네임스페이스에서 실행되는 shell에서 루트 마운트 포인트를 private으로 설정하고 두개의 shared 마운트 포인트를 만든다고 가정하자.
      
      sh1# mount --make-private /
      sh1# mount --make-shared /dev/sda3 /X
      sh1# mount --make-shared /dev/sda5 /Y
      
    • 두번째 터미널에서 shell을 실행하는 새로운 마운트 네임스페이스를 생성하기 위해 unshare 명령을 사용한다.
      
      sh2# unshare -m --propagation unchanged sh
      
      • -m 옵션: 새로운 마운트 네임스페이스를 만든다.
    • 첫번째 터미널로 돌아와서, /X 마운트 포인트에서 bind 마운트를 만든다.
      
      sh1# mkdir /Z
      sh1# mount --bind /X /Z 
      
      • 이 시나리오에선 2가지 peer 그룹이 있다.
        • 첫번째 peer 그룹은 X, X' 마운트 포인트와 Z를 포함한다(X'- 두번째 네임스페이스 생성 시 생성된 마운트 포인트 X의 복제 / Z- 초기 네임스페이스에서 X 마운트 포인트에서 생성된 bind 마운트).
        • 두번째 peer 그룹은 Y, Y' 마운트 포인트를 포함한다.
      • 두번째 네임스페이스가 생성된 후 초기 네임스페이스에서 생성된 bind 마운트 Z는 상위(parent) 마운트(/)가 private으로 표시되었기 때문에 두번째 네임스페이스에는 복제되지 않았다.

Examining propagation types and peer groups via /proc/PID/mountinfo

  • /proc/PID/mountinfo 파일에는 프로세스 PID가 있는 마운트 네임스페이스의 마운트 포인트에 대한 다양한 정보가 표시된다. 동일한 마운트 네임스페이스에 있란는 모든 프로세스들은 이 파일에서 동일한 뷰를 볼 것이다. 이 파일은 이전의 확장 불가능 /proc/PID/mounts파일에서 가능한 것보다 더 많은 마운트 포인트에 대한 정보를 제공하도록 설계되었다. 이 파일의 각 기록에는 각 마운트의 propagation typepeer 그룹에 대한 정보를 표시하는 소위 optional fields가 있다.
  • shared 마운트의 경우, /proc/PID/mountinfo의 해당 레코드안 optional fields에는 shared:N 형태의 태그를 포함된다. shared 태그는 마운트가 peer 그룹과 전파 이벤트를 공유하고 있음을 나타낸다. peer 그룹은 peer 그룹을 유일하게 구분하는 정수 값인 N으로 식별된다. 이러한 ID들은 1부터 번호가 매겨지며, 모든 구성원이 그룹을 떠났기 때문에 peer 그룹이 더 이상 존재하지 않을 때 재활용 될 수 있다. 동일한 peer 그룹의 멤버인 모든 마운트 포인트들은 /proc/PID/mountinfo파일 안에 'N'과 동일한 shared:N태그를 보여줄 것이다.
  • 예를 들어, 위의 예제에서 언급한 shell의 첫번째 /proc/self/mountinfo의 내용을 나열하면, 다음과 같다.
    
    sh1# cat /proc/self/mountinfo | sed 's/ - .*//'
    61 0 8:2 / / rw,relatime
    81 61 8:3 / /X rw,relatime shared:1
    124 61 8:5 / /Y rw,relatime shared:2
    228 61 8:3 / /Z rw,relatime shared:1
    
    • 이 출력에서, 우리는 root 마운트 포인트가 private이라는 것을 알 수 있다. optional fields에 아무 태그도 없기 때문이다. 우리는 또한 마운트 포인트 /X, /Y가 동일 peer 그룹(with ID 1)의 shared마운트 포인트라는 것을 알 수 있다. 이는 두 마운트 중 하나에 따른 mount, unmount 이벤트가 다른 peer 그룹으로 전파된다는 것을 의미한다. 마운트 /Y는 다른 peer 그룹(ID 2)의 shared 마운트로서, peer 그룹 1에 이벤트를 전파하거나 전파받지 않는다.
  • /proc/PID/mountinfo는 우리로 하여금 마운트 포인트 간 부모 관계를 볼 수 있게 해준다. 각 레코드의 첫번째 필드는 각 마운트 포인트에 대한 고유한 ID이다. 두번째 필드는 부모 마운트의 ID이다. 위의 출력에서, 우리는 마운트 포인트 /X, /Y, /Z는 모두 부모가 61이므로 루트 마운트의 하위 항목임을 알 수 있다.
  • 두번째 shell에서 같은 명령을 내려보자.
    
    sh2# cat /proc/self/mountinfo | sed 's/ - .*//'
    147 146 8:2 / / rw,relatime
    221 147 8:3 / /X rw,relatime shared:1
    224 147 8:5 / /Y rw,relatime shared:2
    
    • X는 peer 그룹 1의 shared 마운트이고 초기 마운트 네임스페이스의 마운트 /X, /Z와 동일한 peer 그룹이다.
    • Y는 peer 그룹 2의 shared 마운트이고 초기 마운트 네임스페이스의 마운트 /Y와 동일한 peer 그룹이다.
    • 마지막으로, 두번째 네임스페이스에서 복사된 마운트 포인트에는 초기 네임스페이스에서 해당 마운트의 ID와 다른 고유한 ID가 있다는 것에 주의하자.

Debating defaults

  • 커널 관점에서, 새로운 장치 마운트가 생성될 때의 기본 값은 다음과 같다.
    • 만일 마운트 포인트가 부모를(non-root mount point) 가지고 있고 부모의 propagation typeMS_SHARED인 경우, 새로운 마운트의 propagation type역시 MS_SHARED이다.
    • 그렇지 않으면, 새로운 마운트의 propagation typeMS_PRIVATE이다.
  • 위의 규칙에 따르면, 루트 마운트는 MS_PRIVATE이 되며, 모든 하위 마운트도 기본적으로 MS_PRIVATE이 된다. 그러나 MS_SHARED는 더 일반적으로 사용되는 propagation type이기 때문에 더 나은 기본 값이다. 이러한 이유로 systemd는 모든 마운트 포인트의 propagation typeMS_SHARED로 설정한다. 따라서 대부분의 현대 리눅스 배포에서 기본 propagation typeMS_SHARED이다.
  • 그러나 이것은 이 주제에 대한 최종적인 결론은 아니다. 왜냐하면 util-linux의 unshare 기능 또한 할 말이 있기 때문이다. 새로운 마운트 네임스페이스를 만들 때, unshare은 유저가 완전히 분리된 네임스페이스를 원한다고 가정하고, 다음과 같은 명령을 수행하여 모든 마운트 포인트를 private으로 만든다.
    
    mount --make-rprivate /
    
  • 이것을 막기 위해 새로운 네임스페이스를 생성할 때 추가 옵션을 사용할 수 있다.
    
    unshare -m --propagation unchanged <cmd>
    
반응형