SDB:LXC

跳转到:导航搜索

更新的 LXC 信息

2015 年 11 月
本文档的大部分内容仅适用于 LXC 12.3。
对于 LEAP 和 13.2 中与 libvirt 的新实现和集成,
请遵循技术帮助论坛中发布的安装步骤
[安装 - 技术帮助论坛帖子]

请遵循此文档
[SLES 12 和 LEAP LXC 虚拟化文档(在线)]


2013 年 7 月
openSUSE 上更新的 LXC 信息可在 openSUSE 技术帮助论坛 - 虚拟化 上找到。您可以根据我的用户名 (TSU2) 进行搜索以查看我的帖子
以及我 wiki 中的特定文章

IMO,本文档中的信息仍然有效,但与今天的工具相比,操作起来很麻烦。
任何重做都会肯定涵盖此页面原始作者列出的需要涵盖的主题。

无论进行任何重做,我强烈建议出于存档目的保留此页面上的内容。

如果您想要一份完全重做、更新的 LXC 文档,请通过 PM(个人消息)联系我。这在我的待办事项清单上,但就像生活中的一切一样,优先级被赋予了。

.


序言

LXC 是一种形式的准虚拟化。作为一种超级 duper chroot 监狱,它仅限于运行 linux 二进制文件,但提供本质上的原生性能,就像这些二进制文件直接在主机内核中运行一样。事实上,它们就是这样。

LXC 的有趣之处主要在于

  • 它可以用于运行一个简单的应用程序、服务或一个完整的操作系统。
  • 它提供本质上的原生性能。作为 LXC 客户运行的二进制文件实际上作为正常的进程直接在主机操作系统内核中运行,就像任何其他进程一样。特别是这意味着 CPU 和 I/O 调度更加公平和可调,并且您可以获得原生磁盘 I/O 性能,而这是在真正的虚拟化中无法获得的(即使是 Xen,即使在准虚拟化模式下)。这意味着您可以容器化磁盘 I/O 密集型数据库应用程序。它还意味着您只能运行主机内核可以执行的二进制文件。(例如,您可以运行 Linux 二进制文件,而不是 Solaris 或 Windows 等其他操作系统)

LXC 是 Linux 内核的一个内置功能,自内核 2.6.29 起(openSUSE 11.2)
用户空间工具包含在 openSUSE 11.2 以来的“lxc”包中,位于主 oss 仓库中。
因此,从技术上讲,openSUSE 从 openSUSE 11.2 开始“支持”LXC

然而,实际上

  • 目前还没有 openSUSE 特定的文档,除了此页面。
  • 没有 openSUSE 版本的 lxc-fedora 或 lxc-debian 脚本,这些脚本可以自动执行构建或“安装”完整系统作为 lxc 客户的过程。
  • 没有像我们为 Xen 准备的漂亮前端实用程序和系统集成。

直到编写一个漂亮的前端实用程序或 YaST 模块,或者将 lxc-fedora 脚本移植到创建 lxc-suse,本 HOWTO 将仅描述设置 LXC 主机服务器和其中虚拟系统的一种方式。将运行 lxc 的硬件服务器称为主机,将在主机上运行的虚拟环境称为容器或容器。假设您已经在物理机器上安装了 openSUSE 11.2 或更高版本,并且知道如何管理和使用它。网上还有其他关于在基于 Debian 的系统中使用 LXC 的教程。此页面专门记录如何在 openSUSE 系统上执行相同的操作。

在本示例的其余部分中,容器名称将为vps0

我们将发明并遵循的约定是,容器配置文件位于 /etc/lxc/<container-name> 下,容器根文件系统位于 /lxc/<container-name> 下。

因此,在以下示例中,与此第一个容器关联的两个配置文件将是 /etc/lxc/vps0/config 和 /etc/lxc/vps0/fstab,容器的根文件系统将在 /lxc/vps0 下

容器的网络将通过桥接和 veth 实现。主机有一个名为 eth0 的网卡,地址为 192.168.0.100,位于 192.168.0.0/24 网络上。默认路由和名称服务器都是 192.168.0.1。容器将获得一个名为 192.168.0.50 的虚拟 eth0,并通过主机中的桥接设备(如虚拟集线器或交换机,无路由或 NAT)连接到与主机相同的 LAN。

容器还将有一个单独的控制台 tty,即使 SSH 或其他网络访问不起作用,也可以用于访问容器。

好的,我们开始吧...

主机设置

这是您在“真实”系统上一次性完成的操作,该系统将托管一个或多个容器。

在主机上安装 lxc 和 bridge-utils

zypper in lxc bridge-utils iputils screen inotify-tools kernel-default

您需要运行“-default”内核,而不是“-desktop”内核。

不幸的是,“-desktop”内核是目前默认安装的内核。

在安装 kernel-default 后,重新启动并从 grub 菜单中选择“-default”内核。然后卸载“-desktop”内核。

zypper rm kernel-desktop

在主机上设置控制组虚拟文件系统

awk 'BEGIN{E=1}($3=="cgroup"){E=0;exit}END{exit E}' /etc/fstab || echo "cgroup /cgroup cgroup defaults 0 0" >>/etc/fstab
M=`awk '($3=="cgroup"){print $2}' /etc/fstab`
[ -d $M ] || mkdir -p $M
mount -t cgroup |grep -qwm1 $M || mount $M

在主机上设置网络桥接设备

您应该在系统控制台或通过串行控制台执行此操作,因为您将暂时中断网络连接。

在主机系统上,yast,网络设备

  • 添加一个新的接口,类型:桥接,名称:br0
  • 将 eth0 添加到此桥接
  • 将 br0 的 IP 设置为主机上的 eth0 一样。eth0 变为“未配置”,br0 取代 eth0 作为主机访问 LAN 或互联网的接口。
  • 设置主机名、默认网关和名称服务器,如正常一样

YaST 中桥接定义屏幕的示例


YaST2 - lan @ lxchost

 Network Card Setup
 ┌General──Address──────────────────────────────────────────────────────────┐
 │ Device Type                Configuration Name                            │
 │ Bridge▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒↓  br0▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒  │
 │( ) Dynamic Address  DHCP▒▒▒▒▒▒▒▒▒▒↓  DHCP both version 4 and 6▒↓         │
 │(x) Statically assigned IP Address                                        │
 │IP Address           Subnet Mask           Hostname                       │
 │192.168.0.100▒▒▒▒▒▒▒ /24▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒             │
 │┌────────────────────────────────────────────────────────────────────────┐│
 ││┌Bridged Devices───────────────────────────────────────────────────────┐││
 │││[x] eth0 - 80003ES2LAN Gigabit Ethernet Controller (Copper)           │││
 │││[ ] eth1 - 80003ES2LAN Gigabit Ethernet Controller (Copper)           │││
 │││                                                                      │││
 │││                                                                      │││
 │││                                                                      │││
 │││                                                                      │││
 │││                                                                      │││
 ││└──────────────────────────────────────────────────────────────────────┘││
 │└────────────────────────────────────────────────────────────────────────┘│
 └──────────────────────────────────────────────────────────────────────────┘
[Help]                 [Back]                 [Cancel]                 [Next]

F1 Help  F9 Cancel  F10 Next

之后,此时,主机上的网络应该像使用典型的物理网卡一样正常工作。
主机网络应该如下所示

# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
    inet 127.0.0.2/8 brd 127.255.255.255 scope host secondary lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:30:48:7d:50:ac brd ff:ff:ff:ff:ff:ff
    inet6 fe80::230:48ff:fe7d:50ac/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:30:48:7d:50:ad brd ff:ff:ff:ff:ff:ff
    inet6 fe80::230:48ff:fe7d:50ad/64 scope link
       valid_lft forever preferred_lft forever
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether 00:30:48:7d:50:ac brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.100/24 brd 10.0.0.255 scope global br0
    inet6 fe80::230:48ff:fe7d:50ac/64 scope link
       valid_lft forever preferred_lft forever

# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.0030487d50ac       no              eth0

# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
192.168.0.0     0.0.0.0         255.255.255.0   U         0 0          0 br0
127.0.0.0       0.0.0.0         255.0.0.0       U         0 0          0 lo
0.0.0.0         192.168.0.1     0.0.0.0         UG        0 0          0 br0

# cat /etc/resolv.conf
search mydomain.com
nameserver 192.168.0.1

需要注意的是,eth0 存在,但没有 IP 地址或路由。

主机现在使用 br0 作为它的网卡,而不是 eth0。

br0 是一个桥接设备,可以包含几个实际和虚拟设备,目前仅包含 eth0 物理设备,因此主机上的所有正常网络应该像以前一样工作。稍后,容器将获得一个虚拟网卡,它也将添加到 br0,这样容器才能访问外部世界。br0 可以被认为是虚拟集线器或交换机。

容器设置

这是您一次性完成的操作(每个容器),以创建容器。

[更新:最新的 lxc 包包含一个 lxc-opensuse 模板脚本,该脚本可以自动执行、改进并基本上取代了大部分内容。应该用基于使用它的文档来替换它。]

编写容器的 lxc 配置文件

CN=vps0           # container name
CR=/srv/lxc/$CN       # /path/to/container_root_fs
CF=/etc/lxc/$CN   # /path/to/container_config_files
IP=192.168.0.50   # container nic IP
PL=24             # container nic ipv4 prefix length

# generate a MAC from the IP
HA=`printf "63:6c:%x:%x:%x:%x" ${IP//./ }`

# create the config directory
mkdir -p $CF

# lxc config file for container.
cat >${CF}/config <<%%
lxc.utsname = $CN
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.hwaddr = $HA
lxc.network.ipv4 = ${IP}/$PL
lxc.network.name = eth0
lxc.mount = ${CF}/fstab
lxc.rootfs = $CR
%%

# fstab for container
# it's outside of the container filesystem so that the container can not change it
cat >${CF}/fstab <<%%
none ${CR}/dev/pts devpts defaults 0 0
none ${CR}/proc    proc   defaults 0 0
none ${CR}/sys     sysfs  defaults 0 0
none ${CR}/dev/shm tmpfs  defaults 0 0
%%

填充容器文件系统

有几种不同的方法可以实现这一点。这将使用 zypper 从在线仓库安装一个基本系统到目录中,然后修改结果,以便在容器的上下文中运行。

CN=vps0           # container name
CR=/srv/lxc/$CN       # /path/to/container_root_fs
CF=/etc/lxc/$CN   # /path/to/container_config_files
IP=192.168.0.50   # container nic IP address
PL=24             # container nic ipv4 prefix length
GW=192.168.0.1    # container gateway (aka default route)
NS=$GW            # container nameserver

# create root filesystem directory
mkdir -p $CR

# container /dev
mkdir -p ${CR}/dev
cd ${CR}/dev
mknod -m 666 null c 1 3
mknod -m 666 zero c 1 5
mknod -m 666 random c 1 8
mknod -m 666 urandom c 1 9
mkdir -m 755 pts
mkdir -m 1777 shm
mknod -m 666 tty c 5 0
mknod -m 600 console c 5 1
mknod -m 666 tty0 c 4 0
ln -s null tty10
mknod -m 666 full c 1 7
mknod -m 600 initctl p
mknod -m 666 ptmx c 5 2
ln -s /proc/self/fd fd
ln -s /proc/kcore core
mkdir -m 755 mapper
mknod -m 600 mapper/control c 10 60
mkdir -m 755 net
mknod -m 666 net/tun c 10 200

# Use zypper to install a base system into a subdirectory.
# It's almost but not fully non-interactive.
# There are a few prompts you have to respond to manually.
zypper -R $CR ar -f http://download.opensuse.org/distribution/11.4/repo/oss/ oss
zypper -R $CR in -lt pattern base

# Remove some container-unfriendly packages.
zypper -R $CR rm udev hal grub gfxboot

# Put a copy of the fstab inside the container
cp -f ${CF}/fstab ${CR}/etc/fstab

# replacement /etc/init.d/boot
cp ${CR}/etc/init.d/boot ${CR}/etc/init.d/boot.orig
cat >${CR}/etc/init.d/boot <<%%
#! /bin/bash
rm -f /etc/mtab /var/run/*.{pid,lock}
touch /etc/mtab /fastboot
route add default gw $GW
exit 0
%%

# cut down inittab
cat >${CR}/etc/inittab <<%%
id:3:initdefault:
si::bootwait:/etc/init.d/boot
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l6:6:wait:/etc/init.d/rc 6
ls:S:wait:/etc/init.d/rc S
~~:S:respawn:/sbin/sulogin
p6::ctrlaltdel:/sbin/init 6
p0::powerfail:/sbin/init 0
cons:2345:respawn:/sbin/mingetty --noclear console screen
%%

# disable yast->bootloader in container
cat >${CR}/etc/sysconfig/bootloader <<%%
LOADER_TYPE=none
LOADER_LOCATION=none
%%

# nic in container
cat >${CR}/etc/sysconfig/network/ifcfg-eth0 <<%%
STARTMODE='auto'
BOOTPROTO='static'
IPADDR='${IP}/${PL}'
%%

# default route in container
echo "default $GW - -" >${CR}/etc/sysconfig/network/routes

# nameserver in container
echo "nameserver $NS" >${CR}/etc/resolv.conf

在容器内使用 shell 进行最终调整

运行 /bin/bash chrooted 到容器的根 fs,以便进行一些最终准备,例如添加登录用户并设置 root 密码,否则您将无法实际使用新的容器,即使它可能正在正常运行。您也可以稍后通过登录到容器的“控制台”来执行此操作。

lxchost:~# chroot ${CR}
/# passwd root
Changing password for root.
New Password:
Reenter New Password:
Password changed.
/# useradd -m operator
/# passwd operator
Changing password for operator.
New Password:
Reenter New Password:
Password changed.
/# exit
exit
lxchost:~#

运行

这是您需要定期执行的操作,只要需要,用于容器和/或主机系统的整个生命周期。启动、使用、关闭。

启动容器并登录

使用 gnu screen 启动完整的容器(即在其中运行 /sbin/init)。这允许您查看容器中的 rc 脚本输出的“控制台”消息,并允许您将该控制台分离到后台进程,并随时重新连接到它。在本例中,我们以先前添加的用户 operator 登录,并能够 sudo 到 root shell。

lxchost:~ # screen -S vps0 lxc-start -n vps0
[...]
Starting INET services. (xinetd)                                      done
Starting CRON daemon                                                  done
Master Resource Control: runlevel 3 has been                          reached
Skipped services in runlevel 3:                                       smartd

Welcome to openSUSE 11.2 "Emerald" - Kernel 2.6.31.8-0.1-default (console).


vps0 login: operator
Password: 

/~ su -
Password:
/#

按“ctrl-a d”从终端断开 screen 会话。

容器将继续在后台运行,您可以随时重新连接到“控制台”(screen 会话)。

访问正在运行的容器

此时,您可以以两种方式访问正在运行的容器。
有一个单独的控制台登录 tty,不需要容器中的工作网络即可访问。
要访问此控制台,只需重新连接到 screen 会话

lxchost:~ # screen -r vps0

(按“ctrl-a d”从 screen 会话断开连接)

或者,您可以从主机或网络上的任何其他地方通过 ssh 访问容器

ssh operator@192.168.0.50

停止容器

在容器内发出 "shutdown" 命令

首先,通过它的“控制台”(启动它的 screen 会话)登录到容器,并使用“shutdown -h now”关闭它。等待 init 完成。

lxchost:~ # screen -r vps0

Welcome to openSUSE 11.2 "Emerald" - Kernel 2.6.31.8-0.1-default (tty1).

vps0 login: operator
Password:
Last login: Fri Jan 29 17:46:40 UTC 2010 from lxchost on pts/21
Have a lot of fun...
operator@vps0:~> su -
Password: 
vps0:~ # shutdown -h now

Broadcast message from root (console) (Tue Feb  9 20:01:50 2010):

The system is going down for system halt NOW!
vps0:~ #
[...]
Shutting down service (localfs) network  .  .  .  .  .  .  .  .  .   done
Shutting down D-Bus daemon                                           done
Running /etc/init.d/halt.local                                       done
pidofproc: pidofproc: cannot stat /sbin/splash: No such file or directory

INIT: no more processes left in this runlevel

这就是我们等待的,所以现在按“ctrl-a d”从 screen 会话断开连接。

停止并销毁容器

现在,只有现在,才可以停止容器。

lxchost:~ # lxc-stop -n vps0
lxchost:~ # lxc-destroy -n vps0

只有在对主机上的所有容器执行上述操作后,才可以关闭主机。不要在不先关闭所有容器的情况下关闭主机。它不会自行优雅地发生!主机将优雅地关闭,并且主机会很好,但是对于所有容器系统来说,就像电源线被拔出一样,没有任何警告。

说明

Init 脚本

下面链接的 home:aljex 仓库有一个名为 rclxc 的包,它提供了 /etc/init.d/lxc 和 symlink /usr/sbin/rclxc,它将优雅地启动/停止所有配置的容器。

使用此包,您可以跳过手动启动/停止步骤和 cgroup fstab 设置。

您可以随时关闭主机,lxc init 脚本将在允许主机关闭之前优雅地关闭所有容器。

  • 启用启动时启动所有容器
chkconfig lxc on
  • 手动启动/停止所有容器
rclxc start
rclxc stop
  • 手动启动/停止名为“vps002”的单个容器
rclxc start vps002
rclxc stop vps002
  • lxc 的状态

“状态”在这种情况下仅表示整体 lxc“服务”是启动还是关闭。实际上并没有 lxc 服务,但如果任何容器正在运行,则“lxc”的状态被认为是启动的。只有当没有容器正在运行时,lxc 才被认为是关闭的。这可以防止主机在任何虚拟服务器仍在运行时关闭。

rclxc status
  • 列表

您可以使用“list”或“show”查看一个或所有单个容器的状态。

rclxc list
rclxc show vps002

init 脚本以 screen 会话启动每个容器,以便虚拟服务器的控制台是命名为容器的 screen 会话。

要列出所有容器控制台

screen -ls

要连接到容器控制台

screen -r vps002

要从容器控制台分离,请按 Ctrl-a d

vsftpd

截至撰写本文,LXC 以一种导致 vsftpd 与 LXC 冲突的方式使用 cgroups,因为 vsftpd 也在内部使用 cgroups。LXC 将切换到不同的方案,以避免将来出现此问题,但现在有必要将以下两个选项添加到任何容器 vps 中的 /etc/vsftpd.conf。

isolate=NO
isolate_network=NO

更改后,请记住重新启动 vsftpd。

rcvsftpd restart

参考:http://www.mail-archive.com/lxc-users@lists.sourceforge.net/msg01111.html

仍然缺失的内容

  • 更智能/更好/更简单的网络设置说明
  • 更智能/更好/更简单的方法来调整容器操作系统文件以在容器的上下文中运行。
  • tty10 在 /etc/rsyslog.early.conf、/etc/rsyslog.conf、/etc/init.d/boot.klog
    • 可以通过将“lxc.tty = 12”添加到容器配置文件,创建 /dev/tty1 - tty12 的 12 个 mknod 命令并删除 tty10 到 null 的符号链接来处理。然后您可以使用 lxc-console -n vps0 -t 10 查看 tty10 输出
  • openSUSE 11.2 附带 lxc 0.6.3,没有用于在主机重新启动时启动/停止容器的 init 脚本。下面链接的 lxc-0.7.2 包具有这样的 init 脚本。
  • 改进 init 脚本以处理更多类型和配置的容器
  • libvirt。本文档描述了使用标准 lxc 工具包(称为“lxc”)来操作容器。还有另一种使用 libvirt 和 virsh 命令以及 libvirt xml 文件而不是 lxc-start/lxc-stop 和 lxc 配置文件来执行相同操作的方法。根据 libvirt 网站上的所有可用文档和 示例,使用 libvirt 的 lxc 已经损坏,截至 libvirt 0.81

内部链接

外部链接