LXC 简介

2015-03-02 container linux

LXC (Linux Containters) 是一种基于内核容器的用户空间接口,提供了一系列创建、配置、管理的接口。

其提供了比 chroot 更强的资源隔离,但是与硬件提供的完全虚拟化又不同,其目标为创建一个不需要独立内核,但近可能接近标准 Linux 安装的环境。

在此简单介绍其使用方法,以及常用的命令。

linux container logo

简介

首先大致介绍一下 LXC 是如何做到的。简单来说就是,一台机器上跑了一个 Linux 内核,然后通过 LXC 跑了 N 个不同的 Linux 发行版本的用户程序,包括 init 。

所谓的 Linux 发行版本,如 RedHat、Ubuntu、CentOS、Debian、Fedora 等等,其实际上都是基于 Linux 内核,有可能打了不同的 patch,但真正不同的只是用户空间程序,如 init 用的是 systemV、upstart 还是饱受争议的 systemd,图形界面用的是 Gnome、KDE、LXDE、Xfce 甚至是 FCWM。

这也要多亏了所谓的 Linux 哲学:提供机制,而非策略(说实话没有找到对应的英语原话)。

安装 lxc

在 CentOS 中,如果通过 YUM 安装,则依赖 EPEL 库,可以通过如下方法安装。

# yum install libcgroup lxc lxc-libs lxc-templates --enablerepo=epel

/usr/share/lxc/templates 目录下保存了常用的模板,可以用非 root 创建容器,当然这会更安全,不过会不方便,如不能挂载文件系统、不能创建设备节点等,可以参考 Creating unprivileged containers as a user,后面再研究,暂时还是用 root 用户。

源码编译

对于源码编译的 lxc,其目录中的内容类似,只是默认会添加 /usr/local 的 prefix,可以如下使用 /usr 的 prefix,此时下面讨论的内容会添加 /usr 前缀。

$ ./configure --prefix=/usr && make
# make install

检查

编译安装完成之后,可以通过如下命令检查环境。

$ lxc-checkconfig

配置文件

通过 yum 安装的 lxc ,常见的配置文件以及目录如下。

  • /etc/lxc/default.conf
    LXC 的默认配置文件,如果在创建容器时不指定配置文件,将默认使用这个配置文件,主要包括了对网络以及命名空间的设置;其它一些配置文件保存在 /usr/share/lxc/config 目录下。
  • /var/lib/lxc/
    保存了容器的相关配置,包括已经创建容器的根文件系统 (rootfs)、配置文件 (config)。
  • /usr/share/lxc/templates/
    保存了当前 LXC 支持的各种发行版的 linux 的模板配置文件,如 lxc-ubuntu、lxc-fedora、lxc-busybox、lxc-sshd 等。
  • /var/log/lxc
    日志默认保存在该目录下,容器名.log 。

注意,在创建一个类似 ubuntu、fedora 相关的容器时,通常会在 /var/cache/lxc/ 目录下保存一份,那么第二次创建时,就不需要再次下载。

使用 LXC

在此简单介绍如何创建并使用 LXC,以 CentOS-7 为例,并简单介绍创建 CentOS 的过程。注意,如果安装 ubuntu 镜像,需要安装 debootstrap (用于安装 rootfs) 。

通过 LXC 可以启动一个 Linux 发布版本的镜像,也可以只启动一个进程,下面仍以 root 创建一个 CentOS 7 镜像为例。

1. 创建镜像

可以根据现有的模板创建,可以参考 /usr/share/lxc/templates/lxc-centos ,该文件实际就是一个 bash 脚本,用来创建 rootfs 。

----- 根据模板创建镜像,--后为传入脚本的参数
# lxc-create -t centos -n centos -- --release 7

----- 查看已经安装的rootfsconfig等文件config文件将在lxc-start中使用
# ls /var/lib/lxc/centos/
config  rootfs/  tmp_root_pass

----- 或者通过该命令查看当前已经安装的镜像
# lxc-ls -f
centos

----- 查看设置的密码,创建后会打印该提示
# cat /var/lib/lxc/centos/tmp_root_pass

----- 直接通过chroot修改密码
# chroot /var/lib/lxc/centos/rootfs passwd

/var/cache/lxc/centos 目录下,会保存临时文件,这样创建时只会在第一次下载所需的软件包,后面如果版本比较旧可能还会 update 。

2. 启动容器

启动时,如果不指定 -d 后台运行,则会将当前的 bash 作为 console 输出,此时会输出容器的启动信息,然后直接进入登陆界面。

----- 后台启动容器,并设置日志级别为DEBUG,日志可以查看/var/log/lxc/centos.log
# lxc-start -n centos -l DEBUG -d

----- 查看容器启动的init对应的PID
# ps faux | grep -A 1 "lxc-start -n centos -d"

是不是发现启动很快!!!

实际上很大一部分时间是消耗在网络设置上,如果取消网络你会发现启动速度更快。

3. 查看状态

容器启动之后实际上是一直有一个进程等待接收命令等操作的,对应的容器实际上是一个子进程。

----- 查看容器的运行状态,包括了其PID、运行状态、IP等信息
# lxc-info -n centos
Name:           centos
State:          RUNNING
PID:            31649                # init线程的PID
IP:             192.168.122.118      # 容器中的IP
CPU use:        0.15 seconds
BlkIO use:      0 bytes
Memory use:     1.18 MiB
KMem use:       0 bytes
Link:           vethXTBOA0           # 容器外的对端网络设备
 TX bytes:      1.76 KiB
 RX bytes:      12.95 KiB
 Total bytes:   14.71 KiB

----- 以行显示当前运行状态
# lxc-ls -f
NAME   STATE   AUTOSTART GROUPS IPV4 IPV6
centos STOPPED 0         -      -    -

----- 查看启动的父进程PID
# ps aux | grep 'lxc-start -n centos' | grep -v grep
root  31639  0.0  0.0  30560  1640 pts/9  S+ 12:27 0:00 lxc-start -n centos

----- OK,查看下父进程派生的子进程
# pstree -p 31639
lxc-start(31639)──systemd(31649)─┬─dbus-daemon(31707)
                                 ├─dhclient(31901)
                                 ├─login(31714)───bash(31958)
                                 ├─rsyslogd(31711)─┬─{rsyslogd}(31718)
                                 │                 └─{rsyslogd}(31719)
                                 ├─sshd(31852)
                                 ├─systemd-journal(31665)
                                 └─systemd-logind(31712)

----- 直接查看容器的ip,实际就是在容器中执行命令
# lxc-attach -n centos -- /sbin/ip address list

4. 连接到容器

如果在启动的时候没有使用 -d 选项,则默认使用当前的 bash 作为 console ,可以直接在启动后登陆。

----- 通过lxc的命令链接上去
# lxc-attach -n centos

----- 目前链接时还有点问题,直接卡着不动
# lxc-console -n centos

----- 使用util-linux包提供的命令进入设置的namepace空间,需要PID
# nsenter --target PID --mount --uts --ipc --net --pid --root --wd

注意,attach 只有 3.8 之后的内核才会支持,对于低版本需要通过其它的方法解决。

5. 关闭容器

可以在容器中内执行 poweroffshutdown -h now 来关闭容器,可以通过如下命令强行关闭,不过此时会花费比较长的时间,实际上就是正常的关闭流程。

# lxc-stop -n centos

6. 销毁容器

如果不需要了,可以通过如下方式删除,包括了 rootfs 等配置,所以 “慎用” 。

# lxc-destroy -n centos

7. 其它常见命令

简单介绍经常会用到的命令。

----- 创建,默认使用/etc/lxc/default.conf,可以通过-f指定配置文件
# lxc-create -n NAME -f FILE

----- 用户获取一个容器的状态,容器的状态有STARTING RUNNING STOPPING STOPPED ABORTING
# lxc-info -n NAME

----- 监控一个容器状态的变换,当一个容器的状态变化时,此命令会在屏幕上打印出容器的状态
# lxc-monitor -n NAME

----- 列出当前系统所有的容器
# lxc-ls

----- 列出特定容器中运行的进程
# lxc-ps -n NAME

----- 用于销毁容器
# lxc-destroy -n NAME

另外,需要注意的是:通过 lxc-create 创建后的容器,在停止运行后,不会立即被销毁,要采用 lxc-destroy 命令才能销毁;容器命令空间是全局的,系统中不允许存在重名的容器,否则会失败。

安装 Ubuntu 镜像

只是简单介绍一下如何创建 Ubuntu 的镜像,与镜像相关的大部分的操作与创建 CentOS-7 相同,只是在创建 rootfs 时有些区别。

在此,主要介绍其创建方法,安装 rootfs 时,可能会由于镜像无法访问导致创建失败,可以将 Ubuntu 访问的网站在 /usr/share/lxc/templates/lxc-ubuntu 开始设置 MIRROR 变量。

MIRROR=${MIRROR:-http://mirrors.163.com/ubuntu/}

然后通过如下命令创建 rootfs 。

# lxc-create -t ubuntu -n ubuntu -- -r precise

实际上,上述的脚本是通过 debootstrap 创建一个 rootfs,也可以通过如下命令自己创建。

# debootstrap --arch amd64 precise ubuntu-precise http://mirrors.163.com/ubuntu/

资源设置

LXC 是通过 cgroup 进行资源管理的,也就是说这部分的设置,都可以通过 lxc-cgroup 命令进行动态调整。在使用前,需要通过如下方式挂载。

----- 挂载cgroup
# mount none -t cgroup /cgroup

----- 让系统每次启动自动挂载cgroup
# echo "none /cgroup cgroup defaults 0 0" >> /etc/fstab

LXC 在创建容器的时候就在 /group 下创建一个子 group 以实现对容器的资源控制,可以根据需要设定相应子系统的参数来达到目的。

CPU

对于 CPU 资源配置,主要通过两个变量 cpu.shares、cpuset.cpus 进行设置。

cpu.shares 是一个按照比例计算的 cpu 使用份额,例如,只存在两个 lxc 的 cpu.shares 都是 1024,那么这两个 lxc 使用 cpu 的理论比例就是 50%:50%。

cpuset.cpus 是分配给这个 lxc 使用的具体 cpu,编号从 0 开始;可以通过如下方式进行分配:

# lxc-cgroup -n name cpu.shares 1024
# lxc-cgroup -n name cpuset.cpus 0-1

另外一个相关的参数是 cpuset.mems,与 cpus 类似,主要用于 NUMA 类型的机器。

Memory

内存的设置比较简单,主要是关于物理内存以及 swap 。

memory.limit_in_bytes 用户内存的最大量,包括了文件缓存,默认单位是字节。如果 swap 没有关闭的话,即使超过了该限制,仍可能转储到 swap 空间,可以通过 swapoff 关闭。

memory.memsw.limit_in_bytes 设定最大内存与 swap 用量之和,同样默认单位是字节。设置该项前,同样要设置上述的值,而且不能大于该值。

blkio

也就是用来设置块设备的 IO 访问。

配置文件

LXC 配置项都是以 key=value 的形式设置,其中以 # 开始的一行为注释;当然,配置也可以在 lxc-execute 或者 lxc-start 的命令行以 -s key=value 设定;如下列举出常见的一些配置。

日志设置

容器的启动日志默认只收集 ERROR 级别的信息,默认保存在 /var/log/lxc 目录下,以容器名开头,以 .log 结尾的文件中,日志级别和日志路径都是可以在配置文件中修改。

lxc.loglevel=               // 级别,value是0到8的整数,0-trace, 1-debug, 2-info, 3-notice, 4-warn,
                            //         5-error, 6-critical, 7-alert, 8-fatal.
lxc.logfile=                // 路径

cgroup 设置

cgroup 部分通常以 lxc.cgroup.[subsystem name].key=value 的形式进行设置。

安全

如果以 root 启动,可以通过如下参数取消其中的部分功能,以 CAP_SYS_MODULE 为例,实际设置应为该 sys_module,其它详细的参数可以参考 man 7 capabilities

lxc.cap.drop = sys_module mac_admin

常用命令

简单列举一下经常使用的命令,想到那写到那,备忘。

查看当前容器

可以通过 lxc-ls 命令查看,容器的状态,默认查看的是已经创建的容器(可能没有启动)。

----- 查看当前已经创建的容器
# lxc-ls

查看 LXC 相关的配置

通过如下命令可以查看 LXC 的系统配置信息,主要有两类参数。

----- 查看当前LXC的系统配置
# lxc-config -l
lxc.default_config
lxc.lxcpath
... ...

----- 查看其中的配置项
# lxc-config lxc.lxcpath

参考

官方网站 linuxcontainers.org