フラミナル

考え方や調べたことを書き殴ります。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の下に先ほどまでは存在しなかった元々のルートファイルシステムがあることがわかります。