Skip to content

3-3. Mount Namespace

別のNamespaceも追加してみましょう。次はMount Namespaceです。

Mount Namespaceを分けてみる

Mount Namespaceは、Mount情報を分けることができるNamespaceです。 Namespace内で行ったMountは、(一部例外を除いて) 別Namespaceに影響を及ぼしません

実はお配りしたテンプレートには、rootfsの設定がMount Namespaceを必要とする都合で、既にMount Namespaceを分ける処理が入っています。

go
// runサブコマンド
func runCommand(c Config) error {
  // Namespaceを分離
  if err := unix.Unshare(unix.CLONE_NEWUTS); err != nil {
    return errors.WithStack(err)
  }

  // cgroupの設定
  if err := SetupCgroup(c.Name, os.Getpid(), c.Cgroup); err != nil {
    return errors.WithStack(err)
  }

  // rootfsの設定
  _ = unix.Unshare(unix.CLONE_NEWNS) // rootfsで使うので、Namespace系の処理だが仮置き
  if err := SetupRootfs(c.Rootfs); err != nil {
    return errors.WithStack(err)
  }

  // 作成した簡易コンテナ内でエントリーポイントを実行
  path, err := exec.LookPath(c.EntryPoint[0])
  if err != nil {
    return errors.WithStack(err)
  }
  if err := unix.Exec(path, c.EntryPoint, os.Environ()); err != nil {
    return errors.WithStack(err)
  }

  return nil
}

この節では、既に仮置きされていたMount Namespaceの処理を、先程記述したUTS Namespaceの設定に合体させてみましょう!

ヒント

flagsは、ビット論理和演算子|を使うことで、複数を同時に指定することができます。

想定解答

想定解答
go
// runサブコマンド
func runCommand(c Config) error {
  // Namespaceを分離
  if err := unix.Unshare(unix.CLONE_NEWUTS); err != nil { 
  if err := unix.Unshare(unix.CLONE_NEWUTS | unix.CLONE_NEWNS); err != nil { 
    return errors.WithStack(err)
  }

  // cgroupの設定
  if err := SetupCgroup(c.Name, os.Getpid(), c.Cgroup); err != nil {
    return errors.WithStack(err)
  }

  // rootfsの設定
  _ = unix.Unshare(unix.CLONE_NEWNS) // rootfsで使うので、Namespace系の処理だが仮置き
  if err := SetupRootfs(c.Rootfs); err != nil {
    return errors.WithStack(err)
  }

  // 作成した簡易コンテナ内でエントリーポイントを実行
  path, err := exec.LookPath(c.EntryPoint[0])
  if err != nil {
    return errors.WithStack(err)
  }
  if err := unix.Exec(path, c.EntryPoint, os.Environ()); err != nil {
    return errors.WithStack(err)
  }

  return nil
}

Namespaceが分かれたことを確かめる

Namespace内でマウントをしても元のシェルに影響を及ぼさないことを確かめましょう。
Namespaceの分離にはroot権限が必要なので、sudo suを実行してrootになってからプログラムを実行して下さい。

umountコマンドを使って/procフォルダをアンマウントするとpsの結果が見れなくなるので、今回はそれを使って確かめます。
mountコマンドを使ったbind mountなども影響を及ぼさないか、各自で調べて試してみて下さい!

console
$ sudo su
# make run
go build -o main *.go
./main run bash
# ps                    ← ここではちゃんと表示できている
    PID TTY          TIME CMD
 177532 pts/8    00:00:00 sudo
 177533 pts/8    00:00:00 su
 177534 pts/8    00:00:00 bash
 177589 pts/8    00:00:00 make
 177634 pts/8    00:00:00 bash
 177706 pts/8    00:00:00 ps
# umount -l /proc
# ps                    ← /procをアンマウントすると表示できない
Error, do this: mount -t proc proc /proc
# exit
exit
# ps                    ← Namespaceを抜けるとちゃんと表示できている
    PID TTY          TIME CMD
 177532 pts/8    00:00:00 sudo
 177533 pts/8    00:00:00 su
 177534 pts/8    00:00:00 bash
 178291 pts/8    00:00:00 ps
#