LXC
Linux 容器 (LXC) 提供了类似于 BSD Jails、Linux VServers 和 Solaris Zones 的容器。它给人以虚拟化的印象,但与“主机”共享内核和资源。您可以直接使用 lxc 或通过 LXD 使用。
安装
安装所需的软件包
apk add lxc bridge lxcfs lxc-download xz
如果您想创建除 Alpine 之外的其他容器,则需要 lxc-templates
apk add lxc-templates
从 2.x 版本升级
从 Alpine 3.9 开始,我们发布了 LXC 3.1 版本。LXC 3.x 进行了重大更改,可能会破坏您当前的设置。LXC 3.x 将不会附带旧版容器模板。检查您当前的容器配置,看看是否有任何包含指向不存在的文件(由旧版模板提供)。例如,如果您使用 Alpine 模板创建的 Alpine 容器,您需要安装
apk add lxc-templates-legacy-alpine
另请确保将您的 LXC 配置文件转换为新的 2.x 格式(这是现在必需的)。
lxc-update-config -c /var/lib/lxc/container-name/config
确保您已从 cmdline 中删除 cgroup_enable,因为这将导致 cgroups 挂载失败并导致 LXC 服务失败。
在主机上准备网络
安装 lxc-bridge 软件包以创建 lxcbr0
桥接,并使用 iptables 配置转发路由
apk add lxc-bridge iptables
在启动时启用 dnsmasq OpenRC 服务并启动它
rc-update add dnsmasq.lxcbr0 boot service dnsmasq.lxcbr0 start
如果您不想转发路由,请将 DISABLE_IPTABLES="yes"
添加到 /etc/conf.d/dnsmasq.lxcbr0 文件中
为容器分配静态 IP
使用 dnsmasq 方法,您可以保持容器接口按原样请求 DHCP。您只需要设置 DHCP 服务器应答。
通过编辑文件 /etc/lxc/dnsmasq.conf 并添加主机名(容器名称)和所需的 IP
dhcp-host=guest1,10.0.3.4 dhcp-host=guest2,10.0.3.5
重启服务
service dnsmasq.lxcbr0 restart
创建 guest 容器
从列表中选择
lxc-create -n guest1 -f /etc/lxc/default.conf -t download
然后从列表中选择即可。lxc-download 和 xz 在完成后可以卸载。
Alpine 模板
lxc-create -n guest1 -f /etc/lxc/default.conf -t alpine
这将创建一个 /var/lib/lxc/guest1 目录,其中包含一个 config 文件和一个 rootfs 目录。
注意:默认情况下,alpine 模板未启用网络服务,您需要使用 lxc-console 添加它
如果在 x64 兼容硬件上运行,则可以创建 32 位 guest 容器
lxc-create -n guest1 -f /etc/lxc/default.conf -t alpine -- --arch x86
Debian 模板
为了创建 debian 模板容器,您需要安装一些软件包
apk add debootstrap rsync
您需要关闭一些 grsecurity chroot 选项,否则 debootstrap 将会失败
echo 0 > /proc/sys/kernel/grsecurity/chroot_caps echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_chroot echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mount echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mknod echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_chmod
记住要重新打开它们,或者直接重启。
现在您可以运行
SUITE=wheezy lxc-create -n guest1 -f /etc/lxc/default.conf -t debian
设置静态 IP
由于 systemd 的更改,自 Debian Bullseye 11.3 起,您无法使用容器的 lxc 配置文件分配静态 IP 地址 因为 systemd 更改。为了使其与以下配置一起工作
# grep net /var/lib/lxc/bullseye/config lxc.net.0.type = veth lxc.net.0.flags = up lxc.net.0.link = virbr1 lxc.net.0.ipv4.address = 192.168.1.111/24 lxc.net.0.ipv4.gateway = 192.168.1.1
您必须附加到容器并运行
lxc-attach -n bullseye systemctl stop systemd-networkd systemctl disable systemd-networkd reboot
重启后,IP 地址应该设置正确。可以使用 lxc-ls 命令确认这一点
# lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED bullseye RUNNING 1 - 192.168.1.111 - false
Ubuntu 模板
![]() Alpine 很久以前就不再包含 grsec (讨论) |
为了创建 ubuntu 模板容器,您需要关闭一些 grsecurity chroot 选项
echo 0 > /proc/sys/kernel/grsecurity/chroot_caps echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_chroot echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mount echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mknod echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_chmod
记住要重新打开它们,或者直接重启。
现在您可以运行(将 %MIRROR% 替换为实际主机名,例如:http://us.archive.ubuntu.com/ubuntu/)
lxc-create -n guest2 -f /etc/lxc/default.conf -t ubuntu -- -r xenial -a amd64 -u user --password secretpassword --mirror $MIRROR

非特权 LXC 镜像 (Alpine / Debian / Ubuntu / Centos 等)
要启用非特权容器,必须创建一个 uidgid 映射
echo root:1000000:65536 | tee -a /etc/subuid echo root:1000000:65536 | tee -a /etc/subgid
这将为 root 用户创建一个 uid 和 gid 映射,起始于 1000000,大小为 65536。
要配置容器以使用此映射,请将以下行添加到配置中
lxc.idmap = u 0 1000000 65536 lxc.idmap = g 0 1000000 65536
这可以在全局或容器特定的配置中。
要创建非特权 lxc 容器,您需要使用 download 模板。必须安装 download 模板
apk add gnupg xz lxc-download lxc-create -n container-name -t download
选择 Distribution | Release | Architecture。
为了能够登录到 Debian 容器,您目前需要
rm /lib/systemd/system/container-getty\@.service
您也可以 从容器中删除 Systemd。
启动/停止 guest 容器
首先,您应该启用 cgroup 脚本
rc-update add cgroups
如果您不想重启,可以通过运行以下命令来启动服务
rc-service cgroups start
为您的 guest 容器创建指向 /etc/init.d/lxc 脚本的符号链接。
ln -s lxc /etc/init.d/lxc.guest1
您可以使用以下命令启动您的 guest 容器
rc-service lxc.guest1 start
使用以下命令停止它
rc-service lxc.guest1 stop
使用以下命令使其在启动时自动启动
rc-update add lxc.guest1
您可以添加到容器配置中:lxc.start.auto = 1
rc-update add lxc
仅使用 lxc 服务自动启动容器。
连接到 guest 容器
默认情况下,sshd 未安装。您必须附加到容器或连接到虚拟控制台。这是通过以下方式完成的
lxc-attach -n guest1
键入 exit 再次从容器分离(请检查上面的 grsec 注释)
连接到虚拟控制台
lxc-console -n guest1
要断开连接,请按 Ctrl+a q
删除 guest 容器
确保 guest 容器已停止,然后运行
lxc-destroy -n guest1
这将擦除所有内容,无需任何询问。它等同于
rm -r /var/lib/lxc/guest1
高级
创建 LXC 容器,无需修改网络接口
桥接的问题在于,您桥接的接口会被您的新桥接接口替换。假设您有一个想要桥接的接口 eth0。您的 eth0 接口将被您创建的 br0 接口替换。这也意味着您使用的接口需要置于混杂模式,以捕获可能定向到桥另一侧的所有流量,这可能不是您想要的。
解决方案是创建一个虚拟网络接口,桥接该接口,并设置 NAT,以便从您的桥接接口发出的流量通过您选择的接口推送。
让我们创建该虚拟接口(感谢 ncopa 说服我放弃 macvlan 并指出虚拟接口内核模块)
modprobe dummy
这将在您的主机上创建一个名为 dummy0 的虚拟接口。要在每次启动时创建此接口,请将“dummy”附加到 /etc/modules
现在我们将创建一个名为 br0 的桥接
brctl addbr br0 brctl setfd br0 0
然后使该虚拟接口成为桥接的一端
brctl addif br0 dummy0
接下来,让我们给该桥接接口一个存在的理由
ifconfig br0 192.168.1.1 netmask 255.255.255.0 up
为您的容器创建一个文件。假设为 /etc/lxc/bridgenat.conf,具有以下设置。
lxc.net.0.type = veth lxc.net.0.flags = up lxc.net.0.link = br0 lxc.net.0.name = eth1 lxc.net.0.ipv4.address = 192.168.1.2/24 192.168.1.255 lxc.net.0.ipv4.gateway = 192.168.1.1 lxc.net.0.veth.pair = veth-if-0
并使用该文件构建您的容器
lxc-create -n alpine -f /etc/lxc/bridgenat.conf -t alpine
您现在应该能够从您的主机 ping 您的容器,以及从您的容器 ping 您的主机。
您的容器需要知道将不在其子网内的流量推送到哪里。为此,我们告诉容器通过桥接接口 br0 路由。从容器内部运行
route add default gw 192.168.1.1
下一步是将来自您的私有子网的流量通过 br0 推送到您的面向互联网的接口,或您选择的任何接口
我们在这里修改您的 IP 表,因此请确保这些设置与您可能已设置的任何内容不冲突。
假设 eth0 是您的面向互联网的网络接口,而 br0 是您之前创建的桥接的名称。我们将这样做
echo 1 > /proc/sys/net/ipv4/ip_forward iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE iptables --append FORWARD --in-interface br0 -j ACCEPT
现在您应该能够通过您的桥接接口从您的容器路由到您的主机的面向互联网的接口,就像在家里一样!
您还可以在您的主机上运行 dhcp 服务器,并将其设置为从您的私有子网向任何请求它的容器提供 IP 地址,然后为多个 alpine LXC 容器使用一个模板,非常适合 alpine 开发 :)
使用静态 IP
如果您使用静态 IP,则需要在 guest 容器的 /etc/network/interfaces 上正确配置它。为了与上面的示例保持一致,请修改 /var/lib/lxc/guest1/rootfs/etc/network/interfaces
从
#auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp
到
#auto lo iface lo inet loopback auto eth0 iface eth0 inet static address <lxc-container-ip> # IP which the lxc container should use gateway <gateway-ip> # IP of gateway to use, mostly same as on lxc-host netmask <netmask>
内存和交换空间
vim /boot/extlinux.conf
APPEND initrd=initramfs-3.10.13-1-grsec root=UUID=7cd8789f-5659-40f8-9548-ae8f89c918ab modules=sd-mod,usb-storage,ext4 quiet cgroup_enable=memory swapaccount=1
checkconfig
lxc-checkconfig
在 /proc/config.gz 中未找到内核配置;正在搜索... 在 /boot/config-3.10.13-1-grsec 中找到内核配置 --- 命名空间 --- 命名空间:已启用 Utsname 命名空间:已启用 Ipc 命名空间:已启用 Pid 命名空间:已启用 用户命名空间:缺失 网络命名空间:已启用 多个 /dev/pts 实例:已启用 --- 控制组 --- Cgroup:已启用 Cgroup clone_children 标志:已启用 Cgroup 设备:已启用 Cgroup sched:已启用 Cgroup cpu account:已启用 Cgroup memory controller:缺失 Cgroup cpuset:已启用 --- 杂项 --- Veth pair 设备:已启用 Macvlan:已启用 Vlan:已启用 文件 capabilities:已启用 注意:在启动新内核之前,您可以检查其配置用法:CONFIG=/path/to/config /usr/bin/lxc-checkconfig
VirtualBox
为了使网络在容器上工作,您需要在 VirtualBox 设置中将网络适配器的“混杂模式”设置为“允许全部”。
postgreSQL
在容器内部运行
chmod go+w /dev/null
修复
rc-service postgresql start
openVPN
参见 Setting_up_a_OpenVPN_server#openVPN_and_LXC
LXC 1.0 附加信息
关于 LXC 1.0 新功能的一些信息
https://www.stgraber.org/2013/12/20/lxc-1-0-blog-post-series/