フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【コンテナ要素技術】pivot_rootについて例をまじえて説明します

ここのサイトで紹介されているpivot_rootの理解に時間がかかったので解説します。

pivot_rootとは?

pivot_rootプロセスのルートファイルシステムを隔離する目的で使用されるコマンドです。仲間にchrootがいますが挙動が異なります。pivot_rootプロセスのルートファイルシステムそのものを入れ替えることでファイルシステムを隔離します。

またpivot_rootを使うには以下の条件があります。

【引用】

・新しいファイルシステム(new_root)と元のファイルシステムの移動先(put_old)はディレクトリでなければならない ・new_rootとput_oldは現在のrootと同じファイルシステムにあってはならない ・put_oldはnew_root配下になければならない ・他のファイルシステムがput_oldにマウントされていてはならない

試してみる

このコマンドを叩くとpivot_rootを使ってルートファイルシステムの隔離ができます。

$ ROOTFS=$(mktemp -d)
$ cp -a /bin /lib /lib64 $ROOTFS
$ NEW_ROOT=$ROOTFS
$ mkdir $NEW_ROOT/{.put_old,proc}
$ unshare -mpfr /bin/sh -c " \ 
  mount --bind $NEW_ROOT $NEW_ROOT && \ 
  mount -t proc proc $NEW_ROOT/proc && \ 
  pivot_root $NEW_ROOT $NEW_ROOT/.put_old && \ 
  umount -l /.put_old && \ 
  cd / && \ 
  exec /bin/sh
"

# ls
bin  lib  lib64  proc

何をしているのか?

ここにフォーカスして説明します。

  mount --bind $NEW_ROOT $NEW_ROOT && \ 
  mount -t proc proc $NEW_ROOT/proc && \ 
  pivot_root $NEW_ROOT $NEW_ROOT/.put_old && \ 
  umount -l /.put_old && \ 
  cd / && \ 
  exec /bin/sh

f:id:lirlia:20200409174853p:plain

まずmount --bind $NEW_ROOT $NEW_ROOT && \$NEW_ROOTをマウントします。続いてprocをマウントしたのち、pivot_rootコマンドによって現在のプロセスのルートファイルシステムを移動しています。

pivot_rootのmanページをみると

pivot_root moves the root file system of the current process to the directory put_old and makes new_root the new root file system.

とあり日本語に訳すと

pivot_rootは、現在のプロセスのルートファイルシステムをput_oldディレクトリを作成し、new_rootを新しいルートファイルシステムにします。

と言っています。

unshareコマンドを叩いたプロセスでは/を使っていました。このルートファイルシステムを$NEW_ROOT/.put_oldに移し、$NEW_ROOTをルートファイルシステムに変更しています。

f:id:lirlia:20200409174853p:plain

そして不要になった/.put_oldunmountしています。

ためしにunmountを抜いてみよう

$ unshare -mpfr /bin/sh -c " \ 
  mount --bind $NEW_ROOT $NEW_ROOT && \ 
  mount -t proc proc $NEW_ROOT/proc && \ 
  pivot_root $NEW_ROOT $NEW_ROOT/.put_old && \ 
  umount -l /.put_old && \ 
  cd / && \ 
  exec /bin/sh
"

このコマンドからumount -l /.put_old &&を抜いてみましょう。

root@ubuntu-bionic:~/docker# unshare -mpfr /bin/sh -c " \ 
  mount --bind $NEW_ROOT $NEW_ROOT && \ 
  mount -t proc proc $NEW_ROOT/proc && \ 
  pivot_root $NEW_ROOT $NEW_ROOT/.put_old && \ 
  cd / && \                
  exec /bin/sh
"
# ls /.put_old
bin   home            lib64       opt   sbin  tmp      vmlinuz
boot  initrd.img      lost+found  proc  snap  usr      vmlinuz.old
dev   initrd.img.old  media       root  srv   vagrant
etc   lib             mnt         run   sys   var

すると/.put_oldの下に先ほどまでは存在しなかった元々のルートファイルシステムがあることがわかります。