以前にルートファイルシステムの下にあったデータを専用のマウントポイントに移動するには、システムのパーティションを再配置する必要があることに気づきました。ボリュームはすべてLVMにあるため、これは比較的簡単です。新しいボリュームを作成し、そこにデータを移動し、ルートファイルシステムを縮小してから、適切なポイントに新しいボリュームをマウントします。
問題はステップ3で、ルートファイルシステムを縮小します。関連するファイルシステムはext4であるため、オンラインでのサイズ変更がサポートされています。ただし、マウントされている間は、ファイルシステムを拡張することしかできません。パーティションを縮小するには、それをアンマウントする必要がありますが、通常の操作ではルートパーティションではこれは不可能です。
Webに関する回答は、LiveCDまたはその他のレスキューメディアの起動、縮小操作の実行、インストールされたシステムへの再起動に関係しているようです。ただし、問題のシステムはリモートであり、SSH経由でのみアクセスできます。再起動はできますが、レスキューディスクを起動してコンソールから操作することはできません。
リモートシェルアクセスを維持しながらルートファイルシステムをマウント解除するにはどうすればよいですか?
この問題を解決する際、 http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml で提供された情報は、極めて重要です。ただし、そのガイドは非常に古いバージョンのRHEL用であり、さまざまな情報が古くなりました。
以下の手順はCentOS 7で動作するように作成されていますが、systemdを実行するすべてのディストリビューションに簡単に転送できるはずです。すべてのコマンドはrootとして実行されます。
システムが安定した状態であることを確認します
他の誰もそれを使用していないこと、そして他に重要なことは何も起こっていないことを確認してください。外部接続によって途中で混乱が生じないようにするために、httpdやftpdなどのサービス提供ユニットを停止することをお勧めします。
systemctl stop httpd
systemctl stop nfs-server
# and so on....
未使用のファイルシステムをすべてマウント解除します
umount -a
これにより、ルートボリューム自体およびさまざまな一時/システムFSについて、「ターゲットがビジーです」という警告が表示されます。現時点ではこれらは無視できます。重要なのは、ルートファイルシステム自体を除いて、ディスク上のファイルシステムがマウントされたままにならないことです。これを確認してください:
# mount alone provides the info, but column makes it possible to read
mount | column -t
ディスク上にマウントされているファイルシステムがまだマウントされている場合は、実行すべきではない何かがまだ実行中です。 fuser
を使用しているかどうかを確認します。
# if necessary:
yum install psmisc
# then:
fuser -vm <mountpoint>
systemctl stop <whatever>
umount -a
# repeat as required...
一時的なルートを作成する
mkdir /tmp/tmproot
mount -t tmpfs none /tmp/tmproot
mkdir /tmp/tmproot/{proc,sys,dev,run,usr,var,tmp,oldroot}
cp -ax /{bin,etc,mnt,sbin,lib,lib64} /tmp/tmproot/
cp -ax /usr/{bin,sbin,lib,lib64} /tmp/tmproot/usr/
cp -ax /var/{account,empty,lib,local,lock,nis,opt,preserve,run,spool,tmp,yp} /tmp/tmproot/var/
これにより、(特に)マンページの表示(/usr/share
なし)、ユーザーレベルのカスタマイズ(/root
または/home
なし)などが中断する非常に最小限のルートシステムが作成されます。これは意図的なものであり、必要以上に長くそのような陪審不正ルートシステムに留まらないように奨励しているためです。
この時点で、必要なソフトウェアがすべてインストールされていることも確認する必要があります。これにより、パッケージマネージャーも確実に機能しなくなります。すべての手順を確認し、必要な実行可能ファイルがあることを確認します。
ルートにピボットする
mount --make-rprivate / # necessary for pivot_root to work
pivot_root /tmp/tmproot /tmp/tmproot/oldroot
for i in dev proc sys run; do mount --move /oldroot/$i /$i; done
systemdは、マウントがデフォルトでサブツリーの共有を許可するようにし(mount --make-shared
と同様)、これによりpivot_root
が失敗します。したがって、これをmount --make-rprivate /
でグローバルにオフにします。システムおよび一時ファイルシステムは、新しいルートに大量に移動されます。これは、まったく機能させるために必要です。とりわけsystemdとの通信用のソケットは/run
に存在するため、実行中のプロセスにソケットを閉じる方法はありません。
リモートアクセスが切り替え後も存続することを確認する
systemctl restart sshd
systemctl status sshd
Sshdを再起動した後、別のターミナルを開き、sshを介してマシンに再度接続することにより、アクセスできることを確認してください。できない場合は、先に進む前に問題を修正してください。
再度接続できることを確認したら、現在使用しているシェルを終了して再接続します。これにより、残りの分岐したsshd
が終了し、新しいものが/oldroot
を保持していないことが保証されます。
古いルートを使用して、すべてを閉じます
fuser -vm /oldroot
これにより、古いルートディレクトリを保持しているプロセスのリストが出力されます。私のシステムでは、次のようになりました。
USER PID ACCESS COMMAND
/oldroot: root kernel mount /oldroot
root 1 ...e. systemd
root 549 ...e. systemd-journal
root 563 ...e. lvmetad
root 581 f..e. systemd-udevd
root 700 F..e. auditd
root 723 ...e. NetworkManager
root 727 ...e. irqbalance
root 730 F..e. tuned
root 736 ...e. smartd
root 737 F..e. rsyslogd
root 741 ...e. abrtd
chrony 742 ...e. chronyd
root 743 ...e. abrt-watch-log
libstoragemgmt 745 ...e. lsmd
root 746 ...e. systemd-logind
dbus 747 ...e. dbus-daemon
root 753 ..ce. atd
root 754 ...e. crond
root 770 ...e. agetty
polkitd 782 ...e. polkitd
root 1682 F.ce. master
postfix 1714 ..ce. qmgr
postfix 12658 ..ce. pickup
/oldroot
をアンマウントする前に、これらの各プロセスに対処する必要があります。ブルートフォースアプローチは、それぞれに対して単純にkill $PID
ですが、これにより問題が発生する可能性があります。より柔らかくするには:
systemctl | grep running
これにより、実行中のサービスのリストが作成されます。これを/oldroot
を保持しているプロセスのリストと関連付けることができるはずです。次に、それぞれに対してsystemctl restart
を発行します。一部のサービスは、一時的なルートでの起動を拒否し、失敗状態に入ります。これらは今のところ重要ではありません。
サイズを変更するルートドライブがLVMドライブの場合、fuser -vm /oldroot
によって作成されたリストに表示されない場合でも、他の実行中のサービスを再起動する必要がある場合があります。手順7でLVMドライブのサイズを変更できない場合は、systemctl restart systemd-udevd
を試してください。
一部のプロセスは、単純なsystemctl restart
では処理できません。私にとっては、これらにはauditd
が含まれていました(これはsystemctl
を介して殺されることを好まないため、kill -15
が必要でした)。これらは個別に処理できます。
あなたが見つける最後のプロセスは、通常、systemd
自体です。これには、systemctl daemon-reexec
を実行します。
完了すると、テーブルは次のようになります。
USER PID ACCESS COMMAND
/oldroot: root kernel mount /oldroot
古いルートをアンマウントします
umount /oldroot
この時点で、必要な操作を実行できます。元の質問では単純なresize2fs
の呼び出しが必要でしたが、ここでは何でも好きなことができます。もう1つの使用例は、ルートファイルシステムを単純なパーティションからLVM/RAID /その他に転送することです。
ルートをピボットして戻す
mount <blockdev> /oldroot
mount --make-rprivate / # again
pivot_root /oldroot /oldroot/tmp/tmproot
for i in dev proc sys run; do mount --move /tmp/tmproot/$i /$i; done
これは、手順4を単純に逆にしたものです。
一時的なルートを破棄する
/tmp/tmproot
の代わりに/oldroot
を使用する以外は、手順5と6を繰り返します。次に:
umount /tmp/tmproot
rmdir /tmp/tmproot
これはtmpfsなので、この時点で一時的なルートはエーテルに溶解し、二度と表示されることはありません。
物を元の場所に戻す
ファイルシステムを再度マウントします。
mount -a
この時点で、手順7で行った調整に従って/etc/fstab
およびgrub.cfg
も更新する必要があります。
失敗したサービスを再起動します。
systemctl | grep failed
systemctl restart <whatever>
共有サブツリーを再び許可:
mount --make-rshared /
停止したサービスユニットを開始します。次の1つのコマンドを使用できます。
systemctl isolate default.target
これで完了です。
RHEL4でこの進化を実現したAndrew Woodと、前者へのリンクを提供してくれたsteveに感謝します。
何をやっているのかがわかっている場合-実験を行わない場合は、非対話的で高速な方法であるinitrdを使用できます。
Debianベースのシステムでは、ここにその方法があります。
コードを参照してください: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-setup/debian-resizefs.sh
DigitalOcean VPS(ルートとして25G/dev/vda1がマウントされている)で私がしたこと:
update-grub
reboot
と祈る上記はresize2fsがサポートされていないと言われたときにうまくいきました。