CGManager 是一个核心的特权守护进程，通过一个简单的 D-Bus API 管理你所有的 cgroup。它被设计用来处理嵌套的 LXC 容器以及接受无特权的请求，包括解析用户名称空间的 UID/GID。组件cgmanager这个守护进程在宿主机上运行，​​将 cgroupfs 挂载到一个独立的挂载名称空间（所以它不能从宿主机上看到），绑定 /sys/fs/cgroup/cgmanager/sock 用于传入的 D-Bus 查询，并通常处理宿主机上直接运行的所有客户端。cgmanager 既接受使用 D-Bus + SCM 凭证的身份验证请求，用于在命名空间之间转换 uid、gid 和 pid，也可以使用简单的 “unauthenticated”（只是初始的 ucred）D-Bus 来查询来自宿主机级别的查询。cgproxy你可能会在两种情况下看到这个守护进程运行。在宿主机上，如果你的内核老于 3.8（没有 pidns 连接支持）或处于容器中（只有 cgproxy 运行）。cgproxy 本身并不做任何 cgroup 配置更改，而是如其名称所示，代理请求给主 cgmanager 进程。这是必要的，所以一个进程可以直接使用 D-Bus（例如使用 dbus-send）与 /sys/fs/cgroup/cgmanager/sock 进行通信。之后 cgproxy 将从该查询中得到 ucred，并对真正的 cgmanager 套接字进行身份验证的 SCM 查询，并通过 ucred 结构体传递参数，使它们能够正确地转换为 cgmanager 可以理解的宿主机命名空间 。cgm一个简单的命令行工具，与 D-Bus 服务通信，并允许你从命令行执行所有常见的 cgroup 操作。通信协议如上所述，cgmanager 和 cgproxy 使用 D-Bus。建议外部客户端（所以不要是 cgproxy）使用标准的 D-Bus API，不要试图实现 SCM creds 协议，因为它是不必要的，并且容易出错。相反，只要简单假设与 /sys/fs/cgroup/cgmanager/sock 的通信总是正确的。cgmanager API 仅在独立的 D-Bus 套接字上可用，cgmanager 本身不连接到系统总线，所以 cgmanager/cgproxy 不要求有运行中的 dbus 守护进程。你可以在这里阅读更多关于 D-Bus API。许可证CGManager 是免费软件，大部分代码是根据 GNU LGPLv2.1+ 许可条款发布的，一些二进制文件是在 GNU GPLv2 许可下发布的。该项目的默认许可证是 GNU LGPLv2.1+支持CGManager 的稳定版本支持依赖于 Linux 发行版以及它们自己承诺推出稳定修复和安全更新。你可以从 Canonical Ltd 获得对 Ubuntu LTS 版本的 CGManager 的商业支持。via: https://linuxcontainers.org/cgmanager/introduction/作者：Canonical Ltd. 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
本文的主角是容器，一种类似虚拟机但更轻量级的构造。你可以轻易地在你的 Ubuntu 桌面系统中创建一堆容器！虚拟机会虚拟出整个电脑让你来安装客户机操作系统。相比之下，容器复用了主机的 Linux 内核，只是简单地 包容 了我们选择的根文件系统（也就是运行时环境）。Linux 内核有很多功能可以将运行的 Linux 容器与我们的主机分割开（也就是我们的 Ubuntu 桌面）。Linux 本身需要一些手工操作来直接管理他们。好在，有 LXD（读音为 Lex-deeh），这是一款为我们管理 Linux 容器的服务。我们将会看到如何：在我们的 Ubuntu 桌面上配置容器，创建容器，安装一台 web 服务器，测试一下这台 web 服务器，以及清理所有的东西。设置 Ubuntu 容器如果你安装的是 Ubuntu 16.04，那么你什么都不用做。只要安装下面所列出的一些额外的包就行了。若你安装的是 Ubuntu 14.04.x 或 Ubuntu 15.10，那么按照 LXD 2.0 系列（二）：安装与配置 来进行一些操作，然后再回来。确保已经更新了包列表：sudo apt update sudo apt upgrade 安装 lxd 包：sudo apt install lxd 若你安装的是 Ubuntu 16.04，那么还可以让你的容器文件以 ZFS 文件系统的格式进行存储。Ubuntu 16.04 的 Linux kernel 包含了支持 ZFS 必要的内核模块。若要让 LXD 使用 ZFS 进行存储，我们只需要安装 ZFS 工具包。没有 ZFS，容器会在主机文件系统中以单独的文件形式进行存储。通过 ZFS，我们就有了写入时拷贝等功能，可以让任务完成更快一些。安装 zfsutils-linux 包（若你安装的是 Ubuntu 16.04.x）：sudo apt install zfsutils-linux 安装好 LXD 后，包安装脚本应该会将你加入 lxd 组。该组成员可以使你无需通过 sudo 就能直接使用 LXD 管理容器。根据 Linux 的习惯，你需要先登出桌面会话然后再登录 才能应用 lxd 的组成员关系。（若你是高手，也可以通过在当前 shell 中执行 newgrp lxd 命令，就不用重登录了）。在开始使用前，LXD 需要初始化存储和网络参数。运行下面命令：$ sudo lxd init Name of the storage backend to use (dir or zfs): zfs Create a new ZFS pool (yes/no)? yes Name of the new ZFS pool: lxd-pool Would you like to use an existing block device (yes/no)? no Size in GB of the new loop device (1GB minimum): 30 Would you like LXD to be available over the network (yes/no)? no Do you want to configure the LXD bridge (yes/no)? yes > You will be asked about the network bridge configuration. Accept all defaults and continue. Warning: Stopping lxd.service, but it can still be activated by: lxd.socket LXD has been successfully configured. $ _ 我们在一个（单独）的文件而不是块设备（即分区）中构建了一个文件系统来作为 ZFS 池，因此我们无需进行额外的分区操作。在本例中我指定了 30GB 大小，这个空间取之于根（/） 文件系统中。这个文件就是 /var/lib/lxd/zfs.img。行了！最初的配置完成了。若有问题，或者想了解其他信息，请阅读 https://www.stgraber.org/2016/03/15/lxd-2-0-installing-and-configuring-lxd-212/ 。创建第一个容器所有 LXD 的管理操作都可以通过 lxc 命令来进行。我们通过给 lxc 不同参数来管理容器。lxc list 可以列出所有已经安装的容器。很明显，这个列表现在是空的，但这表示我们的安装是没问题的。lxc image list 列出可以用来启动容器的（已经缓存的）镜像列表。很明显这个列表也是空的，但这也说明我们的安装是没问题的。lxc image list ubuntu： 列出可以下载并启动容器的远程镜像。而且指定了显示 Ubuntu 镜像。lxc image list images： 列出可以用来启动容器的（已经缓存的）各种发行版的镜像列表。这会列出各种发行版的镜像比如 Alpine、Debian、Gentoo、Opensuse 以及 Fedora。让我们启动一个 Ubuntu 16.04 容器，并称之为 c1：$ lxc launch ubuntu：x c1 Creating c1 Starting c1 $ 我们使用 launch 动作，然后选择镜像 ubuntu：x （x 表示 Xenial/16.04 镜像），最后我们使用名字 c1 作为容器的名称。让我们来看看安装好的首个容器，$ lxc list +---------|---------|----------------------|------|------------|-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +---------|---------|----------------------|------|------------|-----------+ | c1 | RUNNING | 10.173.82.158 (eth0) | | PERSISTENT | 0 | +---------|---------|----------------------|------|------------|-----------+ 我们的首个容器 c1 已经运行起来了，它还有自己的 IP 地址（可以本地访问）。我们可以开始用它了！安装 web 服务器我们可以在容器中运行命令。运行命令的动作为 exec。$ lxc exec c1 -- uptime 11：47：25 up 2 min，0 users，load average：0.07，0.05，0.04 $ _ 在 exec 后面，我们指定容器、最后输入要在容器中运行的命令。该容器的运行时间只有 2 分钟，这是个新出炉的容器：-)。命令行中的 -- 跟我们 shell 的参数处理过程有关。若我们的命令没有任何参数，则完全可以省略 -。$ lxc exec c1 -- df -h 这是一个必须要 - 的例子，由于我们的命令使用了参数 -h。若省略了 -，会报错。然后我们运行容器中的 shell 来更新包列表。$ lxc exec c1 bash root@c1:~# apt update Ign http://archive.ubuntu.com trusty InRelease Get:1 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB] Get:2 http://security.ubuntu.com trusty-security InRelease [65.9 kB] ... Hit http://archive.ubuntu.com trusty/universe Translation-en Fetched 11.2 MB in 9s (1228 kB/s) Reading package lists... Done root@c1:~# apt upgrade Reading package lists... Done Building dependency tree ... Processing triggers for man-db (2.6.7.1-1ubuntu1) ... Setting up dpkg (1.17.5ubuntu5.7) ... root@c1:~# _ 我们使用 nginx 来做 web 服务器。nginx 在某些方面要比 Apache web 服务器更酷一些。root@c1:~# apt install nginx Reading package lists... Done Building dependency tree ... Setting up nginx-core (1.4.6-1ubuntu3.5) ... Setting up nginx (1.4.6-1ubuntu3.5) ... Processing triggers for libc-bin (2.19-0ubuntu6.9) ... root@c1:~# _ 让我们用浏览器访问一下这个 web 服务器。记住 IP 地址为 10.173.82.158，因此你需要在浏览器中输入这个 IP。让我们对页面文字做一些小改动。回到容器中，进入默认 HTML 页面的目录中。root@c1:~# cd /var/www/html/ root@c1:/var/www/html# ls -l total 2 -rw-r--r-- 1 root root 612 Jun 25 12:15 index.nginx-debian.html root@c1:/var/www/html# 使用 nano 编辑文件，然后保存：之后，再刷一下页面看看，清理让我们清理一下这个容器，也就是删掉它。当需要的时候我们可以很方便地创建一个新容器出来。$ lxc list +---------+---------+----------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +---------+---------+----------------------+------+------------+-----------+ | c1 | RUNNING | 10.173.82.169 (eth0) | | PERSISTENT | 0 | +---------+---------+----------------------+------+------------+-----------+ $ lxc stop c1 $ lxc delete c1 $ lxc list +---------+---------+----------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +---------+---------+----------------------+------+------------+-----------+ +---------+---------+----------------------+------+------------+-----------+ 我们停止（关闭）这个容器，然后删掉它了。本文至此就结束了。关于容器有很多玩法。而这只是配置 Ubuntu 并尝试使用容器的第一步而已。via: https://blog.simos.info/trying-out-lxd-containers-on-our-ubuntu/作者：Simos Xenitellis 译者：lujun9972 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
最近，我对 lxc exec 进行了几个改进。如果你不知道它的话我介绍一下，lxc exec 是 LXD 的客户端工具，使用 LXD 客户端 api 与 LXD 守护程序通信，并执行用户想要执行的各种程序，以下是你可以使用的一个例子：我们的主要目标之一就是使 lxc exec 与 ssh 类似，因为它是交互式或非交互式远程运行命令的标准。这使得 把 lxc exec 做得很好变得有点棘手。1、 处理后台任务一个长期存在的问题当然是如何正确处理后台任务。这是一个关于 LXD 2.7 实例的问题的例子：你可以看到，在后台执行任务将导致 lxc exec 无法退出。许多命令可以触发此问题：chb@conventiont|~ > lxc exec zest1 bash root@zest1:~# yes & y y y . . . 现在没有什么能救你了。yes 将会永远直接写入stdout。问题的根源在于 stdout 是一直打开着的，但这是必要的，因为它用以确保用户所启动的进程写入的任何数据实际上都是通过我们建立的 websocket 连接读取并发回的。假如你想这样，运行一个 shell 会话，然后在后台运行一个进程，并马上退出 shell。对不起，它并不能如预期那样。第一种并且原始的方法是一旦你检测到前台程序（例如 shell）已经退出就直接关闭 stdout。但这不像想得那么好，当你运行快速执行程序时，这个问题会变得明显，比如：lxc exec -- ls -al /usr/lib 这里 lxc exec 进程（和相关的 forkexec 进程。但现在不要考虑它，只要记住 Go + setns() 不相往来就行了……）会在 stdout 中所有的缓冲数据被读取之前退出。这种情况下将会导致截断输出，没有人想要这样。在尝试使用几个方法来解决问题之后，包括禁用 pty 缓冲（我告诉你，这不太漂亮，也没有如预期工作。）和其他奇怪的思路，我设法通过几个 poll() “技巧”（在某种意义上说一个“技巧”）解决了这个问题。现在你终于可以运行后台任务，并且可以完全退出了。如图：2、 报告由信号引起的退出码ssh 是一个很棒的工具。但有一件事，我一直以来不喜欢当 ssh 运行的命令接收到一个信号时， ssh 总是会报告 -1，也就是退出码 255。当你想要了解导致程序终止的信号时，这很烦人。这就是为什么我最近实施标准 shell 所使用的惯例 128 + n 来报告任何由信号导致的退出，其中 n 被定义为导致执行程序退出的信号量。例如，在 SIGKILL 信号上，你会看到 128 + SIGKILL = 137（计算其他致命信号的退出码作为读者的练习）。所以你可以这么做：chb@conventiont|~ > lxc exec zest1 sleep 100 现在，将 SIGKILL 发送到执行程序（不是 lxc exec本身，因为 SIGKILL 不可转发）。kill -KILL $(pidof sleep 100) 最后检查你程序的退出码：chb@conventiont|~ > echo $? 137 瞧。这显然只有当 a) 退出码没有超过 8 位计算壁垒，b）当执行程序不使用 137 来表示成功（这可真……有趣？！）。这两个论点似乎对我来说都不太有说服力。前者因为致命信号量不应该超过这个范围。后者因为（i）这是用户问题，（ii）这些退出代码实际上是保留的（我是这样认为。），（iii）你在本地或其他上面运行程序时会遇到同样的问题。我看到的主要优点是这能够回报执行程序细粒度的退出状态。注意，我们不会报告所有被信号杀死的程序实例。比如说，当你的程序能够处理 SIGTERM 并且完全退出时，LXD 没有简单的方法来检测到这个情况并报告说这个程序被信号杀死了。你只会简单地收到退出码 0。3、 转发信号这可能不太有趣（或者也许不是，谁知道呢），但我发现它非常有用。正如你在 SIGKILL 案例中看到的那样，我明确地指出，必须将 SIGKILL 发送到执行程序，而不是 lxc exec命令本身。这是因为 SIGKILL 在程序中无法处理。程序可以做的唯一的事情就是去死，像现在这样……像这个例子……马上（你明白了了吧……）。但是程序可以处理很多其他信号 SIGTERM、SIGHUP'，当然也可以处理SIGUSR1和SIGUSR2。因此，当你发送可以被lxc exec` 处理而不是被执行程序处理的信号时，较新版本的 LXD 会将信号转发到执行进程。这在脚本中非常方便。无论如何，我希望你觉得这篇小小的 lxc exec 文章/胡言乱语有用。享受 LXD 吧，这是与一只疯狂的美丽的野兽玩耍。请试试在线实验：https://linuxcontainers.org/lxd/try-it/，对于开发人员看看这里：https://github.com/lxc/lxd 并给我们补丁。我们不要求签署任何 CLA，我们遵循内核风格，只要其中有 “Signed-off-by” 这行就好。via: https://cbrauner.wordpress.com/2017/01/20/lxc-exec-vs-ssh/作者：brauner 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
这是 LXD 2.0 系列介绍文章的第五篇。LXD 入门安装与配置你的第一个 LXD 容器资源控制镜像管理远程主机及容器迁移LXD 中的 DockerLXD 中的 LXD实时迁移LXD 和 JujuLXD 和 OpenStack调试，及给 LXD 做贡献因为 lxd 容器管理有很多命令，因此这篇文章会很长。 如果你想要快速地浏览这些相同的命令，你可以尝试下我们的在线演示！容器镜像如果你以前使用过 LXC，你可能还记得那些 LXC “模板”，基本上都是导出一个容器文件系统以及一点配置的 shell 脚本。大多数模板是通过在本机上执行一个完整的发行版自举来生成该文件系统。这可能需要相当长的时间，并且无法在所有的发行版上可用，另外可能需要大量的网络带宽。回到 LXC 1.0，我写了一个“下载”模板，它允许用户下载预先打包的容器镜像，用模板脚本在中央服务器上生成，接着高度压缩、签名并通过 https 分发。我们很多用户从旧版的容器生成方式切换到了使用这种新的、更快更可靠的创建容器的方式。使用 LXD，我们通过全面的基于镜像的工作流程向前迈进了一步。所有容器都是从镜像创建的，我们在 LXD 中具有高级镜像缓存和预加载支持，以使镜像存储保持最新。与 LXD 镜像交互在更深入了解镜像格式之前，让我们快速了解下 LXD 可以让你做些什么。透明地导入镜像所有的容器都是由镜像创建的。镜像可以来自一台远程服务器并使用它的完整 hash、短 hash 或者别名拉取下来，但是最终每个 LXD 容器都是创建自一个本地镜像。这有个例子：lxc launch ubuntu:14.04 c1 lxc launch ubuntu:75182b1241be475a64e68a518ce853e800e9b50397d2f152816c24f038c94d6e c2 lxc launch ubuntu:75182b1241be c3 所有这些引用相同的远程镜像（在写这篇文章时），在第一次运行这些命令其中之一时，远程镜像将作为缓存镜像导入本地 LXD 镜像存储，接着从其创建容器。下一次运行其中一个命令时，LXD 将只检查镜像是否仍然是最新的（当不是由指纹引用时），如果是，它将创建容器而不下载任何东西。现在镜像被缓存在本地镜像存储中，你也可以从那里启动它，甚至不检查它是否是最新的：lxc launch 75182b1241be c4 最后，如果你有个名为“myimage”的本地镜像，你可以：lxc launch my-image c5 如果你想要改变一些自动缓存或者过期行为，在本系列之前的文章中有一些命令。手动导入镜像从镜像服务器中复制如果你想复制远程的某个镜像到你本地镜像存储，但不立即从它创建一个容器，你可以使用lxc image copy命令。它可以让你调整一些镜像标志，比如：lxc image copy ubuntu:14.04 local: 这只是简单地复制一个远程镜像到本地存储。如果您想要通过比记住其指纹更容易的方式来记住你引用的镜像副本，则可以在复制时添加别名：lxc image copy ubuntu:12.04 local: --alias old-ubuntu lxc launch old-ubuntu c6 如果你想要使用源服务器上设置的别名，你可以要求 LXD 复制下来：lxc image copy ubuntu:15.10 local: --copy-aliases lxc launch 15.10 c7 上面的副本都是一次性拷贝，也就是复制远程镜像的当前版本到本地镜像存储中。如果你想要 LXD 保持镜像最新，就像它在缓存中存储的那样，你需要使用 –auto-update 标志：lxc image copy images:gentoo/current/amd64 local: --alias gentoo --auto-update 导入 tarball如果某人给你提供了一个单独的 tarball，你可以用下面的命令导入：lxc image import <tarball> 如果你想在导入时设置一个别名，你可以这么做：lxc image import <tarball> --alias random-image 现在如果你被给了两个 tarball，要识别哪个是含有 LXD 元数据的。通常可以通过 tarball 的名称来识别，如果不行就选择最小的那个，元数据 tarball 包是很小的。 然后将它们一起导入：lxc image import <metadata tarball> <rootfs tarball> 从 URL 中导入lxc image import 也可以与指定的 URL 一起使用。如果你的一台 https Web 服务器的某个路径中有 LXD-Image-URL 和 LXD-Image-Hash 的标头设置，那么 LXD 就会把这个镜像拉到镜像存储中。可以参照例子这么做：lxc image import https://dl.stgraber.org/lxd --alias busybox-amd64 当拉取镜像时，LXD 还会设置一些标头，远程服务器可以检查它们以返回适当的镜像。 它们是 LXD-Server-Architectures 和 LXD-Server-Version。这相当于一个简陋的镜像服务器。 它可以通过任何静态 Web 服务器提供一中用户友好的导入镜像的方式。管理本地镜像存储现在我们本地已经有一些镜像了，让我们瞧瞧可以做些什么。我们已经介绍了最主要的部分，可以从它们来创建容器，但是你还可以在本地镜像存储上做更多。列出镜像要列出所有的镜像，运行 lxc image list：stgraber@dakara:~$ lxc image list +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | alpine-32 | 6d9c131efab3 | yes | Alpine edge (i386) (20160329_23:52) | i686 | 2.50MB | Mar 30, 2016 at 4:36am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | busybox-amd64 | 74186c79ca2f | no | Busybox x86_64 | x86_64 | 0.79MB | Mar 30, 2016 at 4:33am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | gentoo | 1a134c5951e0 | no | Gentoo current (amd64) (20160329_14:12) | x86_64 | 232.50MB | Mar 30, 2016 at 4:34am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | my-image | c9b6e738fae7 | no | Scientific Linux 6 x86_64 (default) (20160215_02:36) | x86_64 | 625.34MB | Mar 2, 2016 at 4:56am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | old-ubuntu | 4d558b08f22f | no | ubuntu 12.04 LTS amd64 (release) (20160315) | x86_64 | 155.09MB | Mar 30, 2016 at 4:30am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | w (11 more) | d3703a994910 | no | ubuntu 15.10 amd64 (release) (20160315) | x86_64 | 153.35MB | Mar 30, 2016 at 4:31am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ | | 75182b1241be | no | ubuntu 14.04 LTS amd64 (release) (20160314) | x86_64 | 118.17MB | Mar 30, 2016 at 4:27am (UTC) | +---------------+--------------+--------+------------------------------------------------------+--------+----------+------------------------------+ 你可以通过别名或者指纹来过滤：stgraber@dakara:~$ lxc image list amd64 +---------------+--------------+--------+-----------------------------------------+--------+----------+------------------------------+ | ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE | +---------------+--------------+--------+-----------------------------------------+--------+----------+------------------------------+ | busybox-amd64 | 74186c79ca2f | no | Busybox x86_64 | x86_64 | 0.79MB | Mar 30, 2016 at 4:33am (UTC) | +---------------+--------------+--------+-----------------------------------------+--------+----------+------------------------------+ | w (11 more) | d3703a994910 | no | ubuntu 15.10 amd64 (release) (20160315) | x86_64 | 153.35MB | Mar 30, 2016 at 4:31am (UTC) | +---------------+--------------+--------+-----------------------------------------+--------+----------+------------------------------+ 或者指定一个镜像属性中的键值对来过滤：stgraber@dakara:~$ lxc image list os=ubuntu +-------------+--------------+--------+---------------------------------------------+--------+----------+------------------------------+ | ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE | +-------------+--------------+--------+---------------------------------------------+--------+----------+------------------------------+ | old-ubuntu | 4d558b08f22f | no | ubuntu 12.04 LTS amd64 (release) (20160315) | x86_64 | 155.09MB | Mar 30, 2016 at 4:30am (UTC) | +-------------+--------------+--------+---------------------------------------------+--------+----------+------------------------------+ | w (11 more) | d3703a994910 | no | ubuntu 15.10 amd64 (release) (20160315) | x86_64 | 153.35MB | Mar 30, 2016 at 4:31am (UTC) | +-------------+--------------+--------+---------------------------------------------+--------+----------+------------------------------+ | | 75182b1241be | no | ubuntu 14.04 LTS amd64 (release) (20160314) | x86_64 | 118.17MB | Mar 30, 2016 at 4:27am (UTC) | +-------------+--------------+--------+---------------------------------------------+--------+----------+------------------------------+ 要了解镜像的所有信息，你可以使用lxc image info：stgraber@castiana:~$ lxc image info ubuntu Fingerprint: e8a33ec326ae7dd02331bd72f5d22181ba25401480b8e733c247da5950a7d084 Size: 139.43MB Architecture: i686 Public: no Timestamps: Created: 2016/03/15 00:00 UTC Uploaded: 2016/03/16 05:50 UTC Expires: 2017/04/26 00:00 UTC Properties: version: 12.04 aliases: 12.04,p,precise architecture: i386 description: ubuntu 12.04 LTS i386 (release) (20160315) label: release os: ubuntu release: precise serial: 20160315 Aliases: - ubuntu Auto update: enabled Source: Server: https://cloud-images.ubuntu.com/releases Protocol: simplestreams Alias: precise/i386 编辑镜像编辑镜像的属性和标志的简单方法是使用：lxc image edit <alias or fingerprint> 这会打开默认文本编辑器，内容像这样：autoupdate: true properties: aliases: 14.04,default,lts,t,trusty architecture: amd64 description: ubuntu 14.04 LTS amd64 (release) (20160314) label: release os: ubuntu release: trusty serial: "20160314" version: "14.04" public: false 你可以修改任何属性，打开或者关闭自动更新，或者标记一个镜像是公共的（后面详述）。删除镜像删除镜像只需要运行：lxc image delete <alias or fingerprint> 注意你不必移除缓存对象，它们会在过期后被 LXD 自动移除（默认上，在最后一次使用的 10 天后）。导出镜像如果你想得到目前镜像的 tarball，你可以使用lxc image export，像这样：stgraber@dakara:~$ lxc image export old-ubuntu . Output is in . stgraber@dakara:~$ ls -lh *.tar.xz -rw------- 1 stgraber domain admins 656 Mar 30 00:55 meta-ubuntu-12.04-server-cloudimg-amd64-lxd.tar.xz -rw------- 1 stgraber domain admins 156M Mar 30 00:55 ubuntu-12.04-server-cloudimg-amd64-lxd.tar.xz 镜像格式LXD 现在支持两种镜像布局，unified 或者 split。这两者都是有效的 LXD 格式，虽然后者在与其他容器或虚拟机一起运行时更容易重用其文件系统。LXD 专注于系统容器，不支持任何应用程序容器的“标准”镜像格式，我们也不打算这么做。我们的镜像很简单，它们是由容器文件系统，以及包含了镜像制作时间、到期时间、什么架构，以及可选的一堆文件模板的元数据文件组成。有关镜像格式的最新详细信息，请参阅此文档。unified 镜像（一个 tarball）unified 镜像格式是 LXD 在生成镜像时使用的格式。它们是一个单独的大型 tarball，包含 rootfs 目录下的容器文件系统，在 tarball 根目录下有 metadata.yaml 文件，任何模板都放到 templates 目录。tarball 可以用任何方式压缩（或者不压缩）。镜像散列是压缩后的 tarball 的 sha256 。Split 镜像（两个 tarball）这种格式最常用于滚动更新镜像并已经有了一个压缩文件系统 tarball 时。它们由两个不同的 tarball 组成，第一个只包含 LXD 使用的元数据， metadata.yaml 文件在根目录，任何模板都在 templates 目录。第二个 tarball 只包含直接位于其根目录下的容器文件系统。大多数发行版已经有这样的 tarball，因为它们常用于引导新机器。 此镜像格式允许不经修改就重用。两个 tarball 都可以压缩（或者不压缩），它们可以使用不同的压缩算法。 镜像散列是元数据的 tarball 和 rootfs 的 tarball 结合的 sha256。镜像元数据典型的 metadata.yaml 文件看起来像这样：architecture: "i686" creation_date: 1458040200 properties: architecture: "i686" description: "Ubuntu 12.04 LTS server (20160315)" os: "ubuntu" release: "precise" templates: /var/lib/cloud/seed/nocloud-net/meta-data: when: - start template: cloud-init-meta.tpl /var/lib/cloud/seed/nocloud-net/user-data: when: - start template: cloud-init-user.tpl properties: default: | #cloud-config {} /var/lib/cloud/seed/nocloud-net/vendor-data: when: - start template: cloud-init-vendor.tpl properties: default: | #cloud-config {} /etc/init/console.override: when: - create template: upstart-override.tpl /etc/init/tty1.override: when: - create template: upstart-override.tpl /etc/init/tty2.override: when: - create template: upstart-override.tpl /etc/init/tty3.override: when: - create template: upstart-override.tpl /etc/init/tty4.override: when: - create template: upstart-override.tpl 属性两个唯一的必填字段是 creation date（UNIX 纪元时间）和 architecture。 其他都可以保持未设置，镜像就可以正常地导入。额外的属性主要是帮助用户弄清楚镜像是什么。 例如 description 属性是在 lxc image list 中可见的。 用户可以使用其它属性的键/值对来搜索特定镜像。相反，这些属性用户可以通过 lxc image edit来编辑，creation date 和 architecture 字段是不可变的。模板模板机制允许在容器生命周期中的某一点生成或重新生成容器中的一些文件。我们使用 pongo2 模板引擎来做这些，我们将所有我们知道的容器信息都导出到模板。 这样，你可以使用用户定义的容器属性或常规 LXD 属性来自定义镜像，从而更改某些特定文件的内容。正如你在上面的例子中看到的，我们使用在 Ubuntu 中使用它们来进行 cloud-init 并关闭一些 init 脚本。创建你的镜像LXD 专注于运行完整的 Linux 系统，这意味着我们期望大多数用户只使用干净的发行版镜像，而不是只用自己的镜像。但是有一些情况下，你有自己的镜像是有必要的。 例如生产服务器上的预配置镜像，或者构建那些我们没有构建的发行版或者架构的镜像。将容器变成镜像目前使用 LXD 构造镜像最简单的方法是将容器变成镜像。可以这么做：lxc launch ubuntu:14.04 my-container lxc exec my-container bash <do whatever change you want> lxc publish my-container --alias my-new-image 你甚至可以将一个容器过去的快照变成镜像：lxc publish my-container/some-snapshot --alias some-image 手动构建镜像构建你自己的镜像也很简单。生成容器文件系统。这完全取决于你使用的发行版。对于 Ubuntu 和 Debian，它将用于启动。配置容器中该发行版正常工作所需的任何东西（如果需要任何东西）。制作该容器文件系统的 tarball，可选择压缩它。根据上面描述的内容写一个新的 metadata.yaml 文件。创建另一个包含 metadata.yaml 文件的 tarball。用下面的命令导入这两个 tarball 作为 LXD 镜像：lxc image import <metadata tarball> <rootfs tarball> --alias some-name在一切都正常工作前你可能需要经历几次这样的工作，调整这里或那里，可能会添加一些模板和属性。发布你的镜像所有 LXD 守护程序都充当镜像服务器。除非另有说明，否则加载到镜像存储中的所有镜像都会被标记为私有，因此只有受信任的客户端可以检索这些镜像，但是如果要创建公共镜像服务器，你需要做的是将一些镜像标记为公开，并确保你的 LXD 守护进程监听网络。只运行 LXD 公共服务器最简单的共享镜像的方式是运行一个公共的 LXD 守护进程。你只要运行：lxc config set core.https_address "[::]:8443" 远程用户就可以添加你的服务器作为公共服务器：lxc remote add <some name> <IP or DNS> --public 他们就可以像使用任何默认的镜像服务器一样使用它们。 由于远程服务器添加了 -public 选项，因此不需要身份验证，并且客户端仅限于使用已标记为 public 的镜像。要将镜像设置成公共的，只需使用 lxc image edit 编辑它们，并将 public 标志设置为 true。使用一台静态 web 服务器如上所述，lxc image import 支持从静态 https 服务器下载。 基本要求是：服务器必须支持具有有效证书的 HTTPS、TLS 1.2 和 EC 算法。当访问 lxc image import 提供的 URL 时，服务器必须返回一个包含 LXD-Image-Hash 和 LXD-Image-URL 的 HTTP 标头。如果你想使它动态化，你可以让你的服务器查找 LXD 在请求镜像时发送的 LXD-Server-Architectures 和 LXD-Server-Version 的 HTTP 标头，这可以让你返回符合该服务器架构的正确镜像。构建一个简单流服务器ubuntu: 和 ubuntu-daily: 远端服务器不使用 LXD 协议（images: 使用），而是使用称为简单流（simplestreams）的不同协议。简单流基本上是一个镜像服务器的描述格式，使用 JSON 来描述产品以及相关产品的文件列表。它被各种工具，如 OpenStack、Juju、MAAS 等用来查找、下载或者做镜像系统，LXD 将它作为用于镜像检索的原生协议。虽然这的确不是提供 LXD 镜像的最简单的方法，但是如果你的镜像也被其它一些工具使用，那这也许值得考虑一下。关于简单流的更多信息可以在这里找到。总结我希望这篇关于如何使用 LXD 管理镜像以及构建和发布镜像文章让你有所了解。对于以前的 LXC 而言，可以在一组全球分布式系统上得到完全相同的镜像是一个很大的进步，并且引导了更多可复制性的发展方向。额外信息LXD 的主站在： https://linuxcontainers.org/lxdLXD 的 GitHub 仓库： https://github.com/lxc/lxdLXD 的邮件列表： https://lists.linuxcontainers.orgLXD 的 IRC 频道： #lxcontainers on irc.freenode.net如果你不想或者不能在你的机器上安装 LXD ，你可以在 web 上试试在线版的 LXD 。作者简介：我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者，目前在加拿大魁北克蒙特利尔的家所在的Canonical 有限公司担任 LXD 的技术主管。via: https://www.stgraber.org/2016/03/30/lxd-2-0-image-management-512/作者：Stéphane Graber 译者：geekpi 校对：wxy本文由 LCTT 组织翻译，Linux中国 荣誉推出原文：https://www.stgraber.org/2016/03/30/lxd-2-0-image-management-512/
这是 LXD 2.0 系列介绍文章的第四篇。LXD 入门安装与配置你的第一个 LXD 容器资源控制镜像管理远程主机及容器迁移LXD 中的 DockerLXD 中的 LXD实时迁移LXD 和 JujuLXD 和 OpenStack调试，及给 LXD 做贡献因为 LXD 容器管理有很多命令，因此这篇文章会很长。 如果你想要快速地浏览这些相同的命令，你可以尝试下我们的在线演示！可用资源限制LXD 提供了各种资源限制。其中一些与容器本身相关，如内存配额、CPU 限制和 I/O 优先级。而另外一些则与特定设备相关，如 I/O 带宽或磁盘用量限制。与所有 LXD 配置一样，资源限制可以在容器运行时动态更改。某些可能无法启用，例如，如果设置的内存值小于当前内存用量，但 LXD 将会试着设置并且报告失败。所有的限制也可以通过配置文件继承，在这种情况下每个受影响的容器将受到该限制的约束。也就是说，如果在默认配置文件中设置 limits.memory=256MB，则使用默认配置文件（通常是全都使用）的每个容器的内存限制为 256MB。我们不支持资源限制池，将其中的限制由一组容器共享，因为我们没有什么好的方法通过现有的内核 API 实现这些功能。磁盘这或许是最需要和最明显的需求。只需设置容器文件系统的大小限制，并对容器强制执行。LXD 确实可以让你这样做！不幸的是，这比它听起来复杂得多。 Linux 没有基于路径的配额，而大多数文件系统只有基于用户和组的配额，这对容器没有什么用处。如果你正在使用 ZFS 或 btrfs 存储后端，这意味着现在 LXD 只能支持磁盘限制。也有可能为 LVM 实现此功能，但这取决于与它一起使用的文件系统，并且如果结合实时更新那会变得棘手起来，因为并不是所有的文件系统都允许在线增长，而几乎没有一个允许在线收缩。CPU当涉及到 CPU 的限制，我们支持 4 种不同的东西：只给我 X 个 CPU 核心在这种模式下，你让 LXD 为你选择一组核心，然后为更多的容器和 CPU 的上线/下线提供负载均衡。容器只看到这个数量的 CPU 核心。给我一组特定的 CPU 核心（例如，核心1、3 和 5）类似于第一种模式，但是不会做负载均衡，你会被限制在那些核心上，无论它们有多忙。给我你拥有的 20％ 处理能力在这种模式下，你可以看到所有的 CPU，但调度程序将限制你使用 20％ 的 CPU 时间，但这只有在负载状态才会这样！所以如果系统不忙，你的容器可以跑得很欢。而当其他的容器也开始使用 CPU 时，它会被限制用量。每测量 200ms，给我 50ms（并且不超过）此模式与上一个模式类似，你可以看到所有的 CPU，但这一次，无论系统可能是多么空闲，你只能使用你设置的极限时间下的尽可能多的 CPU 时间。在没有过量使用的系统上，这可使你可以非常整齐地分割 CPU，并确保这些容器的持续性能。另外还可以将前两个中的一个与最后两个之一相结合，即请求一组 CPU，然后进一步限制这些 CPU 的 CPU 时间。除此之外，我们还有一个通用的优先级调节方式，可以告诉调度器当你处于负载状态时，两个争夺资源的容器谁会取得胜利。内存内存听起来很简单，就是给我多少 MB 的内存！它绝对可以那么简单。 我们支持这种限制以及基于百分比的请求，比如给我 10％ 的主机内存！另外我们在上层支持一些额外的东西。 例如，你可以选择在每个容器上打开或者关闭 swap，如果打开，还可以设置优先级，以便你可以选择哪些容器先将内存交换到磁盘！内存限制默认是“hard”。 也就是说，当内存耗尽时，内核将会开始杀掉你的那些进程。或者，你可以将强制策略设置为“soft”，在这种情况下，只要没有别的进程的情况下，你将被允许使用尽可能多的内存。一旦别的进程想要这块内存，你将无法分配任何内存，直到你低于你的限制或者主机内存再次有空余。网络 I/O网络 I/O 可能是我们看起来最简单的限制，但是相信我，实现真的不简单！我们支持两种限制。 第一个是对网络接口的速率限制。你可以设置入口和出口的限制，或者只是设置“最大”限制然后应用到出口和入口。这个只支持“桥接”和“p2p”类型接口。第二种是全局网络 I/O 优先级，仅当你的网络接口趋于饱和的时候再使用。块 I/O我把最古怪的放在最后。对于用户看起来它可能简单，但有一些情况下，它的结果并不会和你的预期一样。我们在这里支持的基本上与我在网络 I/O 中描述的相同。你可以直接设置磁盘的读写 IO 的频率和速率，并且有一个全局的块 I/O 优先级，它会通知 I/O 调度程序更倾向哪个。古怪的是如何设置以及在哪里应用这些限制。不幸的是，我们用于实现这些功能的底层使用的是完整的块设备。这意味着我们不能为每个路径设置每个分区的 I/O 限制。这也意味着当使用可以支持多个块设备映射到指定的路径（带或者不带 RAID）的 ZFS 或 btrfs 时，我们并不知道这个路径是哪个块设备提供的。这意味着，完全有可能，实际上确实有可能，容器使用的多个磁盘挂载点（绑定挂载或直接挂载）可能来自于同一个物理磁盘。这就使限制变得很奇怪。为了使限制生效，LXD 具有猜测给定路径所对应块设备的逻辑，这其中包括询问 ZFS 和 btrfs 工具，甚至可以在发现一个文件系统中循环挂载的文件时递归地找出它们。这个逻辑虽然不完美，但通常会找到一组应该应用限制的块设备。LXD 接着记录并移动到下一个路径。当遍历完所有的路径，然后到了非常奇怪的部分。它会平均你为相应块设备设置的限制，然后应用这些。这意味着你将在容器中“平均”地获得正确的速度，但这也意味着你不能对来自同一个物理磁盘的“/fast”和一个“/slow”目录应用不同的速度限制。 LXD 允许你设置它，但最后，它会给你这两个值的平均值。它怎么工作？除了网络限制是通过较旧但是良好的“tc”实现的，上述大多数限制是通过 Linux 内核的 cgroup API 来实现的。LXD 在启动时会检测你在内核中启用了哪些 cgroup，并且将只应用你的内核支持的限制。如果你缺少一些 cgroup，守护进程会输出警告，接着你的 init 系统将会记录这些。在 Ubuntu 16.04 上，默认情况下除了内存交换审计外将会启用所有限制，内存交换审计需要你通过swapaccount = 1这个内核引导参数来启用。应用这些限制上述所有限制都能够直接或者用某个配置文件应用于容器。容器范围的限制可以使用：lxc config set CONTAINER KEY VALUE 或对于配置文件设置：lxc profile set PROFILE KEY VALUE 当指定特定设备时：lxc config device set CONTAINER DEVICE KEY VALUE 或对于配置文件设置：lxc profile device set PROFILE DEVICE KEY VALUE 有效配置键、设备类型和设备键的完整列表可以看这里。CPU要限制使用任意两个 CPU 核心可以这么做：lxc config set my-container limits.cpu 2 要指定特定的 CPU 核心，比如说第二和第四个：lxc config set my-container limits.cpu 1,3 更加复杂的情况还可以设置范围：lxc config set my-container limits.cpu 0-3,7-11 限制实时生效，你可以看下面的例子：stgraber@dakara:~$ lxc exec zerotier -- cat /proc/cpuinfo | grep ^proces processor : 0 processor : 1 processor : 2 processor : 3 stgraber@dakara:~$ lxc config set zerotier limits.cpu 2 stgraber@dakara:~$ lxc exec zerotier -- cat /proc/cpuinfo | grep ^proces processor : 0 processor : 1 注意，为了避免完全混淆用户空间，lxcfs 会重排 /proc/cpuinfo 中的条目，以便没有错误。就像 LXD 中的一切，这些设置也可以应用在配置文件中：stgraber@dakara:~$ lxc exec snappy -- cat /proc/cpuinfo | grep ^proces processor : 0 processor : 1 processor : 2 processor : 3 stgraber@dakara:~$ lxc profile set default limits.cpu 3 stgraber@dakara:~$ lxc exec snappy -- cat /proc/cpuinfo | grep ^proces processor : 0 processor : 1 processor : 2 要限制容器使用 10% 的 CPU 时间，要设置下 CPU allowance：lxc config set my-container limits.cpu.allowance 10% 或者给它一个固定的 CPU 时间切片：lxc config set my-container limits.cpu.allowance 25ms/200ms 最后，要将容器的 CPU 优先级调到最低：lxc config set my-container limits.cpu.priority 0 内存要直接应用内存限制运行下面的命令：lxc config set my-container limits.memory 256MB （支持的后缀是 KB、MB、GB、TB、PB、EB）要关闭容器的内存交换（默认启用）：lxc config set my-container limits.memory.swap false 告诉内核首先交换指定容器的内存：lxc config set my-container limits.memory.swap.priority 0 如果你不想要强制的内存限制：lxc config set my-container limits.memory.enforce soft 磁盘和块 I/O不像 CPU 和内存，磁盘和 I/O 限制是直接作用在实际的设备上的，因此你需要编辑原始设备或者屏蔽某个具体的设备。要设置磁盘限制（需要 btrfs 或者 ZFS）：lxc config device set my-container root size 20GB 比如：stgraber@dakara:~$ lxc exec zerotier -- df -h / Filesystem Size Used Avail Use% Mounted on encrypted/lxd/containers/zerotier 179G 542M 178G 1% / stgraber@dakara:~$ lxc config device set zerotier root size 20GB stgraber@dakara:~$ lxc exec zerotier -- df -h / Filesystem Size Used Avail Use% Mounted on encrypted/lxd/containers/zerotier 20G 542M 20G 3% / 要限制速度，你可以：lxc config device set my-container root limits.read 30MB lxc config device set my-container root.limits.write 10MB 或者限制 IO 频率：lxc config device set my-container root limits.read 20Iops lxc config device set my-container root limits.write 10Iops 最后你在一个过量使用的繁忙系统上，你或许想要：lxc config set my-container limits.disk.priority 10 将那个容器的 I/O 优先级调到最高。网络 I/O只要机制可用，网络 I/O 基本等同于块 I/O。比如：stgraber@dakara:~$ lxc exec zerotier -- wget http://speedtest.newark.linode.com/100MB-newark.bin -O /dev/null --2016-03-26 22:17:34-- http://speedtest.newark.linode.com/100MB-newark.bin Resolving speedtest.newark.linode.com (speedtest.newark.linode.com)... 50.116.57.237, 2600:3c03::4b Connecting to speedtest.newark.linode.com (speedtest.newark.linode.com)|50.116.57.237|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 104857600 (100M) [application/octet-stream] Saving to: '/dev/null' /dev/null 100%[===================>] 100.00M 58.7MB/s in 1.7s 2016-03-26 22:17:36 (58.7 MB/s) - '/dev/null' saved [104857600/104857600] stgraber@dakara:~$ lxc profile device set default eth0 limits.ingress 100Mbit stgraber@dakara:~$ lxc profile device set default eth0 limits.egress 100Mbit stgraber@dakara:~$ lxc exec zerotier -- wget http://speedtest.newark.linode.com/100MB-newark.bin -O /dev/null --2016-03-26 22:17:47-- http://speedtest.newark.linode.com/100MB-newark.bin Resolving speedtest.newark.linode.com (speedtest.newark.linode.com)... 50.116.57.237, 2600:3c03::4b Connecting to speedtest.newark.linode.com (speedtest.newark.linode.com)|50.116.57.237|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 104857600 (100M) [application/octet-stream] Saving to: '/dev/null' /dev/null 100%[===================>] 100.00M 11.4MB/s in 8.8s 2016-03-26 22:17:56 (11.4 MB/s) - '/dev/null' saved [104857600/104857600] 这就是如何将一个千兆网的连接速度限制到仅仅 100Mbit/s 的！和块 I/O 一样，你可以设置一个总体的网络优先级：lxc config set my-container limits.network.priority 5 获取当前资源使用率LXD API 可以导出目前容器资源使用情况的一点信息，你可以得到：内存：当前、峰值、目前内存交换和峰值内存交换磁盘：当前磁盘使用率网络：每个接口传输的字节和包数。另外如果你使用的是非常新的 LXD（在写这篇文章时的 git 版本），你还可以在lxc info中得到这些信息：stgraber@dakara:~$ lxc info zerotier Name: zerotier Architecture: x86_64 Created: 2016/02/20 20:01 UTC Status: Running Type: persistent Profiles: default Pid: 29258 Ips: eth0: inet 172.17.0.101 eth0: inet6 2607:f2c0:f00f:2700:216:3eff:feec:65a8 eth0: inet6 fe80::216:3eff:feec:65a8 lo: inet 127.0.0.1 lo: inet6 ::1 lxcbr0: inet 10.0.3.1 lxcbr0: inet6 fe80::f0bd:55ff:feee:97a2 zt0: inet 29.17.181.59 zt0: inet6 fd80:56c2:e21c:0:199:9379:e711:b3e1 zt0: inet6 fe80::79:e7ff:fe0d:5123 Resources: Processes: 33 Disk usage: root: 808.07MB Memory usage: Memory (current): 106.79MB Memory (peak): 195.51MB Swap (current): 124.00kB Swap (peak): 124.00kB Network usage: lxcbr0: Bytes received: 0 bytes Bytes sent: 570 bytes Packets received: 0 Packets sent: 0 zt0: Bytes received: 1.10MB Bytes sent: 806 bytes Packets received: 10957 Packets sent: 10957 eth0: Bytes received: 99.35MB Bytes sent: 5.88MB Packets received: 64481 Packets sent: 64481 lo: Bytes received: 9.57kB Bytes sent: 9.57kB Packets received: 81 Packets sent: 81 Snapshots: zerotier/blah (taken at 2016/03/08 23:55 UTC) (stateless) 总结LXD 团队花费了几个月的时间来迭代我们使用的这些限制的语言。 它是为了在保持强大和功能明确的基础上同时保持简单。实时地应用这些限制和通过配置文件继承，使其成为一种非常强大的工具，可以在不影响正在运行的服务的情况下实时管理服务器上的负载。更多信息LXD 的主站在： https://linuxcontainers.org/lxdLXD 的 GitHub 仓库： https://github.com/lxc/lxdLXD 的邮件列表：https://lists.linuxcontainers.orgLXD 的 IRC 频道：#lxcontainers on irc.freenode.net如果你不想在你的机器上安装LXD，你可以在线尝试下。作者简介：我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者，目前在加拿大魁北克蒙特利尔的家所在的Canonical 有限公司担任 LXD 的技术主管。via: https://www.stgraber.org/2016/03/26/lxd-2-0-resource-control-412/作者：Stéphane Graber 译者：geekpi 校对：wxy本文由 LCTT 组织翻译，Linux中国 荣誉推出
这是 LXD 2.0 系列介绍文章的第三篇博客。LXD 入门安装与配置你的第一个 LXD 容器资源控制镜像管理远程主机及容器迁移LXD 中的 DockerLXD 中的 LXD实时迁移LXD 和 JujuLXD 和 OpenStack调试，及给 LXD 做贡献由于在管理 LXD 容器时涉及到大量的命令，所以这篇文章的篇幅是比较长的，如果你更喜欢使用同样的命令来快速的一步步实现整个过程，你可以尝试我们的在线示例！创建并启动一个新的容器正如我在先前的文章中提到的一样，LXD 命令行客户端预配置了几个镜像源。Ubuntu 的所有发行版和架构平台全都提供了官方镜像，但是对于其他的发行版也有大量的非官方镜像，那些镜像都是由社区制作并且被 LXC 上游贡献者所维护。Ubuntu如果你想要支持最为完善的 Ubuntu 版本，你可以按照下面的去做：lxc launch ubuntu: 注意，这里意味着会随着 Ubuntu LTS 的发布而变化。因此，如果用于脚本，你需要指明你具体安装的版本（参见下面）。Ubuntu14.04 LTS得到最新更新的、已经测试过的、稳定的 Ubuntu 14.04 LTS 镜像，你可以简单的执行：lxc launch ubuntu:14.04 在该模式下，会指定一个随机的容器名。如果你更喜欢指定一个你自己的名字，你可以这样做：lxc launch ubuntu:14.04 c1 如果你想要指定一个特定的体系架构（非主流平台），比如 32 位 Intel 镜像，你可以这样做：lxc launch ubuntu:14.04/i386 c2 当前的 Ubuntu 开发版本上面使用的“ubuntu:”远程仓库只会给你提供官方的并经过测试的 Ubuntu 镜像。但是如果你想要未经测试过的日常构建版本，开发版可能对你来说是合适的，你需要使用“ubuntu-daily:”远程仓库。lxc launch ubuntu-daily:devel c3 在这个例子中，将会自动选中最新的 Ubuntu 开发版本。你也可以更加精确，比如你可以使用代号名：lxc launch ubuntu-daily:xenial c4 最新的Alpine LinuxAlpine 镜像可以在“Images:”远程仓库中找到，通过如下命令执行：lxc launch images:alpine/3.3/amd64 c5 其他全部的 Ubuntu 镜像列表可以这样获得：lxc image list ubuntu: lxc image list ubuntu-daily: 全部的非官方镜像：lxc image list images: 某个给定的原程仓库的全部别名（易记名称）可以这样获得（比如对于“ubuntu:”远程仓库）：lxc image alias list ubuntu: 创建但不启动一个容器如果你想创建一个容器或者一批容器，但是你不想马上启动它们，你可以使用lxc init替换掉lxc launch。所有的选项都是相同的，唯一的不同就是它并不会在你创建完成之后启动容器。lxc init ubuntu: 关于你的容器的信息列出所有的容器要列出你的所有容器，你可以这样这做：lxc list 有大量的选项供你选择来改变被显示出来的列。在一个拥有大量容器的系统上，默认显示的列可能会有点慢（因为必须获取容器中的网络信息），你可以这样做来避免这种情况：lxc list --fast 上面的命令显示了另外一套列的组合，这个组合在服务器端需要处理的信息更少。你也可以基于名字或者属性来过滤掉一些东西：stgraber@dakara:~$ lxc list security.privileged=true +------+---------+---------------------+-----------------------------------------------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+---------+---------------------+-----------------------------------------------+------------+-----------+ | suse | RUNNING | 172.17.0.105 (eth0) | 2607:f2c0:f00f:2700:216:3eff:fef2:aff4 (eth0) | PERSISTENT | 0 | +------+---------+---------------------+-----------------------------------------------+------------+-----------+ 在这个例子中，只有那些特权容器（禁用了用户命名空间）才会被列出来。stgraber@dakara:~$ lxc list --fast alpine +-------------+---------+--------------+----------------------+----------+------------+ | NAME | STATE | ARCHITECTURE | CREATED AT | PROFILES | TYPE | +-------------+---------+--------------+----------------------+----------+------------+ | alpine | RUNNING | x86_64 | 2016/03/20 02:11 UTC | default | PERSISTENT | +-------------+---------+--------------+----------------------+----------+------------+ | alpine-edge | RUNNING | x86_64 | 2016/03/20 02:19 UTC | default | PERSISTENT | +-------------+---------+--------------+----------------------+----------+------------+ 在这个例子中，只有在名字中带有“alpine”的容器才会被列出来（也支持复杂的正则表达式）。获取容器的详细信息由于 list 命令显然不能以一种友好的可读方式显示容器的所有信息，因此你可以使用如下方式来查询单个容器的信息：lxc info <container> 例如：stgraber@dakara:~$ lxc info zerotier Name: zerotier Architecture: x86_64 Created: 2016/02/20 20:01 UTC Status: Running Type: persistent Profiles: default Pid: 31715 Processes: 32 Ips: eth0: inet 172.17.0.101 eth0: inet6 2607:f2c0:f00f:2700:216:3eff:feec:65a8 eth0: inet6 fe80::216:3eff:feec:65a8 lo: inet 127.0.0.1 lo: inet6 ::1 lxcbr0: inet 10.0.3.1 lxcbr0: inet6 fe80::c0a4:ceff:fe52:4d51 zt0: inet 29.17.181.59 zt0: inet6 fd80:56c2:e21c:0:199:9379:e711:b3e1 zt0: inet6 fe80::79:e7ff:fe0d:5123 Snapshots: zerotier/blah (taken at 2016/03/08 23:55 UTC) (stateless) 生命周期管理命令这些命令对于任何容器或者虚拟机管理器或许都是最普通的命令，但是它们仍然需要讲到。所有的这些命令在批量操作时都能接受多个容器名。启动启动一个容器就向下面一样简单：lxc start <container> 停止停止一个容器可以这样来完成：lxc stop <container> 如果容器不合作（即没有对发出的 SIGPWR 信号产生回应），这时候，你可以使用下面的方式强制执行：lxc stop <container> --force 重启通过下面的命令来重启一个容器：lxc restart <container> 如果容器不合作（即没有对发出的 SIGINT 信号产生回应），你可以使用下面的方式强制执行：lxc restart <container> --force 暂停你也可以“暂停”一个容器，在这种模式下，所有的容器任务将会被发送相同的 SIGSTOP 信号，这也意味着它们将仍然是可见的，并且仍然会占用内存，但是它们不会从调度程序中得到任何的 CPU 时间片。如果你有一个很占用 CPU 的容器，而这个容器需要一点时间来启动，但是你却并不会经常用到它。这时候，你可以先启动它，然后将它暂停，并在你需要它的时候再启动它。lxc pause <container> 删除最后，如果你不需要这个容器了，你可以用下面的命令删除它：lxc delete <container> 注意，如果容器还处于运行状态时你将必须使用“-force”。容器的配置LXD 拥有大量的容器配置设定，包括资源限制，容器启动控制以及对各种设备是否允许访问的配置选项。完整的清单因为太长所以并没有在本文中列出，但是，你可以从[这里]获取它。就设备而言，LXD 当前支持下面列出的这些设备类型：磁盘 既可以是一块物理磁盘，也可以只是一个被挂挂载到容器上的分区，还可以是一个来自主机的绑定挂载路径。网络接口卡 一块网卡。它可以是一块桥接的虚拟网卡，或者是一块点对点设备，还可以是一块以太局域网设备或者一块已经被连接到容器的真实物理接口。unix 块设备 一个 UNIX 块设备，比如 /dev/sdaunix 字符设备 一个 UNIX 字符设备，比如 /dev/kvmnone 这种特殊类型被用来隐藏那种可以通过配置文件被继承的设备。配置 profile 文件所有可用的配置文件列表可以这样获取：lxc profile list 为了看到给定配置文件的内容，最简单的方式是这样做：lxc profile show <profile> 你可能想要改变文件里面的内容，可以这样做：lxc profile edit <profile> 你可以使用如下命令来改变应用到给定容器的配置文件列表：lxc profile apply <container> <profile1>,<profile2>,<profile3>,... 本地配置有些配置是某个容器特定的，你并不想将它放到配置文件中，你可直接对容器设置它们：lxc config edit <container> 上面的命令做的和“profile edit”命令是一样。如果不想在文本编辑器中打开整个文件的内容，你也可以像这样修改单独的配置：lxc config set <container> <key> <value> 或者添加设备，例如：lxc config device add my-container kvm unix-char path=/dev/kvm 上面的命令将会为名为“my-container”的容器设置一个 /dev/kvm 项。对一个配置文件使用lxc profile set和lxc profile device add命令也能实现上面的功能。读取配置你可以使用如下命令来读取容器的本地配置：lxc config show <container> 或者得到已经被展开了的配置（包含了所有的配置值）：lxc config show --expanded <container> 例如：stgraber@dakara:~$ lxc config show --expanded zerotier name: zerotier profiles: - default config: security.nesting: "true" user.a: b volatile.base_image: a49d26ce5808075f5175bf31f5cb90561f5023dcd408da8ac5e834096d46b2d8 volatile.eth0.hwaddr: 00:16:3e:ec:65:a8 volatile.last_state.idmap: '[{"Isuid":true,"Isgid":false,"Hostid":100000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":100000,"Nsid":0,"Maprange":65536}]' devices: eth0: name: eth0 nictype: macvlan parent: eth0 type: nic limits.ingress: 10Mbit limits.egress: 10Mbit root: path: / size: 30GB type: disk tun: path: /dev/net/tun type: unix-char ephemeral: false 这样做可以很方便的检查有哪些配置属性被应用到了给定的容器。实时配置更新注意，除非在文档中已经被明确指出，否则所有的配置值和设备项的设置都会对容器实时发生影响。这意味着在不重启正在运行的容器的情况下，你可以添加和移除某些设备或者修改安全配置文件。获得一个 shellLXD 允许你直接在容器中执行任务。最常用的做法是在容器中得到一个 shell 或者执行一些管理员任务。和 SSH 相比，这样做的好处是你不需要容器是网络可达的，也不需要任何软件和特定的配置。执行环境与 LXD 在容器内执行命令的方式相比，有一点是不同的，那就是 shell 并不是在容器中运行。这也意味着容器不知道使用的是什么样的 shell，以及设置了什么样的环境变量和你的家目录在哪里。通过 LXD 来执行命令总是使用最小的路径环境变量设置，并且 HOME 环境变量必定为 /root，以容器的超级用户身份来执行（即 uid 为 0，gid 为 0）。其他的环境变量可以通过命令行来设置，或者在“environment.”配置中设置成永久环境变量。执行命令在容器中获得一个 shell 可以简单的执行下列命令得到：lxc exec <container> bash 当然，这样做的前提是容器内已经安装了 bash。更复杂的命令要求使用分隔符来合理分隔参数。lxc exec <container> -- ls -lh / 如果想要设置或者重写变量，你可以使用“-env”参数，例如：stgraber@dakara:~$ lxc exec zerotier --env mykey=myvalue env | grep mykey mykey=myvalue 管理文件因为 LXD 可以直接访问容器的文件系统，因此，它可以直接读取和写入容器中的任意文件。当我们需要提取日志文件或者与容器传递文件时，这个特性是很有用的。从容器中取回一个文件想要从容器中获得一个文件，简单的执行下列命令：lxc file pull <container>/<path> <dest> 例如：stgraber@dakara:~$ lxc file pull zerotier/etc/hosts hosts 或者将它读取到标准输出：stgraber@dakara:~$ lxc file pull zerotier/etc/hosts - 127.0.0.1 localhost # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts 向容器发送一个文件发送以另一种简单的方式完成：lxc file push <container>/<path> 直接编辑一个文件编辑是一个方便的功能，其实就是简单的提取一个给定的路径，在你的默认文本编辑器中打开它，在你关闭编辑器时会自动将编辑的内容保存到容器。lxc file edit <container>/<path> 快照管理LXD 允许你对容器执行快照功能并恢复它。快照包括了容器在某一时刻的完整状态（如果-stateful被使用的话将会包括运行状态），这也意味着所有的容器配置，容器设备和容器文件系统也会被保存。创建一个快照你可以使用下面的命令来执行快照功能：lxc snapshot <container> 命令执行完成之后将会生成名为snapX（X 为一个自动增长的数）的记录。除此之外，你还可以使用如下命令命名你的快照：lxc snapshot <container> <snapshot name> 列出所有的快照一个容器的所有快照的数量可以使用lxc list来得到，但是具体的快照列表只能执行lxc info命令才能看到。lxc info <container> 恢复快照为了恢复快照，你可以简单的执行下面的命令：lxc restore <container> <snapshot name> 给快照重命名可以使用如下命令来给快照重命名：lxc move <container>/<snapshot name> <container>/<new snapshot name> 从快照中创建一个新的容器你可以使用快照来创建一个新的容器，而这个新的容器除了一些可变的信息将会被重置之外（例如 MAC 地址）其余所有信息都将和快照完全相同。lxc copy /<snapshot name> <destination container> 删除一个快照最后，你可以执行下面的命令来删除一个快照：lxc delete <container>/<snapshot name> 克隆并重命名得到一个纯净的发行版镜像总是让人感到愉悦，但是，有时候你想要安装一系列的软件到你的容器中，这时，你需要配置它然后将它分支成多个其他的容器。复制一个容器为了复制一个容器并有效的将它克隆到一个新的容器中，你可以执行下面的命令：lxc copy <destination container> 目标容器在所有方面将会完全和源容器等同。除了新的容器没有任何源容器的快照以及一些可变值将会被重置之外（例如 MAC 地址）。移动一个快照LXD 允许你复制容器并在主机之间移动它。但是，关于这一点将在后面的文章中介绍。现在，“move”命令将会被用作给容器重命名。lxc move <old name> <new name> 唯一的要求就是当容器应该被停止，容器内的任何事情都会被保存成它本来的样子，包括可变化的信息（类似 MAC 地址等）。结论这篇如此长的文章介绍了大多数你可能会在日常操作中使用到的命令。很显然，这些如此之多的命令都会有不少选项，可以让你的命令更加有效率，或者可以让你指定你的 LXD 容器的某个具体方面。最好的学习这些命令的方式就是深入学习它们的帮助文档（ -help）。更多信息LXD 的主要网站是：https://linuxcontainers.org/lxdGithub 上的开发动态： https://github.com/lxc/lxd邮件列表支持：https://lists.linuxcontainers.orgIRC 支持： #lxcontainers on irc.freenode.net如果你不想或者不能在你的机器上安装 LXD，你可以试试在线版本!作者简介：我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者，目前在加拿大魁北克蒙特利尔的家所在的Canonical 有限公司担任 LXD 的技术主管。来自于：https://www.stgraber.org/2016/03/19/lxd-2-0-your-first-lxd-container-312/ 作者：Stéphane Graber 译者：kylepeng93 校对：wxy本文由 LCTT 原创翻译，Linux中国 荣誉推出
这是 LXD 2.0 系列介绍文章的第二篇。LXD 入门安装与配置你的第一个 LXD 容器资源控制镜像管理远程主机及容器迁移LXD 中的 DockerLXD 中的 LXD实时迁移LXD 和 JujuLXD 和 OpenStack调试，及给 LXD 做贡献安装篇有很多种办法可以获得 LXD。我们推荐你配合最新版的 LXC 和 Linux 内核使用 LXD，这样就可以享受到它的全部特性。需要注意的是，我们现在也在慢慢的降低对旧版本 Linux 发布版的支持。Ubuntu 标准版所有新发布的 LXD 都会在发布几分钟后上传到 Ubuntu 开发版的安装源里。这个安装包然后就会作为 Ubuntu 用户的其他安装包源的种子。如果使用 Ubuntu 16.04，可以直接安装：sudo apt install lxd 如果运行的是 Ubuntu 14.04，则可以这样安装：sudo apt -t trusty-backports install lxd Ubuntu Core使用 Ubuntu Core 稳定版的用户可以使用下面的命令安装 LXD：sudo snappy install lxd.stgraber Ubuntu 官方 PPA使用其他 Ubuntu 发布版 —— 比如 Ubuntu 15.10 —— 的用户可以添加下面的 PPA（Personal Package Archive）来安装：sudo apt-add-repository ppa:ubuntu-lxc/stable sudo apt update sudo apt dist-upgrade sudo apt install lxd GentooGentoo 已经有了最新的 LXD 包，你可以直接安装：sudo emerge --ask lxd 使用源代码安装如果你曾经编译过 Go 语言的项目，那么从源代码编译 LXD 并不是十分困难。然而注意，你需要 LXC 的开发头文件。为了运行 LXD， 你的发布版需也要使用比较新的内核（最起码是 3.13）、比较新的 LXC （1.1.4 或更高版本）、LXCFS 以及支持用户子 uid/gid 分配的 shadow 文件。从源代码编译 LXD 的最新教程可以在上游 README里找到。Ubuntu 上的网络配置Ubuntu 的安装包会很方便的给你提供一个“lxdbr0”网桥。这个网桥默认是没有配置过的，只提供通过 HTTP 代理的 IPv6 的本地连接。要配置这个网桥并添加 IPv4 、 IPv6 子网，你可以运行下面的命令：sudo dpkg-reconfigure -p medium lxd 或者直接通过 LXD 初始化命令一步一步的配置：sudo lxd init 存储后端LXD 提供了几种存储后端。在开始使用 LXD 之前，你应该决定将要使用的后端，因为我们不支持在后端之间迁移已经生成的容器。各个后端特性比较表可以在这里找到。ZFS我们的推荐是 ZFS， 因为它能支持 LXD 的全部特性，同时提供最快和最可靠的容器体验。它包括了以容器为单位的磁盘配额、即时快照和恢复、优化后的迁移（发送/接收），以及快速从镜像创建容器的能力。它同时也被认为要比 btrfs 更成熟。要和 LXD 一起使用 ZFS ，你需要首先在你的系统上安装 ZFS。如果你是用的是 Ubuntu 16.04 ， 你只需要简单的使用命令安装：sudo apt install zfsutils-linux 在 Ubuntu 15.10 上你可以这样安装：sudo apt install zfsutils-linux zfs-dkms 如果是更旧的版本，你需要从 zfsonlinux PPA 安装：sudo apt-add-repository ppa:zfs-native/stable sudo apt update sudo apt install ubuntu-zfs 配置 LXD 只需要执行下面的命令：sudo lxd init 这条命令接下来会向你提问一些 ZFS 的配置细节，然后为你配置好 ZFS。btrfs如果 ZFS 不可用，那么 btrfs 可以提供相同级别的集成，但不能正确地报告容器内的磁盘使用情况（虽然配额仍然可用）。btrfs 同时拥有很好的嵌套属性，而这是 ZFS 所不具有的。也就是说如果你计划在 LXD 中再使用 LXD，那么 btrfs 就很值得你考虑。使用 btrfs 的话，LXD 不需要进行任何的配置，你只需要保证 /var/lib/lxd 保存在 btrfs 文件系统中，然后 LXD 就会自动为你使用 btrfs 了。LVM如果 ZFS 和 btrfs 都不是你想要的，你还可以考虑使用 LVM 以获得部分特性。 LXD 会以自动精简配置的方式使用 LVM，为每个镜像和容器创建 LV，如果需要的话也会使用 LVM 的快照功能。要配置 LXD 使用 LVM，需要创建一个 LVM 卷组，然后运行：lxc config set storage.lvm_vg_name "THE-NAME-OF-YOUR-VG" 默认情况下 LXD 使用 ext4 作为全部逻辑卷的文件系统。如果你喜欢的话可以改成 XFS：lxc config set storage.lvm_fstype xfs 简单目录如果上面全部方案你都不打算使用，LXD 依然能在不使用任何高级特性情况下工作。它会为每个容器创建一个目录，然后在创建每个容器时解压缩镜像的压缩包，并在容器拷贝和快照时进行一次完整的文件系统拷贝。除了磁盘配额以外的特性都是支持的，但是很浪费磁盘空间，并且非常慢。如果你没有其他选择，这还是可以工作的，但是你还是需要认真的考虑一下上面的几个替代方案。配置篇LXD 守护进程的完整配置项列表可以在这里找到。网络配置默认情况下 LXD 不会监听网络。和它通信的唯一办法是通过 /var/lib/lxd/unix.socket 使用本地 unix 套接字进行通信。要让 LXD 监听网络，下面有两个有用的命令：lxc config set core.https_address [::] lxc config set core.trust_password some-secret-string 第一条命令将 LXD 绑定到 IPv6 地址 “::”，也就是监听机器的所有 IPv6 地址。你可以显式的使用一个特定的 IPv4 或者 IPv6 地址替代默认地址，如果你想绑定某个 TCP 端口（默认是 8443）的话可以在地址后面添加端口号即可。第二条命令设置了密码，用于让远程客户端把自己添加到 LXD 可信证书中心。如果已经给主机设置了密码，当添加 LXD 主机时会提示输入密码，LXD 守护进程会保存他们的客户端证书以确保客户端是可信的，这样就不需要再次输入密码（可以随时设置和取消）。你也可以选择不设置密码，而是人工验证每个新客户端是否可信——让每个客户端发送“client.crt”（来自于 ~/.config/lxc）文件，然后把它添加到你自己的可信证书中心：lxc config trust add client.crt 代理配置大多数情况下，你会想让 LXD 守护进程从远程服务器上获取镜像。如果你处在一个必须通过 HTTP(s) 代理链接外网的环境下，你需要对 LXD 做一些配置，或保证已在守护进程的环境中设置正确的 PROXY 环境变量。lxc config set core.proxy_http http://squid01.internal:3128 lxc config set core.proxy_https http://squid01.internal:3128 lxc config set core.proxy_ignore_hosts image-server.local 以上代码使所有 LXD 发起的数据传输都使用 squid01.internal HTTP 代理，但与在 image-server.local 的服务器的数据传输则是例外。镜像管理LXD 使用动态镜像缓存。当从远程镜像创建容器的时候，它会自动把镜像下载到本地镜像商店，同时标志为已缓存并记录来源。几天后（默认 10 天）如果某个镜像没有被使用过，那么它就会自动地被删除。每隔几小时（默认是 6 小时）LXD 还会检查一下这个镜像是否有新版本，然后更新镜像的本地拷贝。所有这些都可以通过下面的配置选项进行配置：lxc config set images.remote_cache_expiry 5 lxc config set images.auto_update_interval 24 lxc config set images.auto_update_cached false 这些命令让 LXD 修改了它的默认属性，缓存期替换为 5 天，更新间隔为 24 小时，而且只更新那些标记为自动更新（–auto-update）的镜像（lxc 镜像拷贝被标记为 –auto-update）而不是 LXD 自动缓存的镜像。总结到这里为止，你就应该有了一个可以工作的、最新版的 LXD，现在你可以开始用 LXD 了，或者等待我们的下一篇博文，我们会在其中介绍如何创建第一个容器以及使用 LXD 命令行工具操作容器。额外信息LXD 的主站在: https://linuxcontainers.org/lxdLXD 的 GitHub 仓库: https://github.com/lxc/lxdLXD 的邮件列表: https://lists.linuxcontainers.orgLXD 的 IRC 频道: #lxcontainers on irc.freenode.net如果你不想或者不能在你的机器上安装 LXD ，你可以试试在线版的 LXD。作者简介：我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者，目前在加拿大魁北克蒙特利尔的家所在的Canonical 有限公司担任 LXD 的技术主管。via: https://www.stgraber.org/2016/03/15/lxd-2-0-installing-and-configuring-lxd-212/作者：Stéphane Graber 译者：ezio 校对：PurlingNayuki本文由 LCTT 原创翻译，Linux中国 荣誉推出
这是 LXD 2.0 系列介绍文章的第一篇。LXD 入门安装与配置你的第一个 LXD 容器资源控制镜像管理远程主机及容器迁移LXD 中的 DockerLXD 中的 LXD实时迁移LXD 和 JujuLXD 和 OpenStack调试，及给 LXD 做贡献关于 LXD 几个常见问题什么是 LXD ?简单地说， LXD 就是一个提供了 REST API 的 LXC 容器管理器。LXD 最主要的目标就是使用 Linux 容器而不是硬件虚拟化向用户提供一种接近虚拟机的使用体验。LXD 和 Docker/Rkt 又有什么关系呢 ?这是一个最常被问起的问题，现在就让我们直接指出其中的不同吧。LXD 聚焦于系统容器，通常也被称为架构容器。这就是说 LXD 容器实际上如在裸机或虚拟机上运行一般运行了一个完整的 Linux 操作系统。这些容器一般基于一个干净的发布镜像并会长时间运行。传统的配置管理工具和部署工具可以如在虚拟机、云实例和物理机器上一样与 LXD 一起使用。相对的， Docker 关注于短期的、无状态的、最小化的容器，这些容器通常并不会升级或者重新配置，而是作为一个整体被替换掉。这就使得 Docker 及类似项目更像是一种软件发布机制，而不是一个机器管理工具。这两种模型并不是完全互斥的。你完全可以使用 LXD 为你的用户提供一个完整的 Linux 系统，然后他们可以在 LXD 内安装 Docker 来运行他们想要的软件。为什么要用 LXD?我们已经持续开发并改进 LXC 好几年了。 LXC 成功的实现了它的目标，它提供了一系列很棒的用于创建和管理容器的底层工具和库。然而这些底层工具的使用界面对用户并不是很友好。使用它们需要用户有很多的基础知识以理解它们的工作方式和目的。同时，向后兼容旧的容器和部署策略也使得 LXC 无法默认使用一些安全特性，这导致用户需要进行更多人工操作来实现本可以自动完成的工作。我们把 LXD 作为解决这些缺陷的一个很好的机会。作为一个长时间运行的守护进程， LXD 可以绕开 LXC 的许多限制，比如动态资源限制、无法进行容器迁移和高效的在线迁移；同时，它也为创造新的默认体验提供了机会：默认开启安全特性，对用户更加友好。LXD 的主要组件LXD 是由几个主要组件构成的，这些组件都出现在 LXD 目录结构、命令行客户端和 API 结构体里。容器LXD 中的容器包括以下及部分：根文件系统（rootfs）配置选项列表，包括资源限制、环境、安全选项等等设备：包括磁盘、unix 字符/块设备、网络接口一组继承而来的容器配置文件属性（容器架构、暂时的还是持久的、容器名）运行时状态（当用 CRIU 来中断/恢复时）快照容器快照和容器是一回事，只不过快照是不可修改的，只能被重命名，销毁或者用来恢复系统，但是无论如何都不能被修改。值得注意的是，因为我们允许用户保存容器的运行时状态，这就有效的为我们提供了“有状态”的快照的功能。这就是说我们可以使用快照回滚容器的状态，包括快照当时的 CPU 和内存状态。镜像LXD 是基于镜像实现的，所有的 LXD 容器都是来自于镜像。容器镜像通常是一些纯净的 Linux 发行版的镜像，类似于你们在虚拟机和云实例上使用的镜像。所以可以「发布」一个容器：使用容器制作一个镜像并在本地或者远程 LXD 主机上使用。镜像通常使用全部或部分 sha256 哈希码来区分。因为输入长长的哈希码对用户来说不方便，所以镜像可以使用几个自身的属性来区分，这就使得用户在镜像商店里方便搜索镜像。也可以使用别名来一对一地将一个用户好记的名字映射到某个镜像的哈希码上。LXD 安装时已经配置好了三个远程镜像服务器（参见下面的远程一节）：“ubuntu”：提供稳定版的 Ubuntu 镜像“ubuntu-daily”：提供 Ubuntu 的每日构建镜像“images”： 社区维护的镜像服务器，提供一系列的其它 Linux 发布版，使用的是上游 LXC 的模板LXD 守护进程会从镜像上次被使用开始自动缓存远程镜像一段时间（默认是 10 天），超过时限后这些镜像才会失效。此外， LXD 还会自动更新远程镜像（除非指明不更新），所以本地的镜像会一直是最新版的。配置配置文件是一种在一个地方定义容器配置和容器设备，然后将其应用到一系列容器的方法。一个容器可以被应用多个配置文件。当构建最终容器配置时（即通常的扩展配置），这些配置文件都会按照他们定义顺序被应用到容器上，当有重名的配置键或设备时，新的会覆盖掉旧的。然后本地容器设置会在这些基础上应用，覆盖所有来自配置文件的选项。LXD 自带两种预配置的配置文件：“default”配置是自动应用在所有容器之上，除非用户提供了一系列替代的配置文件。目前这个配置文件只做一件事，为容器定义 eth0 网络设备。“docker”配置是一个允许你在容器里运行 Docker 容器的配置文件。它会要求 LXD 加载一些需要的内核模块以支持容器嵌套并创建一些设备。远程如我之前提到的， LXD 是一个基于网络的守护进程。附带的命令行客户端可以与多个远程 LXD 服务器、镜像服务器通信。默认情况下，我们的命令行客户端会与下面几个预定义的远程服务器通信：local：默认的远程服务器，使用 UNIX socket 和本地的 LXD 守护进程通信ubuntu：Ubuntu 镜像服务器，提供稳定版的 Ubuntu 镜像ubuntu-daily：Ubuntu 镜像服务器，提供 Ubuntu 的每日构建版images：images.linuxcontainers.org 的镜像服务器所有这些远程服务器的组合都可以在命令行客户端里使用。你也可以添加任意数量的远程 LXD 主机，并配置它们监听网络。匿名的开放镜像服务器，或者通过认证可以管理远程容器的镜像服务器，都可以添加进来。正是这种远程机制使得与远程镜像服务器交互及在主机间复制、移动容器成为可能。安全性我们设计 LXD 时的一个核心要求，就是在不修改现代 Linux 发行版的前提下，使容器尽可能的安全。LXD 通过使用 LXC 库实现的主要安全特性有：内核名字空间。尤其是用户名字空间，它让容器和系统剩余部分完全分离。LXD 默认使用用户名字空间（和 LXC 相反），并允许用户在需要的时候以容器为单位关闭（将容器标为“特权的”）。Seccomp 系统调用。用来隔离潜在危险的系统调用。AppArmor。对 mount、socket、ptrace 和文件访问提供额外的限制。特别是限制跨容器通信。Capabilities。阻止容器加载内核模块，修改主机系统时间，等等。CGroups。限制资源使用，防止针对主机的 DoS 攻击。为了对用户友好，LXD 构建了一个新的配置语言把大部分的这些特性都抽象封装起来，而不是如 LXC 一般直接将这些特性暴露出来。举了例子，一个用户可以告诉 LXD 把主机设备放进容器而不需要手动检查他们的主/次设备号来手动更新 CGroup 策略。和 LXD 本身通信是基于使用 TLS 1.2 保护的链路，只允许使用有限的几个被允许的密钥算法。当和那些经过系统证书认证之外的主机通信时， LXD 会提示用户验证主机的远程指纹（SSH 方式），然后把指纹缓存起来以供以后使用。REST 接口LXD 的工作都是通过 REST 接口实现的。在客户端和守护进程之间并没有其他的通讯渠道。REST 接口可以通过本地的 unix socket 访问，这只需要经过用户组认证，或者经过 HTTP 套接字使用客户端认证进行通信。REST 接口的结构能够和上文所说的不同的组件匹配，是一种简单、直观的使用方法。当需要一种复杂的通信机制时， LXD 将会进行 websocket 协商完成剩余的通信工作。这主要用于交互式终端会话、容器迁移和事件通知。LXD 2.0 附带了 1.0 版的稳定 API。虽然我们在 1.0 版 API 添加了额外的特性，但是这不会在 1.0 版 API 端点里破坏向后兼容性，因为我们会声明额外的 API 扩展使得客户端可以找到新的接口。容器规模化虽然 LXD 提供了一个很好的命令行客户端，但是这个客户端并不能管理多个主机上大量的容器。在这种使用情况下，我们可以使用 OpenStack 的 nova-lxd 插件，它可以使 OpenStack 像使用虚拟机一样使用 LXD 容器。这就允许在大量的主机上部署大量的 LXD 容器，然后使用 OpenStack 的 API 来管理网络、存储以及负载均衡。额外信息LXD 的主站在: https://linuxcontainers.org/lxdLXD 的 GitHub 仓库: https://github.com/lxc/lxdLXD 的邮件列表: https://lists.linuxcontainers.orgLXD 的 IRC 频道: #lxcontainers on irc.freenode.net如果你不想或者不能在你的机器上安装 LXD ，你可以在 web 上试试在线版的 LXD 。作者简介：我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者，目前在加拿大魁北克蒙特利尔的家所在的Canonical 有限公司担任 LXD 的技术主管。via: https://www.stgraber.org/2016/03/11/lxd-2-0-introduction-to-lxd-112/作者：Stéphane Graber 译者：ezio 校对：PurlingNayuki本文由 LCTT 原创翻译，Linux中国 荣誉推出
使用“容器”来保证主机环境的安全性，这个概念早在十年前就已经存在（例如 FreeBSD 的 jail 虚拟化技术），但是直到最近，随着部署云架构需求越来越多，像 LXC 和 Docker 这种 Linux 下的容器才成为被关注的焦点。当然，由于主流厂商（云服务商如亚马逊主推 AWS，微软主推 Azure；发行版如红帽、Ubuntu等）组成的强大靠山，Docker 已经被放在媒体的聚光灯下面，其实，Docker 里面所谓的“容器”技术是由 LXC 提供的。你只是一个普通的 Linux 用户，那 Docker/LXC 能为你带来什么好处呢？容器可以将你的应用在不同的 Linux 发行版之间迁移。想像一下这个场景：你正在用的发行版是 Debian，你喜欢它的稳定性，同时你又想玩一款最新的 Ubuntu 游戏，你不需要在电脑上装双系统然后重启进入 Ubuntu，也不需要在 Debian 上跑一个耗资源的 Ubuntu 虚拟机，你只需要简单地生成一个 Ubuntu 容器就够了。抛开 Docker 的好处不谈，让我们聊一下 LXC 容器的好处：我可以使用 libvirt 提供的接口来管理 LXC，这些接口和 Docker 没有任何关系。如果你有使用基于 libvirt 库的管理工具（例如 virt-manager 和 virsh），你就可以使用它们来管理 LXC 容器。在这篇教程中，我只介绍标准 LXC 容器管理工具的命令行操作，来教你如何在 Ubuntu 下创建和管理 LXC 容器。Ubuntu 下安装 LXC使用下面的命令安装 LXC 在用户态的工具：$ sudo apt-get install lxc 然后检查当前内核是否支持 LXC。如果所有结果都是“enable”，说明内核支持：$ lxc-checkconfig 安装完 LXC 工具后，就能看到 LXC 自动创建了一块桥接网卡（lxcbr0，可以在 /etc/lxc/default.conf 中设置）。当你创建了 LXC 容器后，它的网口会自动链接到这个桥接网卡上，然后这个容器就能和外部世界通信了。创建 LXC 容器为了在指定环境下（比如 Debian Wheezy 64位）创建 LXC 容器，你需要一个相应的 LXC 模板。幸运的是 LXC 提供的工具集成了一整套现成的 LXC 模板，你可以在 /usr/share/lxc/templates 目录下找到它们。 $ ls /usr/share/lxc/templates 一个 LXC 模板实质上就是一个脚本，用于创建指定环境下的容器。当你创建 LXC 容器时，你需要用到它们。比如你要新建 Ubuntu 容器，使用下面的命令即可：$ sudo lxc-create -n <container-name> -t ubuntu 默认情况下，这个命令会创建一个最小的 Ubuntu 环境，版本号与你的宿主机一致，我这边是“活泼的蝾螈”（版本号是13.10），64位。当然你也可以创建任何你喜欢的版本，只要在命令里面加一个版本参数即可。举个例子，创建 Ubuntu 14.10 的容器：$ sudo lxc-create -n <container-name> -t ubuntu -- --release utopic 这个命令就会下载安装指定环境下的软件包，创建新容器。整个过程需要几分钟时间，与容器的类型有关，所以，你可能需要耐心等待。下载安装完所有软件包后，LXC 容器镜像就创建完成了，你可以看到默认的登录界面。容器被放到 /var/lib/lxc/<容器名> 这个目录下，容器的根文件系统放在 /var/lib/lxc/<容器名>/rootfs 目录下。创建过程中下载的软件包保存在 /var/cache/lxc 目录下面，当你想另外建一个一样的容器时，可以省去很多下载时间。用下面的命令看看主机上所有的 LXC 容器：$ sudo lxc-ls --fancy NAME STATE IPV4 IPV6 AUTOSTART ------------------------------------ test-lxc STOPPED - - NO 使用下面的命令启动容器。参数“-d”将容器作为后台进程打开。如果没有指定这个参数，你可以在控制台界面上直接把容器的运行程序关闭（LCTT译注：Ctrl+C组合键）。$ sudo lxc-start -n <container-name> -d 打开容器后，看看状态：$ sudo lxc-ls --fancy NAME STATE IPV4 IPV6 AUTOSTART ----------------------------------------- lxc RUNNING 10.0.3.55 - NO 容器状态是“运行中”，容器 IP 是10.0.3.55。你也可以看到容器的网络接口（比如我这里是 vethJ06SFL）自动与 LXC 内部网桥（lxcbr0）连上了：$ brctl show lxcbr0 管理 LXC 容器我们已经学习了怎么创建和启动 LXC 容器，现在来看看怎么玩一个正在运行着的容器。第一步：打开容器控制台：$ sudo lxc-console -n <container-name> 使用“Crtl+a q”组合键退出控制台。停止、删除容器：$ sudo lxc-stop -n <container-name> $ sudo lxc-destroy -n <container-name> 复制容器，用下面的命令：$ sudo lxc-stop -n <container-name> $ sudo lxc-clone -o <container-name> -n <new-container-name> 常见问题这个小节主要介绍你们在使用 LXC 过程中碰到过的问题。创建 LXC 容器时遇到下面的错误：$ sudo lxc-create -n test-lxc -t ubuntulxc-create: symbol lookup error: /usr/lib/x86_64-linux-gnu/liblxc.so.1: undefined symbol: cgmanager_get_pid_cgroup_abs_sync 错误的原因是你运行了最新的 LXC，但是它所依赖的 libcgmanager 版本较老，两者不兼容。升级下 libcmanager 即可解决问题：$ sudo apt-get install libcgmanager0 via: http://xmodulo.com/lxc-containers-ubuntu.html作者：Dan Nanni 译者：bazz2 校对：wxy本文由 LCTT 原创翻译，Linux中国 荣誉推出
lmctfy (Let Me Contain That For you，发音是lem-kut-fee)是谷歌Google开发的容器栈，可以为Linux应用提供容器（container）。这些容器可以让一台机器上的不同应用使用相互隔离的资源，以独占的方式运行在同一台机器上。这些应用也可以拥有容器，因此能够创建和管理属于他们自己的子容器。这项项目旨在提供一组以用户的意图为原点的高级API，来实现对容器概念的抽象化。这些创建的容器自身也通过继承也可以拥有了自己的容器、也能够被其他的用户程序所管理。Lmctfy是为某些特定的场景（配置环境）设计、实现的，所以可能不能在所有场景（配置环境）中正常运作。我们的目标是为更多的场景（配置环境）提供更多的支持，所以你可以为这项项目贡献你的补丁或是在邮件列表中发送邮件，这样我们可以朝着既定的路线图前进。lmctfy 内包含一个C++库和一个CLI（命令行界面程序）最新进展lmctfy 还是一个在beta阶段的应用，目前仍在主要开发中。最新的版本是0.1。她目前只支持CPU和内存资源的隔离。点击查看我们的路线图来了解各部分的开发情况，点击查看贡献。从此开始这一节描述如何编译你的CLI，运行所有的UI测试，和初始化机器的细节。 CLI这节提供了一些CLI操作的例子，C++ 库描述了这个库的使用详情。依赖编译本程序需要使用make和g++4.7。 lmcfy使用了C++11，所以需要支持这项功能的编译器。我们在 Ubuntu 12.04+ 上测试过编译。如果有为其他环境的编译提供支持的补丁，我们很高兴而且希望这越多越好。lmctfy 依赖下列几个库，需要这些库存在于你的计算机系统里。Protocol BuffersgflagsRE2编译CLI编译lmctfy的CLI：make -j <线程数> lmctfyCLI程序会生成在 bin/lmctfy/cli/lmctfy编译C++库编译lmctfy的库：make -j <线程数> liblmctfy.a库文件会生成在 bin/liblmctfy.a.运行测试编译和运行所有的UI测试：make -j <线程数> check初始化lmctfy已经在 Ubuntu 12.04+ 上的 3.3 和 3.8 内核上测试过。 lmctfy在一台机器的所有容器都是运行它的时候运转得最好，所以不建议让她运行在LXC或者其他container系统上（尽管在某些特殊得配置下这能够跑起来）。为了运行lmctfy，我们必须首先初始化计算机。这只需要运行一次就可以，而且一般是在计算机第一次启动时候就完成了。当cgroup的hierarchies已经挂载了，接下来通常一个空的配置会可以让lmctfy自动监测到目前的挂载。lmctfy init ""如果cgroup的hierarchies没有被挂载，那么必须指明这些资源，这样lmctfy才可以挂载他们。目前版本需要以下cgroup的hierarchies资源cpu，cpuset，cpuacct，memory和freezer。 cpu和cpuacct 是目前唯一可以被共享挂载的，其他的必须被单独地挂载。具体配置说明可以查看lmctfy.proto中的InitSpec节。以下的例子是一个挂载了/dev/cgroup中的所有hierarachies的配置文件：lmctfy init " cgroup_mount:{ mount_path:'/dev/cgroup/cpu' hierarchy:CGROUP_CPU hierarchy:CGROUP_CPUACCT } cgroup_mount:{ mount_path:'/dev/cgroup/cpuset' hierarchy:CGROUP_CPUSET } cgroup_mount:{ mount_path:'/dev/cgroup/freezer' hierarchy:CGROUP_FREEZER } cgroup_mount:{ mount_path:'/dev/cgroup/memory' hierarchy:CGROUP_MEMORY }"这样，机器就可以被lmctfy使用、进行容器的操作。容器的命名容器的命名系统简化了文件系统的路径，因为以后只需要一系列容器的继承（容器的容器、子容器、子子容器）就可以了♪───Ｏ（≧∇≦）Ｏ──── ♪。容器名称允许的字符集：英文字母＋阿拉伯数字 ([a-zA-Z0-9]+)下划线 (\_)横县 (-)英文句号 (.)绝对路径是从容器（比如是/sys/subcont）的根目录(/)开始计算的。容器的名字也可以是相对的（比如subcont）。一般地（除非特殊情况说明），都是沿用一般的文件路径方式。例子 / : 容器的根目录 /sys : "sys" 容器 /sys/sub : "sub" 容器，"sys"容器的子容器 . : 当前的容器 ./ : 当前的容器 .. : 当前的容器的父容器 sub : 当前的容器的"sub" 子容器 ./sub : 当前的容器的"sub" 子容器 /sub : "sub" 容器 ../sibling : 当前的父容器的“sibling”子容器CLI创建创建一个容器：lmctfy create <名称> <参数>更完整的细节参见lmctfy.proto例子 (创建一个内存限制在100MB的容器)：lmctfy create memory\_only "memory:{limit:100000000}"销毁销毁一个容器：lmctfy destroy<名称>列表从根目录递归显示当前机器的所有容器：lmctfy list containers -r /你也可以只列出当前的子容器：lmctfy list containers运行在一台容器中运行命令：lmctfy run <名称> <命令行>例子：lmctfy run test "echo hello world"lmctfy run /test/sub bashlmctfy run -n /test "echo hello from a daemon"其他键入lmctfy help查看全部的命令和文档C++ Library此库包含了::containers::lmctfy::ContainerApi 用来创建、获取、销毁、监测::containers::lmctfy::Container类型的对象，并且被独立的容器相互交流。具体的lmctfy C++库的文档可以查看头文件lmctfy.h（你是认真的吗(￣▽￣)）。路线图lmctfy项目通过两个层（CL1、CL2）来实现一个容器栈。CL1围绕着驱动进程，并执行CL2制定的容器策略。CL1会为更高层创建和维护容器的抽象。她应当是唯一直接和内核交流以维护容器的层。 CL2发展和设定容器策略，她使用CL1来执行策略和操控容器。比如，CL2（后台进程）实现了一个策略：所有容器的CPU和内存使用总和不可以超过现提供的CPU和内存资源（以防止对内存资源的过度使用）。为了执行这条策略，她（CL2）会使用CL1（library／CLI）来创建带这条内存限制规则的容器。另一条对应的策略可能包括了允许过度使用X％的机器资源或者对不同资源的多重层次控制。lmcfty项目现在提供了CL1组件，CL2还没有实现。CL1现在只提供高性能CPU和内存隔离。在我们的路线图中我们还需要实现以下几项：磁盘IO隔离: 这部分几乎完成了，但是我们还缺少控制器和资源处理器。网络隔离: 这部分和cgroup实现还在计划中。命名空间支援: 给所有命名空间支援并且整合到相关的资源中。根文件系统支援: 识别并建立根文件系统。磁盘镜像: 可以导入和导出容器的根文件系统的镜像。支持暂停／继续: 使用继承的freezer。还原点恢复: 可以建立还原点并恢复到不同机器的容器中。CL2最基础的CL2 应当有一个容器策略来保证在机器不允许超载运行情况下的资源合理分配。我们的目标是CL2最终实现提供不同层次的服务。在这个框架下一些层次可以比其他的获得更多好的服务。监控和统计支持。管理功能和功能检查。服务的质量保证和执行。内核支持lmctfy 最初的设计和实现是在一个自定义的内核上（一个原生linux内核外加一些列自选的补丁）上。由此，一些特性在这些内核补丁上跑得最理想。但是lmctfy应该在没有他们得情况下正常运行。她应当监测可用得内核支援并且与之适应。我们已经在原生的 Ubuntu 的 3.3 和 3.8 系列内核上测试过。如果你发现在其他版本内核下的问题，请汇报。一些相关的内核补丁：CPU 延时: 这个补丁为cpu hierarchy增加了cpu.lat的cgroup 文件。她限制了cgroup能预测的CPU唤醒延时时间。CPU 柱状图统计: 这个补丁为cpuacct hierarchy增加了cpuacct.histogram cgroup 文件。她为CPU计划行为提供了多种柱状图方案。OOM 管理: 一系列的补丁，用于在内存用尽的情况下执行优先权。贡献对项目感到兴趣了？看看我们的路线图，看你是不是由很多想贡献的方向呢？ 从此开始，你应该可以运行我们的程序。如果无法运行，请让我们知道，这样我们可以改进这份指南。邮件列表本项目的邮件列表是lmctfy@googlegroups.com。本邮件列表用来发布、讨论、一般性支持。原文: https://github.com/google/lmctfy/本文由LCTT 原创翻译，Linux中国 荣誉推出译者：Chilledheart 校对：wxy