Linuxブートのマスターになる

最初に、udevに精通し、起動時にコンピューターにインストールされているデバイスを調べるためにそれを使用する方法を学習します。例として、Xorgのビデオカード設定を自動的に選択します。 次に、initramfsに独自のハンドラーを実装することで、多数のコンピューターで1つのイメージを同時に処理する問題を解決すると同時に、ネットワークブート用にシステムを最適化します。 ロード時間をさらに短縮し、ネットワークの負荷を削減するために、NFSをNBDに置き換え、TFTPをHTTPでサポートするようにします。 最後に、最初に戻りましょう-また、読み取り専用モードに設定したブートサーバーに戻ります。







この記事は既製のガイドというよりも研究です(すべてのソリューションが機能しますが、常に最適とは限りません)。 最終的には、あなたが望むとおりにすべてを行うのに十分な知識が得られます。



ここから始めましょう:

サーバーの初期セットアップ

ネットワークブート用のイメージの準備



VirtualBoxマシンをネットワーク経由でロードし、Firefoxを起動することに決めました。 ここで実際のコンピューターで同じことを行おうとすると、ユーザー名の循環認証とグラフィカル環境の起動の失敗が画面に表示されます-Xorgは必要なドライバーを見つけません。



ビデオカードを発売します



VirtualBoxのグラフィックモードには、必要なものがすべて揃っています。 ディスクレスシステムはどのハードウェアでも動作するように当初計画されていましたが 、遅延のため、広大さを把握しようとはしません。そのため、nVidia、Intel、AMDの主要メーカーのグラフィックソリューションのサポートに限定します。



Ctrl + Alt + F2を押してクライアントマシンを2番目の端末に切り替え、開いているドライバーをインストールします。

pacman -S xf86-video-ati xf86-video-nouveau xf86-video-intel
      
      





おそらく、今回はXorgが各ケースに適切な設定を個別に選択することができず、ロードされたクライアントの画面から判断すると、何も変わっていないように見えます。



システムにあるビデオデバイスを見つける最も簡単な方法は、コンソールにコマンドを入力することです。

 lspci | grep -i vga 00:02.0 VGA compatible controller: InnoTek Systemberatung GmbH VirtualBox Graphics Adapter
      
      





しかし、私たちは簡単な方法を探しませんが、報酬として知識の新しい部分を受け取ります。



udevを詳しく知る



先ほど、Archlinux のデバイスマネージャーudevと呼ばれると述べました。 systemd-udevdという名前でsystemdパッケージに含まれています。



ブート可能なシステムで新しいデバイスが検出されると、カーネルは/デバイスディレクトリに階層を作成します。 最初にPCIシステム自体が表示され、次にエンドデバイスが「座っている」バスがその中にあり、そのドライバーがデバイスをクラスに分類します。 systemdが次の目標を達成するためにサービスを並行して実行するように、クラス内のデバイスは並行して検出されます。



デバイスの非同期検索は、同じクラスに属する複数のデバイスがコンピューター上に同時に存在する場合、たとえば、最初に1つのビデオカード、次に別のビデオカードなど、異なる順序で検出できるという事実につながり、その名前は彼らの間で変化します。 幸いなことに、デバイス階層内の新しい要素の出現はudevイベントであり、必要に応じて追跡および取得できます。



udevマネージャーの場合、混乱を合理化し、インストールされたプログラムの寿命を単純化するルールが考案されました。 ルールは/usr/lib/udev/rules.d/および/etc/udev/rules.d/フォルダーに保存されます(後者は、フックの場合のように優先度が高く、そこからのファイルが最初にチェックされます)。 デバイス階層での新しい要素の出現には、確立されたすべてのudevルールの検証と、一致した場合にそこに示されたアクションの自動実行が伴います。 通常、これらの手順では、プログラムでの使いやすさのために、デバイスの名前を変更し、/ devおよび/ sys内のディレクトリにデバイスをリンクします。



ビデオカードドライバーはそれらをdrmサブシステム(クラス)に帰属させるため、そのようなデバイスに関する情報は/ sys / class / drmディレクトリに複製されます。 システムで最初に検出されたビデオカードは、デフォルトで「card0」という名前を取得します。複数のビデオ出力がある場合、「card0-CON-n」という形式の名前を取得します。「CON」はコネクタのタイプ(VGA、HDMI、DVI、など)、「n」はコネクタのシリアル番号です(さらに、一部のメーカーは「0」で始まるコネクタに番号を付け、他のメーカーは「1」で番号を付けます)。 次のビデオカードは「card1」などになります。



何も行われない場合、検出の並列性を考慮して、次にcard1をオンにしたときにcard0になる可能性があります。 Udevは、そのようなデバイスを1つまたは別の名前で/ devに追加します。 このようなudevの動作が望ましくない場合は、インターネットで詳細に説明されており、主にさまざまなUSBデバイスについて説明しています。 しかし、ビデオカードを検出した場合、特定のプログラムを実行する必要があります。これについては後で説明しますが、今のところ、udevの目的を確認しましょう。



udevがビデオカードについて知っているのと同じことを見つけるために、クライアントでコマンドを入力します。

 udevadm info -a -p /sys/class/drm/card0
      
      





コマンド出力
Udevadm情報は、devpathで指定されたデバイスで始まり、次に

親デバイスのチェーンをたどります。 すべてのデバイスについて印刷します

見つかった、udevルールキー形式のすべての可能な属性。

一致するルール。デバイスの属性で構成できます

単一の親デバイスからの属性。



デバイス「/devices/pci0000:00/0000:00:02.0/drm/card0」を見る:

KERNEL == "card0"

サブシステム== "drm"

ドライバー== ""



親デバイス「/devices/pci0000:00/0000:00:02.0」を見る:

KERNELS == "0000:00:02.0"

サブシステム== "pci"

ドライバー== ""

ATTRS {irq} == "18"

ATTRS {subsystem_vendor} == "0x0000"

ATTRS {broken_parity_status} == "0"

ATTRS {class} == "0x030000"

ATTRS {driver_override} == "(null)"

ATTRS {consistent_dma_mask_bits} == "32"

ATTRS {dma_mask_bits} == "32"

ATTRS {local_cpus} == "00000000,00000000,0000000000,00000,000000000001"

ATTRS {device} == "0xbeef"

ATTRS {enable} == "1"

ATTRS {msi_bus} == "1"

ATTRS {local_cpulist} == "0"

ATTRS {ベンダー} == "0x80ee"

ATTRS {subsystem_device} == "0x0000"

ATTRS {boot_vga} == "1"

ATTRS {numa_node} == "-1"

ATTRS {d3cold_allowed} == "0"



親デバイス '/ devices / pci0000:00'を見る:

KERNELS == "pci0000:00"

サブシステム== ""

ドライバー== ""



親デバイスと子デバイスのパラダイムを使用して、ツリー構造に注意してください。 「…を見て」で始まる行は、/ sysディレクトリに関連するこのデバイスへのパスを示しています。つまり、パス/ sys / class / drm / card0に沿ったビデオカードを参照して、これは実際にリンクであることがわかりました/sys/devices/pci0000:00/0000:00:02.0/drm/card0。



親デバイス/devices/pci0000:00/0000:00:02.0には、製造元識別子を持つベンダー属性があります。 Udevは広範なデータベースにアクセスでき、このコードを消化可能な形式に変換できます。

 udevadm info -q property -p /sys/devices/pci0000:00/0000:00:02.0 DEVPATH=/devices/pci0000:00/0000:00:02.0 ID_MODEL_FROM_DATABASE=VirtualBox Graphics Adapter ID_PCI_CLASS_FROM_DATABASE=Display controller ID_PCI_INTERFACE_FROM_DATABASE=VGA controller ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible controller ID_VENDOR_FROM_DATABASE=InnoTek Systemberatung GmbH MODALIAS=pci:v000080EEd0000BEEFsv00000000sd00000000bc03sc00i00 PCI_CLASS=30000 PCI_ID=80EE:BEEF PCI_SLOT_NAME=0000:00:02.0 PCI_SUBSYS_ID=0000:0000 SUBSYSTEM=pci USEC_INITIALIZED=24450
      
      





コマンドの出力と比較します。

 lspci | grep -i vga 00:02.0 VGA compatible controller: InnoTek Systemberatung GmbH VirtualBox Graphics Adapter.
      
      







udevを使用してビデオカードを動的に構成する



ブートサーバーに接続します。 ルールファイルを作成します。

 export root=/srv/nfs/diskless nano $root/etc/udev/rules.d/10-graphics.rules KERNEL=="card[0-9]*", SUBSYSTEM=="drm", RUN+="/etc/default/xdevice %n" KERNEL=="card*", SUBSYSTEM=="drm", ATTR{enabled}=="enabled", ATTR{status}=="connected", RUN+="/etc/default/xdevice %n %k"
      
      





各ルールは新しい行に書かれています。 最初の部分は、行の最後に示されたアクションが適用されるべきudevイベントを識別するために使用されます。 イベントを識別するために、コマンド「udevadm info -a -p / sys ...」の出力で取得できるデータが使用されます。



最初の行のルールは、drmサブシステムの名前(コア)card0、card1 ...を持つすべてのデバイスに対して機能します。 2番目のルールは、モニターが現在接続されているdrmサブシステムのアクティブなデバイスでのみ機能します(card0、card1では機能しませんが、card0-HDMI-1という形式の名前でのみ機能します。ステータス)。 イベントがその説明と一致する場合、同じプログラムが実行されます。最初の場合、1つのパラメーターが渡されます%n(カーネルのシリアル番号、card0の場合は「0」)、2番目の-追加のパラメーター%k(カーネル名自体card0 ")。



プログラム/ etc / default / xdeviceは、/ etc / X11 / xorg.conf.d /フォルダー内のファイルの内容を変更します。これには、xorgのビデオアダプターの設定に関する情報が含まれています。 メーカーごとに、実装機能を考慮したさまざまなテンプレートを用意します。 デバイスを一意に識別するために最低限必要な情報を指定するだけで十分で、残りはxorgが自動的に行います。

 Section "Device" Identifier "  " Driver " " Option "AccelMethod" " " BusID "PCI:  PCI,    " EndSection
      
      





テンプレート自体に必要なデータを示すか、udevadm infoコマンドの出力を調べて取得します。



プログラムは、モニターが接続されている各ビデオカードの各出力に対してトリガーされます。 タスクを簡素化するために、最後に検出されたオプションを機能させて、少なくとも1つのモニターがマルチモニターシステムで機能するようにします。 これは設定するのに最適な方法ではなく、graphical.targetに到達する前にグラフィックスサブシステムを一度確認することをお勧めしますが、このオプションは機能し、実際のudevルールを学習するのに適しています。

次の内容のプログラムファイルを作成します。

 nano $root/etc/default/xdevice
      
      





非表示のテキスト
 #!/bin/sh #         xorg CONF_FILE=/etc/X11/xorg.conf.d/20-device.conf #        ""  #     ,       get_vendor(){ local card=$(get_path $1) udevadm info -q property -p ${card%\/drm*} | \ awk '/^ID_VENDOR_FROM_DATABASE/{split($1,a,"=");print tolower(a[2])}' } #    PCI         x:y:z get_bus(){ local bus=$(get_path $1) echo ${bus%\/drm*} | \ sed 's\:\.\g' | \ awk '{n=split($0,a,".");printf "%i:%i:%i",a[n-2],a[n-1],a[n]}' } #      get_path(){ udevadm info -q path -p /sys/class/drm/$1 } #          . make_conf(){ local filename="xorg-device-$(get_vendor $1).conf" cat /etc/X11/$filename | \ sed 's\%BUS%\'$(get_bus $1)'\g'| \ sed 's\%ID%\'$1'\g' > $CONF_FILE } #    virtualbox,      check_vbox(){ local vendor=$(get_vendor $1) [ "$vendor" == "innotek" ]] && systemctl start vboxservice } #  card_numb=$1 if [ -z "$2" ] #    virtualbox then card_name="card$card_numb" check_vbox $card_name && make_conf $card_name else card_name=$2 make_conf $card_name fi
      
      







ファイルを実行可能にします。

 chmod +x $root/etc/default/xdevice
      
      





VirtualBoxサービスの自動読み込みを無効にします。これは、必要な場合にのみプログラムによって起動されるためです。

 systemctl disable vboxservice
      
      





主要メーカー向けに最適化された設定で、xorg設定ファイルテンプレートを追加します。

 nano $root/etc/X11/xorg-device-intel.conf Section "Device" Identifier "Intel %ID%" Driver "intel" Option "AccelMethod" "uxa" BusID "PCI:%BUS%" EndSection
      
      





AMD、nVidia、VirtualBox
 nano $root/etc/X11/xorg-device-innotek.conf Section "Device" Identifier "VirtualBox %ID%" Driver "vboxvideo" BusID "PCI:%BUS%" EndSection
      
      







 nano $root/etc/X11/xorg-device-advanced.conf Section "Device" Identifier "AMD %ID%" Driver "radeon" Option "AccelMethod" "exa" BusID "PCI:%BUS%" EndSection
      
      







 nano $root/etc/X11/xorg-device-nvidia.conf Section "Device" Identifier "nVidia %ID%" Driver "nouveau" Option "AccelMethod" "exa" BusID "PCI:%BUS%" EndSection
      
      







テンプレートを追加し、これらのデバイス用のドライバーをインストールすることを忘れないでください。 コメントに検証済みの組み合わせを示します。



xorgのセットアップの最後に、「Windowsのように」キーボードレイアウトをAlt + Shiftで切り替えます。

 nano $root/etc/X11/xorg.conf.d/50-keyboard.conf Section "InputClass" Identifier "keyboard-layout" MatchIsKeyboard "on" Option "XkbLayout" "us,ru" Option "XkbVariant" ",winkeys" Option "XkbOptions" "grp:alt_shift_toggle" EndSection
      
      







システムを最適化する



Archlinux すべてのコンポーネントのログはログに保存されます 。 すべてをそのままにしておくと、ログが非常に大きく膨張する可能性があるため、そのサイズを制限します(30MBなど)(行の追加またはコメント解除):

 nano $root/etc/systemd/journald.conf ... SystemMaxUse=30M ...
      
      





各アクションは/ var / log / journalフォルダーに記録されます。 私たちの場合、データ伝送はネットワーク上で実行されますが、実際には帯域幅は狭くなっています。 ログでフォルダを削除できます。フォルダはRAMにのみ保存され、ディスクレスクライアントに最適です。



 rm -r $root/var/log/journal
      
      





アプリケーションの操作におけるさまざまなエラーについては、自動カーネルダンプが/ var / lib / systemd / coredumpフォルダーに作成されます。 同じ理由でそれらを無効にします:



 nano $root/etc/systemd/coredump.conf ... Storage=none ...
      
      







SWAPを無効にします。



 echo -e 'vm.swappiness=0\nvm.vfs_cache_pressure=50' > $root/etc/sysctl.d/99-sysctl.conf
      
      







不要なローカライズを削除します。 この簡単なアクションにより、65 MB以上節約できます。 同時に、 AURのプログラムがどのようにインストールされているかを見てみましょう(実際、ソースから収集されます)。 通常のユーザーとしてブートサーバーにログインし、次の手順を実行します。

 curl -o localepurge.tar.gz https://aur.archlinux.org/packages/lo/localepurge/localepurge.tar.gz tar -xvvzf localepurge.tar.gz cd localepurge makepkg -s
      
      





パッケージの準備ができました。 リポジトリからではなくファイルからインストールするため、SキーはUに置き換えられます(収集したプログラムのバージョンが私のものと一致しない場合は、ファイル名を修正します)。

 sudo pacman --root $root --dbpath $root/var/lib/pacman -U localepurge-0.7.3.4-1-any.pkg.tar.xz
      
      





さあ、セットアップしましょう。 ファイルの先頭にある「NEEDCONFIGFIRST」行をコメント化し、最後に使用されるローカライズを指定します。

 nano $root/etc/locale.nopurge ... # NEEDSCONFIGFIRST ... ru ru_RU ru_RU.UTF-8 en en_US en_US.UTF-8
      
      





プログラムを構成して実行します。

 arch-chroot $root /usr/bin/localepurge-config arch-chroot $root localepurge
      
      







読み取り専用に移動



既存のシステムを複数のコンピューターに同時にロードしようとすると、すべてのコピーがサーバー上の同じフォルダーを変更します。 あるクライアントがファイルを削除すると、別のクライアントで予期せずに消えます。 変更から身を守る最も確実な方法は、読み取り専用モードにすることです。



問題は、システムの通常の操作には、一部のフォルダーにデータを書き込む機能が必要なことです。 表面のソリューション-これらのフォルダーをfstab経由でtmpfsとして接続する-は、たとえば/ var / logに最適です。 しかし、たとえば/ etcディレクトリを使用すると、udevルールがそこのファイルを変更し、他のプログラムがそのファイルを積極的に使用するため、どうすればよいでしょうか? マウントする前にどこかに情報を保存してから、書き直すことができます。 または、すぐに別の場所にすべてを転送してから、それを返します。 1つ明らかなのは、システムを長時間テストおよび監視して、他のフォルダーを書き込み可能にする方法を理解するか、重要な製品を厳密に指定された場所に残すようにすべてのプログラムを構成する必要があることです。 トリッキーすぎる。 システム全体をRAMに展開することを提案します。 作業に必要なすべてのものを事前に書き直すだけです。



操作中に何も書き込まれないフォルダーが1つあります。何もインストールしない場合は、/ usrです。 読み取り専用アクセスでinitramfsの後半にマウントした場合、Firefoxはまったく影響を受けません。 / usrディレクトリのサイズを他のすべてのサイズと比較してください。コピーする余地はあまりありませんが、余分なものをすべて除外すると... rsyncについても考えたことがありますか?



その場でファイルシステムをやり直す



クライアントにrsyncをインストールします。



 pacman -S rsync
      
      





コピーを行うのはintramfs次第であるため、新しいハンドラーが必要です。それを「ライブ」と呼びましょう。 まず、findmntユーティリティを使用して/ etc / fstabファイルを分析し、元のルートディレクトリに必要なすべてのマウントオプションを保存します。 次に、ルートディレクトリを/ new_rootフォルダからアンマウントします。このフォルダは常にinitramfs内にあります。 その代わりに、書き込み機能を持つramfsを作成し、マウントポイント/ srv / new_rootを準備します。ここで、元のルートディレクトリを返します。 読み取り専用モードでバインドする/ usrフォルダーを除き、最も必要なすべてのファイルとディレクトリを書き換えるだけです。 ramfs内のファイルのコピーは、読み取りおよび書き込み可能になります。

 nano $root/etc/initcpio/hooks/live
      
      





cat $ root / etc / initcpio / hooks / live
 #!/usr/bin/bash run_latehook() { local source options fstype local target="/" local fstab=/new_root/etc/fstab local place=/new_root/srv/new_root local filter=${place}/etc/default/live_filter if source=$(findmnt -snero source --tab-file=$fstab -T $target); then options=$(findmnt -snero options --tab-file=$fstab -T $target) fstype=$(findmnt -snero fstype --tab-file=$fstab -T $target) umount /new_root mount -t ramfs none /new_root -o rw,defaults [ ! -d "$place" ] && mkdir -p $place mount ${fstype:+-t ${fstype}} ${options:+-o ${options}} $source $place mount -o remount,ro${options:+-,${options}} $source $place rsync -aAX ${place}/* /new_root --filter="merge $filter" ! findmnt -snero source --tab-file=$fstab -T /usr && bind_usr $place #     "/"   , #      fstab cat ${place}/etc/fstab | grep -v $source > $fstab fi } bind_usr(){ local place=$1 mount --bind ${place}/usr /new_root/usr mount -o remount,ro,bind ${place}/usr /new_root/usr }
      
      







/ etc / fstabファイルを2回参照します。1回目はルートディレクトリのマウントパラメーターに関する情報を取得し、2回目はfstabの/ usrに情報があるかどうかを確認します。 Archlinuxでの/ usrのレイトマウントには、特別なusrハンドラがありますが、これは作業に干渉しません。 / usrが特別な方法でマウントされている場合、ハンドラーはそれをスキップします。



テキストでは、ファイル/ etc / default / live_filterにrsync向けのフィルタリングルールが記載されていますが、準備する必要があります。 ハンドラーのインストーラーからこれを自動的に行います。



 nano $root/etc/initcpio/install/live #!/usr/bin/bash build() { make_filter > /etc/default/live_filter add_binary "/usr/bin/rsync" "/bin/rsync" add_binary findmnt add_runscript } make_filter() { cat <<EOF + /etc/* + /home/* + /home/*/.config - /home/*/*/ + /var/* - /var/cache/*/* - /var/lib/pacman/*/* - /var/lib/systemd/*/* + /var/log/*/ - /var/log/* - /var/tmp/* - /*/* EOF }
      
      





Rsyncは、1つのディレクトリを超えて「表示されません」。 ディレクトリ内のファイルとフォルダは、最初の一致まで順番に各ルールによってチェックされます(「+」-オブジェクトがコピーされ、「-」-オブジェクトはコピーされません)。 一致するものがない場合、ファイルがコピーされ、ディレクトリが空で作成されます。 次に、rsyncは「生き残った」ディレクトリに入り、その内容に再びルールを適用します。 これがまったくなくなるまで繰り返されます。



この場合、ルートディレクトリはどのルールにも該当しないため、その構造は完全に転送されます(すべてのファイルがコピーされ、空のディレクトリが作成されます)。 ディレクトリ/ boot、/ dev、/ lost + found、/ mnt、/ opt、/ proc、/ root、/ run、/ srv、/ sys、/ tmpは最後のルール「-/ * / *」などに該当します。 e。 それらのコンテンツはどこにもコピーされませんが、それら自体が作成されます。 / etcディレクトリはすぐに "+ / etc / *"ルールに該当し、そのすべてのコンテンツがコピーされますが、最初は同じディレクトリ内でのみ(将来、ネストレベル/ etc / * /のため、その構造全体が順番に転送されます)それ以上のルールはありません)。 /ホームディレクトリは同様の始まりを待っています-すべてのユーザーのフォルダは「+ / home / *」ルールに該当し、コピーで再作成されます(これまでは空です)。 次のルール「+ /home/*/.config」は各ユーザーのホームフォルダーにネストされた.configディレクトリをコピーし、「-/ home / * / * /」は他のすべてのディレクトリを除外します(ルールは「レスキュー」ディレクトリの後に来るため、 /home/*/.configは機能しません)。 ホームディレクトリのファイル自体については何も言われていないため、完全に移植可能です。 これらのディレクトリが作成されていないため、除外されたサブディレクトリのファイルはコピーされません。 「-/ var / cache / * / *」ルールは、/ var / cache内のディレクトリ構造全体を保持しますが、その内容は移行されません。 他のルールも同様に機能します。



備考
外部ファイル/ etc / default / live_filterにあるrsyncのルールは、initramfsを再作成することなく、必要に応じて変更できます。 コメントにルールのバージョンが表示されてうれしいです。



Rsyncには多くの可能性があります(rsyncの男-ほぼ3,000行)。 コメントでinitramfs内でrsyncを使用するエキゾチックな方法を提案しますか



理論的には、rsyncはトレントに置き換えて、ルートファイルシステムを構築できます。


initramfsにハンドラーを追加します。



 cat $root/etc/mkinitcpio.conf ... HOOKS="base udev net_nfs4 live"
      
      





initramfsを生成します。



 arch-chroot $root mkinitcpio -p habr
      
      





nfs4 +ライブ
サーバーとクライアントはVirtualBoxで動作します。

ソースファイルシステム:



 cat $root/etc/fstab # <file system> <dir> <type> <options> <dump> <pass> 192.168.1.100:/diskless / nfs4 defaults,noatime 0 0
      
      





ライブハンドラーの実行後、ロードされたクライアント上のファイルシステムの状態:



 mount ... none on / type ramfs (rw,relatime) 192.168.1.100://diskless on /srv/new_root type nfs4 (ro,noatime,vers=4.1,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.131,local_lock=none,addr=192.168.1.100) 192.168.1.100://diskless/usr on /usr type nfs4 (ro,noatime,vers=4.1,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.131,local_lock=none,addr=192.168.1.100) ...
      
      





サーバーへのクライアントのロード中に、次のデータが収集されました。



 vnstat -l ... eth0 / traffic statistics rx | tx --------------------------------------+------------------ bytes 7,23 MiB | 252,33 MiB --------------------------------------+------------------ max 5,11 Mbit/s | 235,23 Mbit/s average 1,48 Mbit/s | 51,68 Mbit/s min 0 kbit/s | 1 kbit/s --------------------------------------+------------------ packets 82060 | 199036 --------------------------------------+------------------ max 6550 p/s | 21385 p/s average 2051 p/s | 4975 p/s min 0 p/s | 0 p/s --------------------------------------+------------------ time 40 seconds
      
      









ネットワークのオーバークロック



物理的に、当然、ネットワークのオーバークロックは機器を交換しないと不可能になりましたが、ソフトウェアの最適化は禁止されていません。 リンクされた/ usrフォルダーの内容をネットワーク経由で転送する必要があります。 このデータを送信することはできませんが、それらが占有するスペースを削減することができます-アーカイブするために。サーバーで圧縮し、クライアントで解凍すると、理論的には同じネットワークを介して単位時間あたりにより多くのデータが送信されます。



squashfsファイルシステムは、通常のファイルシステムと同様に、アーカイバの機能を組み合わせ、fstabを介してアーカイブをマウントします。このファイルシステムの主な欠点-書き込みモード(読み取り専用)で動作できないこと-は、私たちにとって欠点ではありません。



 pacman -S squashfs-tools && mksquashfs $root/usr $root/srv/source_usr.sfs -b 4096 -comp xz
      
      







次のようにマウントします。

 nano $root/etc/fstab # <file system> <dir> <type> <options> <dump> <pass> 192.168.1.100:/diskless / nfs4 defaults,noatime 0 0 /srv/new_root/srv/source_usr.sfs /usr squashfs loop,compress=xz 0 0
      
      





initramfsの後期段階で、usrハンドラーは/ usrフォルダーのマウントに関与しますが、これは少し修正する必要があります。



 cp $root/{usr/lib,etc}/initcpio/install/usr && cp $root/{usr/lib,etc}/initcpio/hooks/usr
      
      





マウント行は次のようにする必要があります。



 nano $root/etc/initcpio/hooks/usr mount "/new_root$usr_source" /new_root/usr -o "$mountopts"
      
      





usrに合わないもの
«file system» fstab "/new_root/srv/new_root/usr/source_usr.sfs". systemd , . /new_root c initrams, systemd . , .


 cat $root/etc/mkinitcpio.conf HOOKS="base udev net_nfs4 live usr" arch-chroot $root mkinitcpio -p habr
      
      





nfs4 + live + squashed / usr
:



 cat $root/etc/fstab # <file system> <dir> <type> <options> <dump> <pass> 192.168.1.100:/diskless / nfs4 defaults,noatime 0 0 /srv/new_root/srv/source_usr.sfs /usr squashfs ro,loop,compress=xz 0 0
      
      





live usr:



 mount ... none on / type ramfs (rw,relatime) 192.168.1.100://diskless on /srv/new_root type nfs4 (ro,noatime,vers=4.1,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.131,local_lock=none,addr=192.168.1.100) /srv/new_root/srv/source_usr.sfs on /usr type squashfs (ro,relatime) ...
      
      





:



 vnstat -l ... eth0 / traffic statistics rx | tx --------------------------------------+------------------ bytes 5,07 MiB | 205,67 MiB --------------------------------------+------------------ max 4,02 Mbit/s | 191,82 Mbit/s average 1,04 Mbit/s | 42,12 Mbit/s min 0 kbit/s | 1 kbit/s --------------------------------------+------------------ packets 65524 | 159941 --------------------------------------+------------------ max 5954 p/s | 17170 p/s average 1638 p/s | 3998 p/s min 0 p/s | 0 p/s --------------------------------------+------------------ time 40 seconds
      
      









データは、前回よりも約20%少なく転送する必要がありました。ルートディレクトリ全体を1つのファイルにパックすると、ライブハンドラーがサーバーからの圧縮データを入力してramfsを設定します。



rsyncフィルターのルールを変更して/srv/source_usr.sfsファイルをramfsにコピーし、新しい場所からfstabを介してマウントします。システム全体がRAMにある場合は、ブートサーバーから切断してみてください。



余分なものを取り除く



ここを参照した場合、「サーバーからファイルをどのように提供しますか?」という質問はありません。もちろん、NFSを介してsquashfsデータを転送できます(上記で発生しました)が、通常のディスクと同様に操作できる、あまり文書化されていないネットワークブロックデバイスソリューションがあります。これは「ファイルシステム」ではなく「ブロックデバイス」であるため、データを圧縮できる任意のファイルシステムを使用できます。読み取りおよび書き込みアクセスの場合、zlibアーカイブを備えたbtrfsで対応できますが、書き込みの必要はなく、squashfsで十分です。



起動時にinitramfsからNBDサーバーに接続できるようにするには、AURからmkinitcpio-nbdパッケージをダウンロードする必要があります(通常のユーザーの権限でダウンロードしてコンパイルする必要があります)。



 curl -o mkinitcpio-nbd.tar.gz https://aur.archlinux.org/packages/mk/mkinitcpio-nbd/mkinitcpio-nbd.tar.gz tar -xvvzf mkinitcpio-nbd.tar.gz cd mkinitcpio-nbd makepkg -s sudo pacman --root $root --dbpath $root/var/lib/pacman -U mkinitcpio-nbd-0.4.2-1-any.pkg.tar.xz
      
      







ファイルの最後に新しいメニュー項目を追加します$ root / boot / grub / grub.cfg:



 cat $root/boot/grub/grub.cfg menuentry "NBD" { load_video set gfxpayload=keep insmod gzio echo " ..." linux vmlinuz-linux \ add_efi_memmap \ ip="$net_default_ip":"$net_default_server":192.168.1.1:255.255.255.0::eth0:none \ nbd_host="$net_default_server" nbd_name=habrahabr root=/dev/nbd0 echo "  ..." initrd initramfs-linux.img }
      
      





ご覧のとおり、変更された行は1行のみです。



 nbd_host="$net_default_server" nbd_name=habrahabr root=/dev/nbd0
      
      





NBDサーバーに接続すると、/ dev / nbd0という名前のブロックデバイスがクライアントに表示されるため、通常のディスクのように扱います。



 nano $root/etc/fstab # <file system> <dir> <type> <options> <dump> <pass> /dev/nbd0 / squashfs ro,loop,compress=xz 0 0
      
      







NBDサーバーの最近のバージョンでは、不快な機能が登場しています(これはおそらくバグです)。NBDクライアントがサーバーとの接続を確立し、接続を正しく完了せずに突然シャットダウンした場合、サーバー上で不完全なプロセスとして「ハングアウト」し続けます。クライアントがブート中にNBDに再接続しようとすると、サーバーは古い接続がアクティブであることを考慮して新しい接続を作成しない可能性があります。NBDに接続する直前にnetcat経由でIPアドレスをサーバーに送信して、このIPアドレスに関連付けられている古い接続を閉じることをお勧めします。



 cp $root/{usr/lib,etc}/initcpio/install/nbd cp $root/{usr/lib,etc}/initcpio/hooks/nbd
      
      





. :



 nano $root/etc/initcpio/hooks/nbd modprobe nbd #     msg "closing old connections..." echo ${ip} | nc ${nbd_host} 45678 local ready=$(nc -l -p 45678) [ "$ready" -ne 1 ] && reboot msg "connecting..." #    
      
      





initramfs - net_nfs4, nbd:



 nano $root/etc/mkinitcpio.conf MODULES="loop squashfs" HOOKS="base udev net_nfs4 keyboard nbd live"
      
      





initramfs:



 arch-chroot $root mkinitcpio -p habr
      
      





$root/srv/source_usr.sfs $root — /usr , /usr:



 mksquashfs $root/* /srv/new_root.sfs -b 4096 -comp xz
      
      









パッケージをインストールします。

 pacman -S nbd
      
      





NBD :



 mv /etc/nbd-server/{config,config.old} && nano /etc/nbd-server/config [generic] user = nbd group = nbd [habrahabr] exportname = /srv/new_root.sfs timeout = 30 readonly = true multifile = false copyonwrite = false
      
      





すべてが非常に簡単です。habrahabrという名前のボールを作成し、ファイルを参照し、接続タイムアウトを設定し、読み取り専用モードで配布し、ファイルを1つだけ与えます。copyonwrite関数は必要ありません。Copyonwriteを使用すると、複数のクライアントが同じディストリビューションを同時に使用して、各クライアントが元のファイルに加えられたすべての変更が記録される個別のファイルを作成できます。クライアントを切断すると、変更されたファイルは自動的に削除されます。この関数を使用すると、サーバーの速度が低下します。インターネット上のNBDに関する多くの情報はありませんが、人が決めます。



このファイルは、開いている接続に関連付けられているプロセスをチェックして終了します。



 nano /etc/default/close_passive_NBD_connections.sh #!/bin/sh #      PID _kill(){ local PID for PID in $* do kill $PID done } main(){ local rIP PIDs #       ip     grub.cfg rIP=$(netcat -l -p 45678 | cut -d: -f1) #     IP     PID PIDs=$(netstat -np | grep $rIP | awk '/^tcp.*nbd-server/{split($NF,a,"/");print a[1]}') _kill $PIDs && echo "1" | netcat -z $rIP 45678 } #     while [ 0 ] do main done
      
      





ファイルを実行可能にします:



 chmod +x /etc/default/close_passive_NBD_connections.sh
      
      





netcatおよびnetstatユーティリティを含むパッケージをインストールします。



 pacman -S gnu-netcat net-tools
      
      





NBDサービスの起動を変更します。



 mkdir -p /etc/systemd/system/nbd.service.d && nano /etc/systemd/system/nbd.service.d/close_passive.conf [Service] Type=oneshot ExecStart=/etc/default/close_passive_NBD_connections.sh
      
      





, , .



nbd + squashed live
:



 cat $root/etc/fstab # <file system> <dir> <type> <options> <dump> <pass> /dev/nbd0 / squashfs ro,loop,compress=xz 0 0
      
      





live usr:



 mount ... none on / type ramfs (rw,relatime) /dev/nbd0 on /srv/new_root type squashfs (ro,relatime) /dev/nbd0 on /usr type squashfs (ro,relatime) ...
      
      





:



 vnstat -l ... eth0 / traffic statistics rx | tx --------------------------------------+------------------ bytes 1,97 MiB | 198,92 MiB --------------------------------------+------------------ max 2,81 Mbit/s | 138,60 Mbit/s average 575,63 kbit/s | 58,20 Mbit/s min 2 kbit/s | 1 kbit/s --------------------------------------+------------------ packets 32473 | 100874 --------------------------------------+------------------ max 5991 p/s | 7576 p/s average 1159 p/s | 3602 p/s min 4 p/s | 1 p/s --------------------------------------+------------------ time 28 seconds
      
      







3% ( ). , NFS 10 , NBD .





ダウンロードを高速化してみましょう。ダウンロードチェーンで最も弱いリンクはTFTPサーバーです。それを完全に排除し、我々はできませんが、ブートローダを通じてその存在を最小限に抑えることができIPXE、両方の助言kvapsを前回の記事にコメントして。



ユーザー名としてブートサーバーに接続します。



ブートオプションを使用してメニューを実行するのではなく、現時点では自動的に最高速で起動します。



 nano ~/myscript.ipxe #!ipxe ifopen net0 set server_ip 192.168.1.100 set http_path http://${server_ip} set kern_name vmlinuz-linux kernel ${http_path}/${kern_name} || read void initrd ${http_path}/initramfs-linux.img || read void imgargs ${kern_name} add_efi_memmap ip=${net0/ip}:${server_ip}:${net0/gateway}:${net0/netmask}::eth0:none nbd_host=${server_ip} nbd_name=habrahabr root=/dev/nbd0 || read void boot || read void
      
      





HTTP経由でvmlinuz-linuxおよびinitramfsファイルを受け取る予定です。スクリプトをブートローダーに挿入しましょう:



 sudo pacman -S git && git clone git://git.ipxe.org/ipxe.git cd ipxe/src/ make bin/undionly.kpxe EMBED=/home/username/myscript.ipxe
      
      





サーバーのルートに戻り、ブートローダーをコピーします。



 cp {/home/username/ipxe/src/bin,$root/boot}/undionly.kpxe
      
      





DHCPサーバーを修正して、新しいファイルのダウンロードを提案します。



 nano /etc/dhcpd.conf #if option architecture = 7 { # filename "/grub/x86_64-efi/core.efi"; # } else { # filename "/grub/i386-pc/core.0"; #} filename "/undionly.kpxe"; systemctl restart dhcpd4
      
      







HTTPサーバーをインストールします。



 pacman -S apache
      
      





ローダーを含むフォルダーをサーバーの作業フォルダーに添付します。



 mount --bind /srv/nfs/diskless/boot/ /srv/http/
      
      





« »:



 mount -o remount,ro,bind /srv/nfs/diskless/boot/ /srv/http/
      
      





:



 systemctl start httpd
      
      







, :



 vnstat -l ... rx | tx --------------------------------------+------------------ bytes 1,50 MiB | 206,73 MiB --------------------------------------+------------------ max 2,96 Mbit/s | 191,95 Mbit/s average 684,08 kbit/s | 94,08 Mbit/s min 5 kbit/s | 1 kbit/s --------------------------------------+------------------ packets 22762 | 90737 --------------------------------------+------------------ max 5735 p/s | 9871 p/s average 1264 p/s | 5040 p/s min 3 p/s | 1 p/s --------------------------------------+------------------ time 18 seconds
      
      







TFTP HTTP iPXE. , , . , .





live . rsync /srv, . systemd:



 nano /etc/fstab LABEL=HABR / ext4 rw,relatime,data=ordered 0 1 /srv/new_root/srv /srv none bind 0 1
      
      





この場合、フォルダー/ srv / new_root / srvおよび/ srvは完全な読み取りおよび書き込みアクセスモードで接続されていますが、解決策はわかっています。



ブートサーバーが読み取り専用モードで動作できるという事実は、安価なUSBフラッシュドライブにインストールされたシステムに非常に役立ちます。このようなドライブでは、より多くのデータを読み取り、書き込みを少なくする方が適切です。インターネットで開くと、追加の保護が提供されます。たとえば、ルーターは安全なVPNチャネルを開き、その反対側にブートサーバーがあります...



システムをUSBフラッシュドライブに転送するには(原理はハードディスクと同じです)、コンピューターに挿入してVirtualBoxに接続する必要があります(デバイスメニュー> USBデバイスから必要なものを選択します)リスト)。使用可能なブロックデバイスのリストは、次のようにlsblkコマンドによってチェックされます。 . , HABR /mnt.



rsync:



 nano /root/clone_filter + /boot/* + /etc/* + /home/* + /srv/* + /usr/* + /var/* - /*/*
      
      





:



 rsync -aAXv /* /mnt --filter="merge /root/clone_filter"
      
      





— /dev/sdb

  arch-chroot /mnt grub-install --target=i386-pc --force --recheck /dev/sdb
      
      





/mnt .



PS . . . .



.



All Articles