ただし、サービスとリソース制御を単純に分離するために、このようなコンテナはいくつかの前提条件で非常に適しています。 たとえば、コンテナのルートがターゲットシステムのルートに等しいと仮定します。
この記事では、LVMスナップショットを使用せずに、共有ファイルを使用してローカルディスク上に軽量コンテナーをすばやく作成する方法を示します。
LXCコンテナの本質について簡単に
LXCは、Linuxカーネルに仮想コンテナーを実装するためのツールです。 コアとなるLXCは、カーネルに実装された機能を活用するユーザースペースユーティリティの単なるコレクションです。 そのため、LinuxカーネルにはLXCの概念がありません。
コンテナの2つの主要コンポーネントは、名前空間とコントロールグループ(cgroup)です。 前者はコンテナプロセスを相互に分離し、後者はコンテナに割り当てられるリソースを制限する役割を果たします。
現在、有効な名前空間は次のとおりです。
- pid-プロセス識別子の名前空間
- mount-マウントされたファイルシステムの名前空間
- ネットワーク-コンテナ内に分離されたネットワークスタックを作成できます
- utsname-utsname構造の分離を提供します。 主に異なるホスト名を設定するために使用されます
- ipcはSysV IPC名前空間です。 共有メモリ、セマフォ、およびメッセージキューのIDは異なります。
- user-名前空間uid / gid
ちなみに、最後の名前空間はカーネルバージョン3.9に確定することが約束されています
これらのスペースは、コンテナを独立させるのに十分です。
最初は、システム内のすべてのプロセスが共通の名前空間を使用します。 新しいプロセスを作成するとき、このプロセスに必要な名前空間を複製するようにカーネルに指示できます。 これは、clone()を呼び出してCLONE_NEW *特殊フラグを指定することにより実現されます。 プロセスを作成するときに特定のネームスペースにこのフラグを指定することにより、プロセスが独自のネームスペースで作成されるようにします。 これがLXCユーティリティの仕組みであり、新しいコンテナを作成します。
unshare()を呼び出すことにより、既存のプロセスの名前空間を分離できます。 setns()を使用して、あるプロセス名前空間を別のプロセス名前空間に完全に置き換えることができますが、この呼び出しには新しいカーネル(> 3.0)のサポートが必要です。
コンテナにジャンプするために使用されるのはsetns()です。
制御グループと名前空間は、カーネルに実装されています。 ユーザー空間では、特殊なcgroupファイルシステムのインターフェイスを使用してLXCで使用できます。 LXCユーティリティは、コンテナの名前を使用してこのファイルシステムにディレクトリを作成し、プロセスのpidをコントロールグループファイルに書き込みます。 したがって、コンテナの名前は基本的にコントロールグループの名前です。
LXCコンテナーを作成するためのシステムの準備
多くのことが言われているので、このステップをスキップします。 たとえば、 こちら 。 構成の本質は、必要なオプションを使用してカーネルを構築し、ユーザースペースユーティリティをインストールすることです。
幸いなことに、最近のディストリビューションの多くのカーネルはこれらのオプションで既にコンパイルされているため、再構築はほとんど必要ありません。
libvirtを使用して仮想化を管理することに慣れている場合、朗報はlibvirtがLXCを完全にサポートしていることです。 彼に関する記事は「身体に近い」とは言われません。
コンテナのファイルシステムの基盤を作成する
通常、彼らはこれを行います:彼らはいくつかの基本的なLVMデバイスを作成し、それに基づいて各コンテナのファイルシステム用に別々のスナップショットを作成します。 したがって、スナップショットは変更されたブロックのサイズによってのみスペースを占有するため、これによりディスクスペースが節約されます。
オプションとして、lvmの代わりに、スナップショットをサポートするファイルシステム(btrfsなど)を使用することができます。
ただし、この方法には重大な欠点があります。lvmスナップショットを使用したディスク書き込み操作は非常に遅いです。
したがって、特定のタスクでは、次の方法を使用できます。
- 基本的なコンテナイメージを作成する
- それから一般的な不変部分を割り当てます
- 画像からこのパーツへのシンボリックリンクを作成する
- コンテナを作成するとき、このパーツをコンテナ内にマウントします
始めましょう。 ベースコンテナと同じLVMを使用します(ただし、これは完全にオプションです)。
$ mkdir -p /lxc/base $ mount /dev/mapper/lxc /lxc/base $ cat /.exclude /dev/* /mnt/* /tmp/* /proc/* /sys/* /usr/src/* /lxc $ rsync --exclude-from=/.exclude -avz / /lxc/base/ $ DEV="/lxc/base/dev" $ mknod -m 666 ${DEV}/null c 1 3 $ mknod -m 666 ${DEV}/zero c 1 5 $ mknod -m 666 ${DEV}/random c 1 8 $ mknod -m 666 ${DEV}/urandom c 1 9 $ mkdir -m 755 ${DEV}/pts $ mkdir -m 1777 ${DEV}/shm $ mknod -m 666 ${DEV}/tty c 5 0 $ mknod -m 600 ${DEV}/console c 5 1 $ mknod -m 666 ${DEV}/full c 1 7 $ mknod -m 600 ${DEV}/initctl p $ mknod -m 666 ${DEV}/ptmx c 5 2
コピーが完了したら、不変部分の作成に進みます。 それを共通と呼びましょう:
$ cd /lxc/base $ mkdir common $ mv bin lib lib64 sbin usr common/ $ ln -s common/bin $ ln -s common/sbin $ ln -s common/lib $ ln -s common/lib64 $ ln -s common/usr $ chroot /lxc/base $ > /etc/fstab
その後、/ etc / rc.sysinitからstart_udevを削除し、不要なサービスを無効にし、独自の裁量で追加設定を行います。 コンテナの起動時にホスト名が再定義されないように、構成ファイルからホスト名を削除します。
cgroupファイルシステムをマウントします。これにより、コンテナリソースが制限されます。 このプロセスは、ファイルシステム内にコンテナの名前でディレクトリを作成することで発生します。 ディレクトリはLXCユーティリティによって作成(および削除)されます。
$ mount -t cgroup -o cpuset,memory,cpu,devices,net_cls none /cgroup
Centos6 / RHEL6ディストリビューションではデフォルトでblkioコントローラーがマウントされるため、マウントするコントローラーを明示的に指定します。これは、LXCの動作に必要なネストされた階層をサポートしません。 Ubuntu / Debianはこれで問題ありません。
libcgroupのcgclearユーティリティも便利です。これは、コントロールグループをアンマウントするだけでなく、カーネルレベルでそれらを破壊します。 これは、個々のコントローラーを再マウントする際の-EBUSYエラーの防止に役立ちます。
次に、すべてのコンテナが接続するネットワークブリッジを作成します。 操作中にネットワークが失われることに注意してください。
$ brctl addbr br0 $ brctl addif br0 eth0 $ ifconfig eth0 0.0.0.0 $ ifconfig br0 10.0.0.15 netmask 255.255.255.0 $ route add default gw 10.0.0.1
すべての新しい仮想コンテナインターフェイスは、この新しいブリッジに含まれます。
ディストリビューションのスタートアップコンフィギュレーションファイルのすべての変更を反映することを忘れないでください。
LXCコンテナーを作成する
システムの基本イメージを準備したら、システムの最初のコンテナーの作成に直接進むことができます。 単にlxc-containerと呼びましょう。
コンテナを作成する手順には、3つの簡単な手順が含まれます。
- コンテナーfstabファイルの作成
- コンテナファイルシステムの準備
- コンテナー構成ファイルの作成
コンテナのfstabをセットアップします。
$ cat > /lxc/lxc-container.fstab << EOF devpts /lxc/lxc-container/dev/pts devpts defaults 0 0 proc /lxc/lxc-container/proc proc defaults 0 0 sysfs /lxc/lxc-container/sys sysfs defaults 0 0 EOF
ここで、ベースイメージの以前に作成された不変部分を使用して、最初のlxcコンテナのファイルシステムを準備します。
$ mkdir /lxc/lxc-container && cd /lxc/lxc-container $ rsync --exclude=/dev/* --exclude=/common/* -avz /lxc/base/ . $ mount --bind /lxc/base/dev /lxc/lxc-container/dev $ mount --bind /lxc/base/common /lxc/lxc-container/common $ mount -o remount,ro /lxc/lxc-container/common
最後の2行を1つにまとめることはできません。 いいでしょう
ご覧のとおり、ここで説明した方法の主な欠点(または主な利点)が明らかになります。 コンテナ内のファイルシステムの基本部分は読み取り専用です。
そして最後に、最も重要なことはコンテナ構成ファイルです。 この例では、lxcユーティリティがシステムのルートにインストールされていると想定しています
$ mkdir -p /var/lib/lxc/lxc-container $ cat > /var/lib/lxc/lxc-container/config << EOF # hostname lxc.utsname = lxc-name0 # tty lxc.tty = 2 # fstab lxc.rootfs = /lxc/lxc-container lxc.rootfs.mount = /lxc/lxc-container lxc.mount = /lxc/lxc-container.fstab # lxc.network.type = veth lxc.network.name = eth0 lxc.network.link = br0 lxc.network.flags = up lxc.network.mtu = 1500 lxc.network.ipv4 = 10.0.0.16/24 # /dev lxc.cgroup.memory.limit_in_bytes = 128M lxc.cgroup.memory.memsw.limit_in_bytes = 256M lxc.cgroup.cpuset.cpus = lxc.cgroup.devices.deny = a lxc.cgroup.devices.allow = c 1:3 rwm lxc.cgroup.devices.allow = c 1:5 rwm lxc.cgroup.devices.allow = c 5:1 rwm lxc.cgroup.devices.allow = c 5:0 rwm lxc.cgroup.devices.allow = c 4:0 rwm lxc.cgroup.devices.allow = c 4:1 rwm lxc.cgroup.devices.allow = c 1:9 rwm lxc.cgroup.devices.allow = c 1:8 rwm lxc.cgroup.devices.allow = c 136:* rwm lxc.cgroup.devices.allow = c 5:2 rwm lxc.cgroup.devices.allow = c 254:0 rwm EOF
明示的に示されたデバイスを除くすべてのデバイスへのアクセスを拒否し、メモリとスワップも制限していることに注意してください。 現在の無料ユーティリティの制限にもかかわらず、コンテナ内の上部には完全な物理メモリが表示されます。
ディストリビューションのスタートアップコンフィギュレーションファイルにすべての変更を反映することを忘れないでください。そうしないと、リブート後にすべて失われます。
LXCコンテナーを起動する
新たに作成されたコンテナを起動します。 これを行うには、lxc-startユーティリティを使用して、引数としてコンテナの名前を渡します。
$ lxc-start --name lxc-container
LXCコンテナーに接続する
LXCには、物理サーバーからコンテナーにジャンプする問題があります。
このために設計されたlxc-attachは、パッチを適用したカーネルでのみ動作します。 パッチは、特定のネームスペース(つまり、mount-namespaceおよびpid-namespace)の機能を実装します。 パッチ自体はここからダウンロードできます。
ジャンプ機能は、サードパーティのプロセスを既存のネームスペースにバインドする特別なシステムコールsetns()によって実装されます。
コンテナーへのジャンプを置き換えることができますlxc-console、コンテナーの仮想コンソールの1つに接続します
$ lxc-console --name lxc-container -t 2
そして、私たちの前にコンテナ/ dev / tty2のコンソールがあります
CentOS release 6.3 (Final) Kernel 2.6.32 on an x86_64 lxc-container login: root Password: Last login: Fri Nov 23 14:28:43 on tty2 $ hostname lxc-container $ tty /dev/tty2 $ ls -l /dev/tty2 crw--w---- 1 root tty 136, 3 Nov 26 14:25 /dev/tty2
デバイス/ dev / tty2のメジャー番号は136であり、「true tty」ではありません。 このデバイスは、物理端末でマスターが読み取られ、コンテナでスレーブが読み取られる疑似端末ドライバーによって提供されます。 つまり、/ dev / tty2は通常のデバイス/ dev / pts / 3です
そして、もちろん、ssh経由で接続できます:
$ ssh root@lxc-container
LXC操作
これは非常に興味深いですが、議論の別のトピックです。 ここで、コンテナを管理するためのタスクの一部はLXCユーティリティによって実行されますが、それらがなくても完全に実行できます。 そのため、たとえば、コンテナに分割されたシステム内のプロセスのリストを表示できます。
$ ps ax -o pid,command,cgroup
この場合のcgroupは、コンテナの名前と一致します