マウントツリーを読んで設計する
目標
/proc/self/mountinfoを直接読んで、マウントツリーと伝播タイプを把握し、バインドマウントとtmpfsを、fstabとsystemdユニットの2つの形式で作成します。
なぜ重要なのか
コンテナの時代にマウントが難しくなった理由は、マウント名前空間と伝播タイプにあります。ホストで取り付けたボリュームがコンテナに見えなかったり、コンテナを消したのにマウントが残ってディスクを握り続けたりする現象は、すべてここから出ています。そしてその情報は、mountコマンドの出力にはなく、/proc/self/mountinfoの任意フィールドにだけあります。このファイルを読めるかどうかで、大きな差が出ます。
このラボはUbuntu 24.04のVM上で動きます。そのため、ステップ7で書いた.mountユニットを、systemctl startで実際にマウントしてみます。ユニット名がパスと1文字でも違うとsystemdが拒否するということを、規則を暗記してではなく、拒否されてみて知ることになります。以前はPodの中で動いていてmountの権限がなく、読み取りと設計までがすべてでした。
ステップ
/root/mntディレクトリを作成し、/proc/self/mountinfoの各行から마운트지점 타입 옵션の3つの値(プレースホルダーは順に、マウントポイント、タイプ、オプションです)を取り出し、空白で区切って/root/mnt/parsed.txtに保存してください。最低5行あり、/procが含まれている必要があります。findmntで現在のマウントを타깃,소스,타입の形式(プレースホルダーは順に、ターゲット、ソース、タイプです)で出力し、/root/mnt/findmnt.txtに保存してください。- タイプが
tmpfsのマウントだけを選んで、/root/mnt/tmpfs.txtに保存してください。最低1行必要です。 - 各マウントの伝播タイプを判定し、
마운트지점 <shared|slave|private>の形式(プレースホルダーはマウントポイントです)で/root/mnt/propagation.txtに保存してください。最低5行必要です。 /root/mnt/bind.fstabに、次のバインドマウントの行を1行で書いてください。元は/srv/data、マウント先は/var/www/data、タイプはnone、オプションにbindとroを含め、dumpは0、passは0です。/root/mnt/tmpfs.fstabに、次のtmpfsの行を1行で書いてください。マウントポイントは/var/cache/app、タイプはtmpfs、オプションにsize=256M、mode=1777、noexec、nosuid、nodevをすべて含め、dumpは0、passは0です。- ステップ6と同じ内容を、systemdユニットとしても作成してください。ファイル名は、マウントポイントをエスケープした正確な名前でなければならず、
/root/mnt/の下に置きます。[Unit]、[Mount]、[Install]の3つのセクションがあり、[Mount]にはWhat、Where、Type、Optionsの4つのキーがある必要があります。 /root/mnt/design.txtを次の4行で作成してください。MOUNTS=<1번 파일의 줄 수>/TMPFS=<3번 파일의 줄 수>/BIND_TARGET=/var/www/data/UNIT=<7번에서 만든 파일 이름(경로 제외)>(プレースホルダーは順に、ステップ1のファイルの行数、ステップ3のファイルの行数、ステップ7で作成したファイルの名前からパスを除いたものです)
参考
- mountinfoは、ハイフン(
-)1つを境に、前後のフィールド数が異なります。マウントポイントは5番目、タイプはハイフンのあとの最初のフィールドです。 findmnt -n -o TARGET,SOURCE,FSTYPEの形で、必要な列だけを取り出せます。- ユニット名は
systemd-escape --path --suffix=mount /var/cache/appで得られます。ツールがなければ、規則(先頭のスラッシュを除去し、残りのスラッシュをハイフンに)を自分で適用してください。 - よくある間違い1: ステップ1で、任意フィールドの数が行ごとに違って、awkの固定列番号がずれる場合です。ハイフンの位置を先に探してください。
- よくある間違い2: ステップ7で、ユニット名を勝手に決める場合です。systemdは、名前がパスと違うとユニットを拒否します。
mountinfoのパース
/root/mntディレクトリを作成し、/proc/self/mountinfoの各行から마운트지점 타입 옵션の3つの値(プレースホルダーは順に、マウントポイント、タイプ、オプションです)を取り出し、空白で区切って/root/mnt/parsed.txtに保存してください。最低5行あり、/procが含まれている必要があります。
フィールドの区切りは空白で、途中に個数が可変の任意フィールドがあります。ハイフン1つが、その境目です。
findmntで見る
findmntで現在のマウントを타깃,소스,타입の形式(プレースホルダーは順に、ターゲット、ソース、タイプです)で出力し、/root/mnt/findmnt.txtに保存してください。
findmntは/procを読むツールなので、特権なしで動作します。出力形式を指定するオプションがあります。
tmpfsのマウントだけを選び出す
タイプがtmpfsのマウントだけを選んで、/root/mnt/tmpfs.txtに保存してください。最低1行必要です。
タイプがtmpfsのものだけをフィルタリングしてください。sizeオプションがあるものとないものに注目してください。
伝播タイプの表を作る
各マウントの伝播タイプを判定し、마운트지점 <shared|slave|private>の形式(プレースホルダーはマウントポイントです)で/root/mnt/propagation.txtに保存してください。最低5行必要です。
任意フィールドにshared:やmaster:があれば、それぞれshared、slaveです。何もなければprivateです。
バインドマウントのfstabの行
/root/mnt/bind.fstabに、次のバインドマウントの行を1行で書いてください。元は/srv/data、マウント先は/var/www/data、タイプはnone、オプションにbindとroを含め、dumpは0、passは0です。
バインドマウントのタイプのフィールドはnoneで、オプションにbindが入ります。読み取り専用も一緒に指定できます。
tmpfsのfstabの行
/root/mnt/tmpfs.fstabに、次のtmpfsの行を1行で書いてください。マウントポイントは/var/cache/app、タイプはtmpfs、オプションにsize=256M、mode=1777、noexec、nosuid、nodevをすべて含め、dumpは0、passは0です。
デバイスの位置にはtmpfsを書きます。サイズを必ず指定し、セキュリティオプションを3つ一緒に入れてください。
.mountユニットファイル
ステップ6と同じ内容を、systemdユニットとしても作成してください。ファイル名は、マウントポイントをエスケープした正確な名前でなければならず、/root/mnt/の下に置きます。[Unit]、[Mount]、[Install]の3つのセクションがあり、[Mount]にはWhat、Where、Type、Optionsの4つのキーがある必要があります。
ユニット名は、マウントポイントのパスをエスケープしたものである必要があります。systemd-escapeで、正確な名前を得られます。
マウント設計書
/root/mnt/design.txtを次の4行で作成してください。
MOUNTS=<1번 파일의 줄 수> / TMPFS=<3번 파일의 줄 수> / BIND_TARGET=/var/www/data / UNIT=<7번에서 만든 파일 이름(경로 제외)>(プレースホルダーは順に、ステップ1のファイルの行数、ステップ3のファイルの行数、ステップ7で作成したファイルの名前からパスを除いたものです)
値は、前のステップで作ったファイルから持ってくればよいです。個数は、行数で数えれば十分です。