前言

LXC 是 Linux Container 的缩写,类似虚拟化技术中的 OpenVZ,是一种半虚拟化技术,可以提供一个和宿主机相对隔绝的沙盒环境。在容器中安装的各种软件不会影响到宿主机,同时也可以通过配置容器的资源限制,来保证容器中运行的软件不会占用过多资源。

与 Docker 不同,LXC 和 OpenVZ 会保留用户操作的状态,而 Docker 则是提供一个无状态的预部署的容器,只有映射出来的文件才会得到保存。

许多优秀的管理面板提供了管理 LXC/OpenVZ 容器的功能,比如 Proxmox 等,但是由于管理面板的内存占用较高(纯净的 Debian9.4 镜像安装 Proxmox 后占用约 660MB 的内存),不适合小内存的机器,因此我选择 lxc 提供的使用命令行工具来对容器进行管理。

本文将主要包括如下内容:

  • 创建 LXC 容器
  • 限制 LXC 容器可用的资源(CPU,内存,磁盘等)
  • 配置 LXC 容器的网络,且为 LXC 容器提供端口映射。

本文介绍的内容主要适用于如下两种情况:

  • 内存较小的机器上无面板使用 lxc 虚拟化以节省内存消耗
  • 面板出现 bug 时使用命令行工具排查错误

注:本文根据 Debian9.4 环境撰写,其余发行版那请自行调整相关命令。

LXC 的安装

对于比较新的 Debian 系统来说,安装 lxc 就是一句话

apt install lxc

宿主机网络配置

首先对宿主机进行网络配置,配置的目标是创建一个网桥及相关的 iptables 命令,实现 NAT 功能。

这个目标比较简单,只需要在网络配置文件(/etc/network/interfaces)中添加如下内容即可

auto vmbr0
iface vmbr0 inet static
	address  192.168.45.1
	netmask  255.255.255.0
	bridge_ports none
	bridge_stp off
	bridge_fd 0
	post-up echo 1 > /proc/sys/net/ipv4/ip_forward
	post-up iptables -t nat -A POSTROUTING -s '192.168.45.0/24' -o eth0 -j MASQUERADE
	post-down iptables -t nat -D POSTROUTING -s '192.168.45.0/24' -o eth0 -j MASQUERAD

创建容器

创建容器用的是 lxc-create 命令,最常见的创建方式包含两个参数:

# 使用 <template> 模板创建名为 <name> 的容器
lxc-create -t <template> -n <name>

如果你有提前编写完成的配置文件,可以通过 -f 参数指定

# 使用 <template> 模板及 <config_file> 配置文件,创建名为 <name> 的容器
lxc-create -t <template> -f <config_file> -n <name>

不同的模板拥有不同的参数,可以通过如下命令查询:

# 查看 <template> 模板的更多参数
lxc-create -t <template> -h

lxc-create 创建的容器需要通过 lxc-start -n <name> 启动。

自动启动需要在容器的配置文件里面加入指定参数:

lxc.start.auto = 1

配置容器

接下来要做的是修改容器的配置文件,LXC 容器的配置文件在 /var/lib/lxc/<容器名>/config

为容器配置NAT网络

首先我们修改配置文件让容器通过我们刚才创建的 NAT 网络连接互联网。

如果准备让所有的容器都使用该网络配置,可以修改默认的配置文件 /etc/lxc/default.conf,如果只打算修改个别容器的配置,可以在 /var/lib/lxc/<容器名>/config 找到个别容器的配置文件。

## Network
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = vmbr0

## xx代表随机生成,每次重启都会有所变化
lxc.network.hwaddr = 00:16:3e:xx:xx:xx

lxc.network.ipv4.gateway = 192.168.45.1

# 如果个别容器,可以指定 IP 地址
# lxc.network.ipv4 = 192.168.45.101

另外需要注意的是,部分容器模板是不包含任何 DNS 设定的,需要手动在 /etc/resolv.conf 中指定 DNS 服务器:

nameserver 8.8.8.8
nameserver 8.8.4.4

限制容器的 CPU 和内存占用

创建容器之后,默认容器可以使用全部的资源,需要修改容器的配置文件才能限制容器的资源使用。对配置文件的修改本质上是通过 cgroups 来限制容器的使用,具体的参数可以参考 cgroups 的参数。

Arch Wiki 提供了一个 cgroups 的详细介绍

一个典型的资源限制配置文件包含如下内容:

# 可使用内存量
lxc.cgroup.memory.limit_in_bytes = 512M

# 突发内存量 = 可用内存 + swap
# 该选项需对 grub 参数进行设置
# 可以参考 https://github.com/yudai/cf_nise_installer/issues/124
# 执行如下命令即可
# sudo echo "GRUB_CMDLINE_LINUX=\"cgroup_enable=memory swapaccount=1\"" >> /etc/default/grub 
# sudo /usr/sbin/update-grub
lxc.cgroup.memory.memsw.limit_in_bytes = 1G

# CPU 核心数量
# 可以通过具体的数字精确指定占用的 CPU 核心编号
# 示例代表可以使用 1 2 3 4 号 CPU 核心。
lxc.cgroup.cpuset.cpus = 1,2-4

# CPU 资源占用比例
lxc.cgroup.cpu.shares = 1024

除了修改配置文件,也可以通过命令行直接指定 cgroup 参数,如:

# 仅允许名为 lxc_name 容器使用 CPU 的核心 1
lxc-cgroup -n lxc_name cpuset.cpus "1"

限制容器的磁盘大小

具体可以参考 man lxc-create 中 -B 参数的部分,在这里简单的提供一个命令对虚拟机进行限制。

注: loop 并不是最佳的参数,更好的方法是使用 lvm,但是这对磁盘分区有要求。

# 限制磁盘大小 5GB
lxc-create -n <name> -t <template> -B loop --fssize 5G

通过 iptables 进行端口转发

具体可以参考 这篇教程,只需要将转发的目标 IP 设置为容器的子网 IP 即可。

这里提供一个脚本来辅助设置端口转发。

wget https://storage.doubi.win/01_Script/01_Linux/nat.sh

使用脚本时需要根据上文中提到的内容对脚本进行微调,

bash nat.sh 101

未曾修改脚本的情况下,这个命令代表将 192.168.45.101 的 22 端口转发到主机的 10122 端口,并把 192.168.45.101 的 10100~10120 端口转发到主机的 10100~10120 端口。

配置完成后可以通过 ssh <宿主机IP> -p 10122 来访问容器的22端口。

注:容器需处于启动状态,且安装 openssh-server 并监听 22 端口。

LXC 常用命令

# 创建容器
lxc-create -t <template> -n <name>

# 启动容器
lxc-start -n <name>

# 停止容器
lxc-stop -n <name>

# 进入容器
lxc-attach -n <name>

# 查看所有容器,可通过参数指定只查看特定状态的容器
lxc-ls

# 查看容器信息
lxc-info -n <name>

# 查看容器中的进程
lxc-ps -n <name>

一个用于创建 LXC 容器的 Python 脚本

TODO