目的
私は、Habrの多くの居住者と同様に、写真とGitoliteのアーカイブから個人および公共の多くのサービスを実行し、いくつかのWebサイトで終わるホーム「バルコニー」サーバーを持っています。 かつて私は、秩序を回復し、システムのセキュリティを強化するために、個人を一般から分離するという問題に戸惑っていました。 パブリックサービスを別の仮想マシンに転送することが決定されました。ハッキングされても、残りのデータは影響を受けず、バックアップからVMを簡単に復元できます。
同時に、私は冗長性がどうしても好きではないので、時間やディスクスペースなどのリソースの費用を最小限に抑えて、すべてのサービスに対して仮想マシンでサービスを開始したいと考えました。 追加の「ウィッシュリスト」は、個別にではなく、すべての仮想マシンで同じ種類のソフトウェアを同時に更新できることでした。
研究オプション
最初は、OpenVZを使用する可能性を探りましたが、いくつかの理由でOpenVZとは関係がありませんでした。 まず、特別なカーネルを使用する必要があります。私のシステムは、プロファイルが強化されたGentooとGrsecurityシステムであり、拒否したくありませんでした。 第二に、OpenVZは、ゲストシステム(コンテナ)内のこのメモリをすべて占有しようとした後、使用可能なメモリの最大量によって制限され、最終的にメインで動作するOOMプロセスの「強制終了」につながりました(!)システムであり、コンテナ内ではありません。 メインシステムの空きメモリが大量にあり、OpenVZを危険な状態から破壊したため、この動作に非常に驚きました。
幸いなことに、Xenが動作するために必要なものはすべて標準のLinuxカーネルにすでに含まれています。今後は、Dom0とDomUの両方が、強化されたカーネルで正常に動作します(わずかな変更があります)。
実装
参照仮想マシン(AMI)のイメージを作成する
上で述べたように、私のメインシステムはGentoo Linux amd64 3.8.6で強化されたSMPなので、仮想マシンではまったく同じシステムとまったく同じカーネルを使用します。 domU専用にカーネルを再構築したわけではなく、Xenハイパーバイザーのバックエンドとフロントエンドの両方のドライバーが含まれています。
仮想マシンの「テンプレート」については、作成する「インスタンス」に基づいて(AMIとAmazon EC2のインスタンスから類推できます)、別のLVM論理パーティションを作成し、
vmtemplate
という名前を付け
vmtemplate
。 このセクションにインストールされたGentoo(インストール手順は標準のGentooハンドブックの手順と同様です)、および仮想マシン内で最終的に動作するサービスに基づいて選択した追加のソフトウェア(それらの間の「差異」が最小限になるように)。 その結果、次の追加ソフトウェアのリストを入手しました。
- dev-lang / php
- dev-lang / v8
- dev-lang / erlang
- dev-python / django
- dev-ruby / rails
- www-apache /乗客
- www-apps / wordpress
- www-servers / nginx
スペースを節約するために、仮想マシンにパッケージをインストールすると、すべてのドキュメントが削除されます(make.confのnoman nodoc noinfoフラグ)。 ソフトウェアを便利に更新するために、参照仮想マシンの環境をすばやく開始および終了できる単純なスクリプトを作成しました。
#!/bin/sh ROOT=/mnt/gentoo DEV=/dev/xenguests/vm-template-gentoo echo "Mounting filesystems" mount $DEV $ROOT mount -t proc none $ROOT/proc mount --bind /dev $ROOT/dev mount --bind /usr/portage $ROOT/usr/portage cp /etc/resolv.conf $ROOT/etc/resolv.conf chroot $ROOT /bin/bash echo "Unmounting filesystems" umount $ROOT/dev $ROOT/proc $ROOT/usr/portage umount $ROOT
Xenハイパーバイザー自体のインストールプロセスは独創的なものではないため、インターネット上で豊富な指示を使用できます。 ただし、私と同じように、強化されたカーネルを使用する場合は、Xenのカーネルが非常に早い段階(画面に何も表示されていない場合)での起動を断固として拒否したことに注意してください。最初は、カーネルブートに到達しなかったと思いました。
死の前にハイパーバイザーが死んだという例外のアドレスをSystem.mapファイルの内容と比較することで、その理由はカーネルスタックで動作する関数にあり、カーネルで
CONFIG_PAX_RANDKSTACK
(カーネルスタックベースのランダム化)関数をオフにしたときにすべてが機能したことがわかりましたPAXに関連します。
参照に基づいて仮想マシンを作成する
まず、小さな余談:この問題を解決するために、LVMスナップショットを使用しようとしましたが、コピーオンライトで割り当てられた空き領域が非常に迅速にいっぱいになり、論理的には仮想マシン内にある場合、これは悪いソリューションであることが判明しました同じファイルを2回書き込むと、キャスト内の占有スペースの量は、記録されたファイルの2サイズ分増加します。 最適化が悪い。 ディスク領域の使用を最適化する問題を解決するために、私はaufsを使用することにしました。そして、最終的に、記事のタイトルに実際に記載されていることを実行します。
- 仮想マシンに対して、別の論理パーティションLVMを作成します
vm-site1
と呼びましょう。 私の場合、このパーティションのサイズは1 GBです(参照VMがあるパーティションのサイズは8 GBです)。 両方のパーティションのFSはext4です。 - メインシステムで
sys-fs/aufs3
をsys-fs/aufs3
ます-すぐに必要になります。
このエキゾチックな構成で仮想マシンを起動するには、パーティションをaufsに正しくマウントする特別なRAMディスクが必要です。 まず、
/etc/genkernel.conf
ファイルで、次の行のコメントを解除します
ALLRAMDISKMODULES="1"
-これは、新しくインストールしたaufsモジュールをramdiskにコピーするために必要です。これは、genkernelを使用して作成します。 これを行うためのよりエレガントな方法は見つかりませんでしたが、
/usr/share/genkernel
システムファイルを編集したくありませんでした。
作業ディレクトリで、
overlay
フォルダーを作成し、その中に
init
というファイルを作成します。
#!/bin/busybox sh mount -t proc -o noexec,nosuid,nodev proc /proc >/dev/null 2>&1 mount -o remount,rw / >/dev/null 2>&1 /bin/busybox --install -s if [ "$0" = '/init' ] then [ -e /linuxrc ] && rm /linuxrc fi modprobe xen-blkfront RO=/dev/xvda1 RW=/dev/xvda2 mknod /dev/xvda1 b 202 1 mknod /dev/xvda2 b 202 2 modprobe aufs mkdir /aufs mkdir /rw mkdir /ro mount $RO /ro mount $RW /rw mount -t aufs -o dirs=/rw:/ro=ro aufs /aufs [ -d /aufs/ro ] || mkdir /aufs/ro [ -d /aufs/rw ] || mkdir /aufs/rw mount --move /ro /aufs/ro mount --move /rw /aufs/rw cat /aufs/ro/etc/fstab | grep -v ' / ' | grep -v swap >> /aufs/etc/fstab ROTYPE=$(cat /proc/mounts | grep $RO | cut -d' ' -f3) ROOPTIONS=$(cat /proc/mounts | grep $RO | cut -d' ' -f4) RWTYPE=$(cat /proc/mounts | grep $RW | cut -d' ' -f3) RWOPTIONS=$(cat /proc/mounts | grep $RW | cut -d' ' -f4) echo $RO /ro $ROTYPE $ROOPTIONS 0 0 > /aufs/etc/fstab echo $RW /rw $RWTYPE $RWOPTIONS 0 0 >> /aufs/etc/fstab echo "cp /proc/mounts /etc/mtab" > /aufs/etc/local.d/mtab.start chmod a+x /aufs/etc/local.d/mtab.start echo "sysctl -w kernel.grsecurity.grsec_lock=1" > /aufs/etc/local.d/grsec.start chmod a+x /aufs/etc/local.d/grsec.start exec /sbin/switch_root -c "/dev/console" /aufs /sbin/init
その後、次のようなスクリプトを使用して、変更されたRAMディスクを作成します。
#!/bin/sh VERSION=`uname -r` MODULE=`modprobe -nv aufs | cut -d' ' -f2` if [ ! -f $MODULE ]; then echo "aufs module not found on your system" fi genkernel initramfs --no-install --no-postclear --initramfs-overlay=/home/xen/overlay cp -v /var/tmp/genkernel/initramfs-${VERSION} /boot/initramfs-domU
これで、仮想マシンはルートFSからaufsにブートできるようになり、すべての変更は
/dev/xvda2
に
/dev/xvda2
、
/dev/xvda1
は参照イメージであり、必要に応じて更新できるファイルであり、更新は「キャッチオン」されますすべての仮想マシン(マシンの参照イメージを更新する時点で停止する必要があります)。 特定の仮想マシンのデータセクション(この場合、
vm-site1
LVMパーティションには、参照FSとの違いのみが含まれます。ホストシステムに自由にマウントしたり、ファイルに変更を加えたり、バックアップを作成したりすることもできます。
仮想マシンを作成します。 これには、次の構成を使用します。
kernel = "/boot/vmlinuz" ramdisk = "/boot/initramfs-domU" memory = 128 name = "site1" vcpus = 1 disk = [ "phy:/dev/xenguests/vm-template,xvda1,r", "phy:/dev/xenguests/vm-site1,xvda2,w" ] root = "/dev/xvda1 ro" extra = "xencons=tty" on_poweroff = "destroy" on_reboot = "restart" on_crash = "destroy" vif = [ "mac=0a:11:10:24:14:20,bridge=br1" ] dhcp = "dhcp"
一意のMACアドレスに基づくさまざまな仮想マシンには、ホストシステム上のDHCPサーバーを介して静的IPアドレスが与えられ、DNSレコードが更新されるため、nginxへの接続をVM内のnginx Webサーバーに簡単に転送できます。ホストシステム上で、トラフィックをフィルタリングします。 さらに、host-nginxはSSLトラフィックを終了するために使用されます。
まとめ
達成された目標:
- 個々の仮想マシンのデータは、仮想マシン内にあるものの参照システムとの違いと同じくらいのスペースを占めるようになりました。 WordPressを使用するサイトの場合、この差は45 MBです。
- スクリプトを使用して「参照」環境に入ると、すべてのVMで同時に同じタイプのソフトウェアを同時に更新できます。