lxc note

Remise

Introduction

  • 最好将容器化定义为:通过操作系统中的特性启用的进程隔离机制

容器是与系统其他部分隔离的一个或多个进程的集合。

Containers != VMs

Virtual Machine Linux LXC Container
操作系统 在VM中运行隔离的客户OS 在主机OS上运行(共享内核)
网络 通过虚拟网络设备 通过虚拟网络适配器隔离的视图
隔离性 OS之间完全隔离 基于命名空间和cgroup的隔离
大小 通常是GB级别 通常是MB级别
启动时间 以秒、分钟数量级,取决于存储介质 以秒数量级

chroot

Introduction

  • 默认情况下,操作系统的根目录为/,进程将其视为所有文件绝对路径的根目录。
  • 这个“视图”可以通过调用chroot()系统调用来更改,这样我们就可以创建一个独立的独立环境来运行。
  • chroot更改当前运行进程及其子进程的表面上的根目录。

Defect

  • 但是,chroot本身并不能提供强隔离
  • 似乎阻止对父目录的访问就足够了,但是chroot只是修改进程(通过pivot_root)及其子进程的路径名查找,将新的chroot-ed目录路径放在任何绝对路径(以/开头的路径)前面。
  • 在其他原因中,如果进程能够访问chroot监狱之外的句柄,那么也允许访问chroot-ed目录的父目录——因此这本身不是强隔离。

Capabilities

Introduction

  • 传统的UNIX自由访问控制分为两个部分
    • root/超级用户/特权;
    • 用户/非特权。
  • 假设一个系统用户需要生成一个需要一些root权限的服务器进程。同时,假设服务器代码具有远程代码执行漏洞。如果脆弱的服务器进程被破坏,整个系统就会被破坏(因为进程的UID是0)。有没有一种方法只给进程它需要的权限(最小权限)?
  • 为了分割通常完全提供给root用户的特权,Linux Capabilities从2.2版开始被引入到Linux内核中。每个Capability代表一个不同的特权单位,前缀为CAP_。一些功能包括:
    • CAP_CHOWN:更改文件的用户和组所有权的能力
    • CAP_NET_ADMIN:在系统上执行与网络相关的管理的能力
    • CAP_NET_RAW:创建RAW和PACKET套接字以及任意地址绑定的能力
    • CAP_SYS_ADMIN:能够做很多事情,以至于很多人把它当作新的根。未来肯定需要进一步的特权分片。

总共29种Capability

  • getcap和setcap命令用于获取/设置文件的Capabilities。

Example

  • 让我们看看ping实用程序,它需要创建一个RAW套接字来发送ICMP数据包:
1
2
student@6858-v20:~$ ls -al /bin/ping
-rwsr-xr-x 1 root root 64424 Jun 28 2019 /bin/ping
  • 它属于root:root,但任何用户都可读和执行。如果我们尝试ping google.com,我们可以验证UID是当前用户的(因为没有setuid位设置):
1
2
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
student 2090 0.0 0.1 21044 2476 pts/2 S+ 23:17 0:00 /bin/ping google.com
  • 这里的非特权用户能够ping,因为在/bin/ping二进制文件上设置了一个功能:
1
2
student@6858-v20:~$ getcap /bin/ping
/bin/ping = cap_net_raw+ep
  • 有3个capability标志可以设置:

    • Effective:该capability是否激活
    • Inheritable:该capability是否被子进程继承
    • allowed:该capability是否被允许,与父进程capability集无关
  • 如果我们清空了ping的capability
1
2
3
4
5
6
7
student@6858-v20:~$ cp /bin/ping .
student@6858-v20:~$ getcap ./ping
student@6858-v20:~$ ./ping google.com
ping: socket: Operation not permitted
student@6858-v20:~$ sudo setcap cap_net_raw=ep ./ping
student@6858-v20:~$ ./ping google.com
PING google.com (172.217.163.46) 56(84) bytes of data.

通过复制ping二进制文件到一个新的目的地,任何扩展的属性(setuid,capabilities等)都会被清除。

  • 如果没有cap_net_raw这个capability,生成的ping进程就无法打开RAW套接字。一旦我们恢复了这种capability,ping功能就会恢复正常。
  • Capabilities似乎是一个好主意,但CAP_SYS_ADMIN仍然有太多特权,这只是lxc用于加强隔离的另一种机制。

cgroup

Introduction

  • Control groups (cgroups)用于根据用户定义的进程组限制系统资源的使用
  • 假设您正在运行一个非常密集的数据分析例程,它使用了大量的算力和内存,以致于您的系统没有很好的响应。cgroups是一个内核特性,它允许您定义一组进程,这些进程运行分析作业并限制、解释和隔离分配的资源,这样您就可以在资源有限的情况下执行多任务分析作业。特别地,cgroup特性包括:
    • Limits:可以在处理器使用、内存使用、设备使用等方面指定最大限制。
    • Accounting:监控资源使用情况。
    • Prioritization:资源使用可以优先于其他cgroup。
    • Control:可以控制进程的状态(如停止、重启、挂起)。
  • 一个cgroup是一个或多个进程的集合,它们被绑定到为cgroup定义的同一组限制上。cgroup还可以以分层的方式继承另一个cgroup的属性。

  • cgroups通常在大多数现代版本的Linux发行版中可用,大多数定义了大约10个子系统(也称为控制器)。

    • blkio:这个子系统设置对块设备,如物理驱动器(磁盘、固态或USB)的输入/输出访问的限制。
    • cpu:这个子系统使用调度器提供cgroup任务对cpu的访问。
    • cpuacct:该子系统自动生成cgroup中任务使用CPU资源的报告。
    • cpuset:这个子系统为cgroup中的任务分配单独的cpu(在多核系统上)和内存节点。
    • devices:这个子系统允许或拒绝cgroup中的任务访问设备。
    • freezer:这个子系统挂起或恢复cgroup中的任务。
    • memory:这个子系统对cgroup中的任务使用内存进行限制,并自动生成关于这些任务使用内存资源的报告。
    • net_cls:这个子系统用一个类标识符(classid)标记网络数据包,这个类标识符允许Linux流量控制器(tc)识别来自特定cgroup任务的数据包。
    • net_prio:这个子系统提供了一种动态设置每个网络接口的网络流量优先级的方法。
    • ns:命名空间子系统。
    • perf_event:这个子系统标识任务的cgroup成员,可以用于性能分析。
  • 管理它们需要cgroup-tools和libcgroup1包,它们可以通过以下方式安装到Ubuntu中:

1
sudo apt install cgroup-tools libcgroup1

Example

  • 假设我们有一个称为memes的内存密集型进程,我们希望在工作站上运行它。我们可以使用cgroups来限制内存使用,方法是在内存子系统中创建一个名为memegroup的cgroup(使用cgcreate),设置它的限制(使用cgset),并在该cgroup下执行进程(使用cgexec):
1
2
3
4
5
6
7
8
student@6858-v20:~$ sudo cgcreate -g memory:memegroup
student@6858-v20:~$ sudo cgset -r memory.limit_in_bytes=1500K memegroup
student@6858-v20:~$ cgget -r memory.limit_in_bytes memegroup
primes:
memory.limit_in_bytes: 1536000
student@6858-v20:~$ cat /sys/fs/cgroup/memory/memegroup/memory.limit_in_bytes
1536000
student@6858-v20:~$ sudo cgexec -g memory:memegroup ./memes
  • cgcreate命令帮助在sysfs下创建目录(sysfs几乎总是挂载在/sys上,可以直接从命令行进行操作),并且cgset适当地设置值。注意,系统总是将其更正为最接近的4096B对齐(从1500 KB到1536 KB),这是内核页面大小。最后,我们在内存子系统下的memegroup中执行meme。

    • 过了一段时间,你会在终端上看到消息,说进程已经被终止了。
1
2
3
4
student@6858-v20:~/cgroup$ cat /sys/fs/cgroup/memory/memegroup/memory.oom_control
oom_kill_disable 0
under_oom 0
oom_kill 1

我们看到oom_kill被设置为1,这意味着”内核内存不足杀手”(OOM Killer)已经终止了memegroup中的进程。

  • memes程序源码如下;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
char *ptr;
int cnt = 0;
while(1) {
ptr = (char *)malloc(4096);
memset(ptr, 0, 4096);
cnt += 4096;
printf("%d bytes have been in use\n", cnt);
sleep(1);
}
return 0;
}

这是一个如何通过cgroup执行限制和过程控制的例子。

大多数子系统都有计数功能,比如memory.usage_in_bytes、cpuacct.usage_sys等等。优先级的一个例子是cpu.shares(每个cgroup中每个进程可用的CPU资源份额)。

Namespaces

Introduction

  • 命名空间是一个抽象对象,它封装了资源,以便资源具有限制于同一命名空间中的其他资源的视图
  • 例如,Linux进程形成了一个单进程树,根在init (PID 1)。一般情况下,特权进程可以跟踪或杀死其他进程。随着PID名称空间的引入,我们可以有多个不相交的进程树(它们不知道另一个名称空间中的进程)。如果我们创建一个新的PID名称空间并在其中运行一个进程,那么第一个进程就成为该名称空间中的PID 1创建命名空间的进程仍然位于父命名空间中,但使其子进程成为新进程树的根
  • Linux内核定义了7个命名空间

    • PID:隔离进程
    • Network:隔离网络
    • User:隔离用户/组id
    • UTS:隔离主机名和完全限定域名(FQDN)
    • Mount:隔离挂载点
    • cgroup:隔离Cgroup的sysfs根目录
    • IPC:隔离IPC/消息队列
  • 通过procfs查看系统中定义的名称空间
1
2
3
student@6858-v20:~/cgroup$ sudo ls /proc/1/ns
cgroup mnt pid user
ipc net pid_for_children uts
  • 这种级别的隔离在容器化中很有用。如果没有名称空间,在容器中运行的进程可以更改另一个容器的主机名、卸载文件系统、删除网络接口、更改限制等。
  • 通过使用名称空间来封装这些资源容器X中的进程不知道另一个容器Y中的资源
  • 随着名称空间的引入,Linux内核提供了3个新的系统调用:

    • clone():使用指定的名称空间创建一个新进程。如果传递了CLONE_NEW标志,则为每个指定的名称空间创建新的名称空间。
    • setns():允许进程加入一个现有的命名空间。命名空间由procfs中的文件描述符引用指定。
    • unshare():将调用进程移动到一个新的命名空间。
1
2
3
4
5
6
7
8
9
10
11
12
13
#procfs下的文件描述符
student@6858-v20:~/cgroup$ sudo ls -al /proc/1/ns
total 0
dr-x--x--x 2 root root 0 May 20 01:28 .
dr-xr-xr-x 9 root root 0 May 19 22:29 ..
lrwxrwxrwx 1 root root 0 May 20 01:28 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 May 20 01:28 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0 May 20 01:28 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0 May 20 01:28 net -> 'net:[4026531993]'
lrwxrwxrwx 1 root root 0 May 20 01:28 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 May 20 01:28 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 May 20 01:28 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 May 20 01:28 uts -> 'uts:[4026531838]'

Example

  • 在新的UTS名称空间中创建新的bash
1
2
3
4
5
6
7
8
9
10
student@6858-v20:~$ hostname
6858-v20
student@6858-v20:~$ sudo unshare -u /bin/bash
root@6858-v20:/home/rayden# hostname lmao
root@6858-v20:/home/rayden# hostname
lmao
root@6858-v20:/home/rayden# exit
exit
student@6858-v20:~$ hostname
6858-v20

注意:主机名在父进程中不变

  • 进程id可以做到相同的事
1
2
3
student@6858-v20:~/cgroup$ sudo unshare --fork --pid --mount-proc /bin/bash
root@6858-v20:~/cgroup# pidof /bin/bash
1
  • 在父进程中查看fork出来的进程id不为1
1
2
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root 4446 0.0 0.0 7912 780 pts/1 S 01:40 0:00 unshare --fork --pid --mount-proc /bin/bash

Difference

  • cgroups定义了一个名称空间子系统(因此可以通过名称空间控制资源),但是注意不要混淆这两者:
    • cgroups限制资源利用率,而名称空间限制资源视图(资源在系统上可能看到的内容)。

seccomp

Introduction

  • 在有些情况下,通过chroot、capabilities、cgroup和namespaces进行隔离是不够的
  • 假设某个运行在容器中的web服务器遭到破坏,攻击者生成了一个远程shell。宿主进程和容器可以调用同一组系统调用,并且可能存在一些调用序列,使容器逃逸成为可能。
  • seccomp通过限制进程允许执行的系统调用的数量来防止恶意进程通过系统调用造成的破坏。
    • 像Chrome和Firefox这样的现代浏览器使用seccomp来更严格地限制它们的应用程序。
    • 通过将系统调用接口限制为只允许容器化应用程序执行其功能所需的系统调用,可以很容易地阻止许多容器逃逸漏洞。
  • 在lxc中,可以通过容器配置文件指定seccomp过滤器
1
2
#vim ~/.local/share/lxc/<container_name>/config
lxc.seccomp = /usr/share/lxc/config/common.seccomp

/usr/share/lxc/config/common.seccomp默认拒绝的系统调用列表。

MAC

  • 假设在上一节的小型web服务器的例子中,攻击者无视chroot, capabilities, cgroups, namespaces和seccomp成功地逃出了容器。现在会发生什么?
    • 如果容器是有特权的(使用UID 0运行),它几乎是完胜。
    • 如果它是无特权的,攻击者仍然可以尝试升级特权,或者如果当前用户的特权足够大,就会造成足够大的破坏。
  • 在这种情况下,只有自由访问控制(DAC)(通过UNIX权限)站在攻击者和完全受损的系统之间。在老式的纵深防御模式中,我们使用另一种控制来降低这种风险:强制访问控制(Mandatory Access Control)。
  • MAC是一种集中的授权机制,其运作原理是信息属于组织(而不是个体成员)。安全策略被定义并保存在内核中,内核根据定义的策略授权访问。像SELinux这样的现代MAC实现是基于角色访问控制(RBAC)和两个概念的结合:

TE

  • TE将类型标记引入到每个文件系统对象中,这是MAC的先决条件
    • 对象被标记一个类型,并且在内核中定义了一个策略来指定哪些类型允许过渡到其他类型
    • 然后,每次访问带标签的文件系统对象时,内核都会检查指定的策略。如果不存在特定的类型转换,则默认拒绝访问。
    • 例如,在 Security-Enhanced Linux (SELinux)中,适用于Apache提供的web服务器内容的标准标签httpd_sys_content_t不允许访问标记为bin_t的文件,它适用于/usr/bin中的二进制文件。
  • 假设,在同一个小型web服务器示例中,攻击者设法获得了root访问权。
    • 在DAC下,任何用户都可以任意控制自己拥有的任何东西,因此攻击者拥有完全的控制权。
    • 如果TE是通过SELinux实现的,则攻击者会受到严重阻碍:web服务器exploit给了一个UID 0的进程,但exploit继承自被exploit的网页的类型标签(httpd_sys_content_t),其只允许访问相同标签的其他文件系统对象(由web服务器提供的内容应该只需要访问其他web内容,而不需要访问其他东西)。
  • 类似地,如果我们为容器主机启用了像SELinux这样的MAC机制,那么所有容器都将被标记为默认的lxc_t类型标签(由用于lxc的默认SELinux TE策略定义)。任何绕过其他隔离机制的恶意进程都将受到TE策略的限制。

MLS

MLS超纲了,此处省略。

Demo: working with lxc

  • 在Ubuntu上安装lxc:
1
sudo apt install lxc

Subordinate UID/GID ranges

  • 通过定义以下文件,我们可以确保当前用户可以拥有从属的uid和gid:
1
2
3
4
5
6
7
8
student@6858-v20:~/cgroup$ cat /etc/subuid
lxd:100000:65536
root:100000:65536
student:165536:65536
student@6858-v20:~/cgroup$ cat /etc/subgid
lxd:100000:65536
root:100000:65536
student:165536:65536
  • 这允许用户student拥有从165536开始的65536个从属uid /gid。
  • 我们还需要为lxc创建用户配置目录,如果它不存在,并创建默认配置文件:
1
2
mkdir -p ~/.config/lxc
touch ~/.config/lxc/default.conf
  • 应该修改~/.config/lxc/default.conf文件,使其看起来像这样(使用正确的id_map值):
1
2
3
student@6858-v20:~/cgroup$ cat ~/.config/lxc/default.conf 
lxc.idmap = u 0 165536 65536
lxc.idmap = g 0 165536 65536

Virtual network interfaces

  • 在安装lxc时,应该已经创建了一个默认网桥:lxcbr0。通过命令验证网桥是否存在
1
2
3
4
5
6
7
8
9
10
11
12
student@6858-v20:~/cgroup$ brctl show
bridge name bridge id STP enabled interfaces
lxcbr0 8000.00163e000000 no
lxcbr1 8000.00163e000000 no
lxcbr2 8000.00163e000000 no
lxcbr3 8000.00163e000000 no
lxcbr4 8000.00163e000000 no
lxcbr5 8000.00163e000000 no
lxcbr6 8000.00163e000000 no
lxcbr7 8000.00163e000000 no
lxcbr8 8000.00163e000000 no
lxcbr9 8000.00163e000000 no
  • 确保/etc/lxc/lxc-usernet文件定义为:
1
2
3
4
5
6
7
8
9
10
11
12
student@6858-v20:~/cgroup$ cat /etc/lxc/lxc-usernet
# USERNAME TYPE BRIDGE COUNT
student veth lxcbr0 10
student veth lxcbr1 10
student veth lxcbr2 10
student veth lxcbr3 10
student veth lxcbr4 10
student veth lxcbr5 10
student veth lxcbr6 10
student veth lxcbr7 10
student veth lxcbr8 10
student veth lxcbr9 10

这告诉lxc它可以将多少虚拟网络接口作为用户student连接到指定的网桥(或组,每行一个)。

应用更改的最快方法是重新启动节点或注销并重新登录

  • 这将重启dbus、正确设置cgroup并打开用户名称空间(kernel.unprivileged_userns_clone=1)。
  • 验证以太网网络模块
1
lsmod | grep veth
  • 如果veth模块没有加载,加载它并使其在重启后持续存在:
1
echo veth | sudo tee -a /etc/modules

Creating a container

  • 运行lxc-create来创建一个容器:
1
2
3
4
5
6
7
8
9
10
student@6858-v20:~/cgroup$ lxc-create -t download -n example
Setting up the GPG keyring
Downloading the image index

---
DIST RELEASE ARCH VARIANT BUILD
---
almalinux 8 amd64 default 20220519_23:08
almalinux 8 arm64 default 20220519_23:08
almalinux 8 ppc64el default 20220519_23:08
  • 这是一个交互式命令,使用download模板创建一个名为example的容器。lxc install中指定了4个默认模板,基本上都是在/usr/share/lxc/templates/目录下的脚本:

    • download:下载预构建的映像并解压缩它们
    • local:使用distrobuilder build-lxc命令构建的本地映像
    • busybox:包含在单个可执行文件中的通用UNIX实用程序
    • oci:从开放容器图像(oci)格式的图像创建应用程序容器
  • download模板提示您从给定的列表中选择发行版/发行版作为容器的基本映像,我们将使用该映像创建示例容器。

    • 我们可以直接在命令行中指定所需的映像,例如Ubuntu 19.10 (Eoan) amd64映像(注意名称后的双破折号):
1
lxc-create -t download -n example -- --dist ubuntu --release focalx --arch amd64
  • 将在~/.local/share/lxc/example/处创建一个容器目录,带有一个特定于容器的配置文件config,在这里你可以指定更多的过滤和控制,如MAC、seccomp拒绝列表、网络等。你会看到新创建的容器的root文件系统被解压到rootfs/中,它看起来像一个标准的Linux根文件系统:
1
2
3
student@6858-v20:~/.local/share/lxc/example$ ls rootfs/
bin dev home lib32 libx32 mnt proc run srv tmp var
boot etc lib lib64 media opt root sbin sys usr
  • 可以通过在rootfs目录上使用chroot进行离线更改(无需启动和附加到容器)。

Running a container

  • 后台运行example容器:
1
lxc-start example

如果在启动容器时遇到错误,使用-F选项在前台启动容器将提供更详细的输出。

  • 验证我们的容器正在运行:
1
2
3
4
student@6858-v20:~/lab$ lxc-info example
Name: example
State: RUNNING
PID: 21372
  • 查看所有的容器:
1
2
3
student@6858-v20:~/lab$ lxc-ls --fancy
NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
example RUNNING 0 - - - true
  • 连接到正在运行的容器实例:
1
2
3
4
5
6
7
student@6858-v20:~/lab$ lxc-attach example
root@example:/# id
uid=0(root) gid=0(root) groups=0(root)
root@example:/# passwd
New password:
Retype new password:
passwd: password updated successfully

一旦我们添加了用户并更改了他们的密码,我们就可以通过命令lxc-console使用交互式登录连接到容器

不同之处在于,lxc-attach的行为更像是基于密钥的ssh设置(在没有任何提示的情况下直接获得一个root会话),而lxc-console为您提供了一个虚拟控制台,它模拟了一个真实服务器上的交互式控制台,如serial、DRAC、ILO等。

  • 注意:我们是容器中的root,尽管我们创建的是一个非特权容器。
    • 此行为是UID名称空间的结果。我们可以看到,通过在容器中运行一个进程,容器中的任何进程都被映射到主机上一个无特权的UID:
1
2
root@example:/# while [ 1 ]; do sleep 5; done &
[1] 130
  • 在主机上可以看到,进程以UID 165536运行:
1
2
student@6858-v20:~$ ps aux | grep sleep
165536 22060 0.0 0.0 9832 580 pts/5 S 03:55 0:00 sleep 5
  • 如果从ps aux输出查看其他进程,可以注意到容器的init进程也是通过uid映射的:
1
2
student@6858-v20:~$ ps aux | grep init
165536 21372 0.0 0.5 103876 10656 ? Ss 03:49 0:00 /sbin/init
  • 我们可以在里面运行大多数系统管理任务,比如安装包。
    • 安装nginx web服务器和net-tools二进制包:
1
2
3
4
root@example:/# apt update
[output truncated]
root@example:/# apt install nginx net-tools
[output truncated]
  • 验证nginx在80端口运行:
1
2
3
4
root@example:/# netstat -atunp | grep LISTEN
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 88/systemd-resolved
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 881/nginx: master p
tcp6 0 0 :::80 :::* LISTEN 881/nginx: master p

Networking

  • LXC默认情况下创建一个独立的网桥,它对所有到主接口的流量使用masquerading(伪装)
    • 网桥是凭空创建的(lxcbr0),容器连接到这个网桥。
    • 如果主接口也可以访问Internet(通过转发和伪装),则允许容器访问Internet。
    • 快速查看主机上的接口,可以看到带有Internet连接ens33的主接口、默认桥接器lxcbr0和容器示例中的虚拟接口veth1000_XXXX。
1

Stopping a container

  • 要停止创建的示例容器,只需发出以下命令:
1
lxc-stop example
  • 从文件系统中清除(删除)容器:
1
lxc-destroy example

What’s the difference between lxc and Docker?

这两种解决方案适用于不同的用例

  • lxc:出现的时间更长(Docker过去使用lxc)。

    • 感觉更像是虚拟机中的一个完整的操作系统,必须以类似的方式处理:软件必须手动安装和更新,要么手工安装,要么通过配置管理工具,如Ansible
  • Docker:用于运行单个应用程序

    • 没有完整的系统进程堆栈,如lxc。一个容器的应用程序及其依赖是使用Dockerfile构建和部署的。
  • 在容器编排方面,两者都有相当新的工具:

    • lxc有lxd, Docker有Docker Swarm和Kubernetes。
    • 有一个名为lxe的新项目,旨在将lxc/lxd与Kubernetes集成。

Docker不使用lxc;Docker曾经使用lxc来运行容器,但在几年前就停止了。

Docker和lxc都使用相同的内核特性来实现容器化,但它们是独立的解决方案。

Summary

  • 容器是与系统其他部分隔离的一个或多个进程的集合。

  • lxc通过使用Linux内核特性来抽象操作系统,并隔离容器来实现容器化,例如:

    • Control Groups (cgroups)

    • Capabilities

    • seccomp
    • Mandatory Access Control(通过AppArmor, SELinux)
    • Namespaces
    • chroot jails
  • lxc配置位置

    • lxc特定于容器的配置位于~/.local/share/lxc/<container name>/config
    • 针对lxc的用户特定配置位于~/.config/lxc/default.conf
    • lxc的全局配置位于/etc/lxc/default.conf
    • 容器rootfs位于~/.local/share/lxc/<container name>/rootfs
  • lxc用法

    • 使用lxc-attach创建容器
    • 使用lxc-start启动容器
    • 使用lxc-stop停止容器
    • 使用lxc-info列出容器
    • 使用lxc-destroy销毁容器