标签 LXD 下的文章

Ubuntu Core 是什么?

Ubuntu Core 是完全基于 snap 包构建,并且完全事务化的 Ubuntu 版本。

该系统大部分是只读的,所有已安装的应用全部来自 snap 包,完全使用事务化更新。这意味着不管在系统更新还是安装软件的时候遇到问题,整个系统都可以回退到之前的状态并且记录这个错误。

最新版是在 2016 年 11 月发布的 Ubuntu Core 16。

注意,Ubuntu Core 限制只能够安装 snap 包(而非 “传统” 软件包),并且有相当数量的 snap 包在当前环境下不能正常运行,或者需要人工干预(创建用户和用户组等)才能正常运行。随着新版的 snapd 和 “core” snap 包发布,Ubuntu Core 每周都会得到改进。

环境需求

就 LXD 而言,Ubuntu Core 仅仅相当于另一个 Linux 发行版。也就是说,snapd 需要挂载无特权的 FUSE 和 AppArmor 命名空间以及软件栈,像下面这样:

  • 一个新版的使用 Ubuntu 官方内核的系统
  • 一个新版的 LXD

创建一个 Ubuntu Core 容器

当前 Ubuntu Core 镜像发布在社区的镜像服务器。你可以像这样启动一个新的容器:

stgraber@dakara:~$ lxc launch images:ubuntu-core/16 ubuntu-core
Creating ubuntu-core
Starting ubuntu-core

这个容器启动需要一点点时间,它会先执行第一阶段的加载程序,加载程序会确定使用哪一个镜像(镜像是只读的),并且在系统上设置一个可读层,你不要在这一阶段中断容器执行,这个时候什么都没有,所以执行 lxc exec 将会出错。

几秒钟之后,执行 lxc list 将会展示容器的 IP 地址,这表明已经启动了 Ubuntu Core:

stgraber@dakara:~$ lxc list
+-------------+---------+----------------------+----------------------------------------------+------------+-----------+
|     NAME    |  STATE  |          IPV4        |                      IPV6                    |    TYPE    | SNAPSHOTS |
+-------------+---------+----------------------+----------------------------------------------+------------+-----------+
| ubuntu-core | RUNNING | 10.90.151.104 (eth0) | 2001:470:b368:b2b5:216:3eff:fee1:296f (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+----------------------------------------------+------------+-----------+

之后你就可以像使用其他的交互一样和这个容器进行交互:

stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap list
Name       Version     Rev  Developer  Notes
core       16.04.1     394  canonical  -
pc         16.04-0.8   9    canonical  -
pc-kernel  4.4.0-45-4  37   canonical  -
root@ubuntu-core:~#

更新容器

如果你一直关注着 Ubuntu Core 的开发,你应该知道上面的版本已经很老了。这是因为被用作 Ubuntu LXD 镜像的代码每隔几个月才会更新。Ubuntu Core 系统在重启时会检查更新并进行自动更新(更新失败会回退)。

如果你想现在强制更新,你可以这样做:

stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap refresh
pc-kernel (stable) 4.4.0-53-1 from 'canonical' upgraded
core (stable) 16.04.1 from 'canonical' upgraded
root@ubuntu-core:~# snap version
snap 2.17
snapd 2.17
series 16
root@ubuntu-core:~#

然后重启一下 Ubuntu Core 系统,然后看看 snapd 的版本。

root@ubuntu-core:~# reboot
root@ubuntu-core:~# 

stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap version
snap 2.21
snapd 2.21
series 16
root@ubuntu-core:~#

你也可以像下面这样查看所有 snapd 的历史记录:

stgraber@dakara:~$ lxc exec ubuntu-core snap changes
ID  Status  Spawn                 Ready                 Summary
1   Done    2017-01-31T05:14:38Z  2017-01-31T05:14:44Z  Initialize system state
2   Done    2017-01-31T05:14:40Z  2017-01-31T05:14:45Z  Initialize device
3   Done    2017-01-31T05:21:30Z  2017-01-31T05:22:45Z  Refresh all snaps in the system

安装 Snap 软件包

以一个最简单的例子开始,经典的 Hello World:

stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap install hello-world
hello-world 6.3 from 'canonical' installed
root@ubuntu-core:~# hello-world
Hello World!

接下来让我们看一些更有用的:

stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap install nextcloud
nextcloud 11.0.1snap2 from 'nextcloud' installed

之后通过 HTTP 访问你的容器就可以看到刚才部署的 Nextcloud 实例。

如果你想直接通过 git 测试最新版 LXD,你可以这样做:

stgraber@dakara:~$ lxc config set ubuntu-core security.nesting true
stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap install lxd --edge
lxd (edge) git-c6006fb from 'canonical' installed
root@ubuntu-core:~# lxd init
Name of the storage backend to use (dir or zfs) [default=dir]: 

We detected that you are running inside an unprivileged container.
This means that unless you manually configured your host otherwise,
you will not have enough uid and gid to allocate to your containers.

LXD can re-use your container's own allocation to avoid the problem.
Doing so makes your nested containers slightly less safe as they could
in theory attack their parent container and gain more privileges than
they otherwise would.

Would you like to have your containers share their parent's allocation (yes/no) [default=yes]? 
Would you like LXD to be available over the network (yes/no) [default=no]? 
Would you like stale cached images to be updated automatically (yes/no) [default=yes]? 
Would you like to create a new network bridge (yes/no) [default=yes]? 
What should the new bridge be called [default=lxdbr0]? 
What IPv4 address should be used (CIDR subnet notation, “auto” or “none”) [default=auto]? 
What IPv6 address should be used (CIDR subnet notation, “auto” or “none”) [default=auto]? 
LXD has been successfully configured.

已经设置过的容器不能回退版本,但是可以在 Ubuntu Core 16 中运行另一个 Ubuntu Core 16 容器:

root@ubuntu-core:~# lxc launch images:ubuntu-core/16 nested-core
Creating nested-core
Starting nested-core 
root@ubuntu-core:~# lxc list
+-------------+---------+---------------------+-----------------------------------------------+------------+-----------+
|    NAME     |  STATE  |         IPV4        |                       IPV6                    |    TYPE    | SNAPSHOTS |
+-------------+---------+---------------------+-----------------------------------------------+------------+-----------+
| nested-core | RUNNING | 10.71.135.21 (eth0) | fd42:2861:5aad:3842:216:3eff:feaf:e6bd (eth0) | PERSISTENT | 0         |
+-------------+---------+---------------------+-----------------------------------------------+------------+-----------+

写在最后

如果你只是想试用一下 Ubuntu Core,这是一个不错的方法。对于 snap 包开发者来说,这也是一个不错的工具来测试你的 snap 包能否在不同的环境下正常运行。

如果你希望你的系统总是最新的,并且整体可复制,Ubuntu Core 是一个很不错的方案,不过这也会带来一些相应的限制,所以可能不太适合你。

最后是一个警告,对于测试来说,这些镜像是足够的,但是当前并没有被正式的支持。在不久的将来,官方的 Ubuntu server 可以完整的支持 Ubuntu Core LXD 镜像。

附录


来自: https://insights.ubuntu.com/2017/02/27/ubuntu-core-in-lxd-containers/

作者:Stéphane Graber 译者:aiwhj 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

最近,我对 lxc exec 进行了几个改进。如果你不知道它的话我介绍一下,lxc execLXD 的客户端工具,使用 LXD 客户端 api 与 LXD 守护程序通信,并执行用户想要执行的各种程序,以下是你可以使用的一个例子:

我们的主要目标之一就是使 lxc execssh 类似,因为它是交互式或非交互式远程运行命令的标准。这使得 把 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 在程序中无法处理。程序可以做的唯一的事情就是去死,像现在这样……像这个例子……马上(你明白了了吧……)。但是程序可以处理很多其他信号 SIGTERMSIGHUP',当然也可以处理SIGUSR1SIGUSR2。因此,当你发送可以被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 已经支持多种存储驱动。用户可以在 zfs、btrfs、lvm 或纯目录存储池之间进行选择,但他们只能使用单个存储池。一个被频繁被提到的需求是不仅支持单个存储池,还支持多个存储池。这样,用户可以维护一个由 SSD 支持的 zfs 存储池用于 I/O 密集型容器,另一个简单的基于目录的存储池用于其他容器。幸运的是,现在这是可能的,因为 LXD 在几个版本后有了自己的存储管理 API。

创建存储池

新安装 LXD 没有定义任何存储池。如果你运行 lxd init ,LXD 将提供为你创建一个存储池。由 lxd init 创建的存储池将是创建容器的默认存储池。

asciicast

创建更多的存储池

我们的客户端工具使得创建额外的存储池变得非常简单。为了创建和管理新的存储池,你可以使用 lxc storage 命令。所以如果你想在块设备 /dev/sdb 上创建一个额外的 btrfs 存储池,你只需使用 lxc storage create my-btrfs btrfs source=/dev/sdb。让我们来看看:

asciicast

在默认存储池上创建容器

如果你从全新安装的 LXD 开始,并通过 lxd init 创建了一个存储池,LXD 将使用此池作为默认存储池。这意味着如果你执行 lxc launch images:ubuntu/xenial xen1,LXD 将为此存储池上的容器的根文件系统创建一个存储卷。在示例中,我们使用 my-first-zfs-pool 作为默认存储池。

asciicast

在特定存储池上创建容器

但是你也可以通过传递 -s 参数来告诉 lxc launchlxc init 在特定存储池上创建一个容器。例如,如果要在 my-btrfs 存储池上创建一个新的容器,你可以执行 lxc launch images:ubuntu/xenial xen-on-my-btrfs -s my-btrfs

asciicast

创建自定义存储卷

如果你其中一个容器需要额外的空间存储额外的数据,那么新的存储 API 将允许你创建可以连接到容器的存储卷。只需要 lxc storage volume create my-btrfs my-custom-volume

asciicast

连接自定义卷到容器中

当然,这个功能是有用的,因为存储 API 让你把这些存储卷连接到容器。要将存储卷连接到容器,可以使用 lxc storage volume attach my-btrfs my-custom-volume xen1 data /opt/my/data

asciicast

在容器之间共享自定义存储卷

默认情况下,LXD 将使连接的存储卷由其所连接的容器写入。这意味着它会将存储卷的所有权更改为容器的 id 映射。但存储卷也可以同时连接到多个容器。这对于在多个容器之间共享数据是非常好的。但是,这有一些限制。为了将存储卷连接到多个容器,它们必须共享相同的 id 映射。让我们创建一个额外的具有一个隔离的 id 映射的容器 xen-isolated。这意味着它的 id 映射在这个 LXD 实例中将是唯一的,因此没有其他容器具有相同的id映射。将相同的存储卷 my-custom-volume 连接到此容器现在将会失败:

asciicast

但是我们让 xen-isolatedxen1 有相同的映射,并把它重命名为 xen2 来反映这个变化。现在我们可以将 my-custom-volume 连接到 xen1xen2 而不会有问题:

asciicast

总结

存储 API 是 LXD 非常强大的补充。它提供了一组基本功能,有助于在大规模使用容器时处理各种问题。这个简短的介绍希望给你一个印象,你可以做什么。将来会有更多介绍。

本篇文章最初在 Brauner 的博客中发布。


via: https://insights.ubuntu.com/2017/07/12/storage-management-in-lxd-2-15/

作者:Christian Brauner 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

介绍

当 LXD 2.0 随着 Ubuntu 16.04 一起发布时,LXD 联网就简单了。要么你可以使用 lxd init 来配置,为你的容器自己提供一个 “lxdbr0” 网桥,要么使用一个已存在的物理接口。

虽然这确实有效,但是有点混乱,因为大部分的桥接配置发生在 Ubuntu 打包的 LXD 之外。那些脚本只能支持一个桥接,并且没有通过 API 暴露,这使得远程配置有点痛苦。

直到 LXD 2.3,LXD 终于发展了自己的网络管理 API ,并有相应的命令行工具。这篇文章试图来简述这些新的功能。

基础联网

在初始情况下,LXD 2.3 没有定义任何网络。lxd init 会为你设置一个,并且默认情况下将所有新的容器连接到它,但是让我们亲手尝试看下究竟发生了些什么。

要创建一个新的带有随机 IPv4 和 IP6 子网,并启用 NAT 的网络,只需要运行:

stgraber@castiana:~$ lxc network create testbr0
Network testbr0 created

你可以如下查看它的配置:

stgraber@castiana:~$ lxc network show testbr0
name: testbr0
config:
 ipv4.address: 10.150.19.1/24
 ipv4.nat: "true"
 ipv6.address: fd42:474b:622d:259d::1/64
 ipv6.nat: "true"
managed: true
type: bridge
usedby: []

如果你不想要那些自动配置的子网,你可以这么做:

stgraber@castiana:~$ lxc network create testbr0 ipv6.address=none ipv4.address=10.0.3.1/24 ipv4.nat=true
Network testbr0 created

那就会这样:

stgraber@castiana:~$ lxc network show testbr0
name: testbr0
config:
 ipv4.address: 10.0.3.1/24
 ipv4.nat: "true"
 ipv6.address: none
managed: true
type: bridge
usedby: []

如果你的容器没有使用它,那么创建的网络对你也没什么用。要将你新创建的网络连接到所有容器,你可以这么做:

stgraber@castiana:~$ lxc network attach-profile testbr0 default eth0

要将一个网络连接到一个已存在的容器中,你可以这么做:

stgraber@castiana:~$ lxc network attach my-container default eth0

现在,假设你已经在机器中安装了 openvswitch,并且要将这个网桥转换成 OVS 网桥,只需更改为正确的驱动:

stgraber@castiana:~$ lxc network set testbr0 bridge.driver openvswitch

如果你想要一次性做一系列修改。lxc network edit 可以让你在编辑器中交互编辑网络配置。

静态租约及端口安全

使用 LXD 管理 DHCP 服务器的一个好处是可以使得管理 DHCP 租约很简单。你所需要的是一个容器特定的网卡设备以及正确的属性设置。

root@yak:~# lxc init ubuntu:16.04 c1
Creating c1
root@yak:~# lxc network attach testbr0 c1 eth0
root@yak:~# lxc config device set c1 eth0 ipv4.address 10.0.3.123
root@yak:~# lxc start c1
root@yak:~# lxc list c1
+------+---------+-------------------+------+------------+-----------+
| NAME |  STATE  |        IPV4       | IPV6 |    TYPE    | SNAPSHOTS |
+------+---------+-------------------+------+------------+-----------+
|  c1  | RUNNING | 10.0.3.123 (eth0) |      | PERSISTENT | 0         |
+------+---------+-------------------+------+------------+-----------+

IPv6 也是相同的方法,但是换成 ipv6.address 属性。

相似地,如果你想要阻止你的容器更改它的 MAC 地址或者为其他 MAC 地址转发流量(比如嵌套),你可以用下面的命令启用端口安全:

root@yak:~# lxc config device set c1 eth0 security.mac_filtering true

DNS

LXD 在网桥上运行 DNS 服务器。除了设置网桥的 DNS 域( dns.domain 网络属性)之外,还支持 3 种不同的操作模式(dns.mode):

  • managed :每个容器都会有一条 DNS 记录,匹配它的名字以及已知的 IP 地址。容器无法通过 DHCP 改变这条记录。
  • dynamic :允许容器通过 DHCP 在 DNS 中自行注册。因此,在 DHCP 协商期间容器发送的任何主机名最终都出现在 DNS 中。
  • none : 针对那些没有任何本地 DNS 记录的递归 DNS 服务器。

默认的模式是 managed,并且典型的是最安全以及最方便的,因为它为容器提供了 DNS 记录,但是不允许它们通过 DHCP 发送虚假主机名嗅探其他的记录。

使用隧道

除了这些,LXD 还支持使用 GRE 或者 VXLAN 隧道连接到其他主机。

LXD 网络可以连接任何数量的隧道,从而轻松地创建跨多个主机的网络。这对于开发、测试和演示非常有用,生产环境通常更喜欢使用 VLAN 进行分割。

所以说,你想在主机 “edfu” 上有一个运行 IPv4 和 IPv6 的基础 “testbr0” 网络,并希望在主机 “djanet” 上使用它来生成容器。最简单的方法是使用组播 VXLAN 隧道。这种类型的隧道仅在两个主机位于同一物理段上时才起作用。

root@edfu:~# lxc network create testbr0 tunnel.lan.protocol=vxlan
Network testbr0 created
root@edfu:~# lxc network attach-profile testbr0 default eth0

它在主机 “edfu” 上定义了一个 “testbr0” 桥接,并为其他主机能加入它设置了一个组播 VXLAN。在这个设置中,“edfu” 为这个网络扮演了一个路由器角色,提供 DHCP、DNS 等等,其他主机只是通过隧道转发流量。

root@djanet:~# lxc network create testbr0 ipv4.address=none ipv6.address=none tunnel.lan.protocol=vxlan
Network testbr0 created
root@djanet:~# lxc network attach-profile testbr0 default eth0

现在你可以在任何一台主机上启动容器,并看到它们从同一个地址池中获取 IP,通过隧道直接互相通讯。

如先前所述,这个使用了组播,它通常在跨越路由器时无法很好工作。在这些情况下,你可以用单播模式使用 VXLAN 或者 GRE 隧道。

要使用 GRE 加入另一台主机,首先配置服务主机:

root@edfu:~# lxc network set testbr0 tunnel.nuturo.protocol gre
root@edfu:~# lxc network set testbr0 tunnel.nuturo.local 172.17.16.2
root@edfu:~# lxc network set testbr0 tunnel.nuturo.remote 172.17.16.9

接着是“客户端”主机:

root@nuturo:~# lxc network create testbr0 ipv4.address=none ipv6.address=none tunnel.edfu.protocol=gre tunnel.edfu.local=172.17.16.9 tunnel.edfu.remote=172.17.16.2
Network testbr0 created
root@nuturo:~# lxc network attach-profile testbr0 default eth0

如果你像使用 VXLAN,只要这么做:

root@edfu:~# lxc network set testbr0 tunnel.edfu.id 10
root@edfu:~# lxc network set testbr0 tunnel.edfu.protocol vxlan

还有:

root@nuturo:~# lxc network set testbr0 tunnel.edfu.id 10
root@nuturo:~# lxc network set testbr0 tunnel.edfu.protocol vxlan

这里需要隧道 id 以防与已经配置的多播 VXLAN 隧道冲突。

这就是如何使用最近的 LXD 简化跨主机联网了!

总结

LXD 使得从简单的单主机网络到数千个容器的非常复杂的跨主机网络的定义变得更加容易。它也使为一些容器定义一个新网络或者给容器添加第二个设备,并连接到隔离的私有网络变得很简单。

虽然这篇文章介绍了支持的大部分功能,但仍有一些可以微调 LXD 网络体验的窍门。可以在这里找到完整的列表:https://github.com/lxc/lxd/blob/master/doc/configuration.md

额外信息


via: https://www.stgraber.org/2016/10/27/network-management-with-lxd-2-3/

作者:Stéphane Graber 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

介绍

终于要结束了!这个大约一年前开始的这系列文章的最后一篇博文。

  1. LXD 入门
  2. 安装与配置
  3. 你的第一个 LXD 容器
  4. 资源控制
  5. 镜像管理
  6. 远程主机及容器迁移
  7. LXD 中的 Docker
  8. LXD 中的 LXD
  9. 实时迁移
  10. LXD 和 Juju
  11. LXD 和 OpenStack
  12. 调试,及给 LXD 做贡献

如果你从一开始就关注了这个系列,你应该已经使用了 LXD 相当长的时间了,并且非常熟悉它的日常操作和功能。

但如果出现问题怎么办?你可以做什么来自己跟踪问题?如果你不能,你应该记录什么信息,以便上游可以跟踪问题?

如果你想自己解决问题或通过实现你需要的功能来帮助改善LXD怎么办?如何构建,测试和贡献 LXD 代码库?

调试 LXD 并填写 bug 报告

LXD 日志文件

/var/log/lxd/lxd.log

这是 LXD 日志的主文件。为了避免它快速充满你的磁盘,默认只会记录 INFOWARNING 或者 ERROR 级别的日志。你可以在 LXD 守护进程中使用 –debug 改变其行为。

/var/log/lxd/CONTAINER/lxc.conf

每当你启动容器时,此文件将更新为传递给 LXC 的配置。

这里会展示容器将如何配置,包括其所有的设备、绑定挂载等等。

/var/log/lxd/CONTAINER/forkexec.log

这个文件包含 LXC 命令执行失败时产生的错误。这个情况是非常罕见的,因为 LXD 通常会在发生之前处理大多数错误。

/var/log/lxd/CONTAINER/forkstart.log

这个文件包含 LXC 在启动容器时的错误信息。含 LXC 命令执行失败时产生的错误。

CRIU 日志 (对于实时迁移)

如果使用 CRIU 进行容器实时迁移或实时快照,则每次生成 CRIU 转储或恢复转储时都会记录额外的日志文件。

这些日志也可以在 /var/log/lxd/CONTAINER/ 中找到,并且有时间戳,以便你可以找到与你最近的操作所匹配的那些日志。它们包含 CRIU 转储和恢复的所有内容的详细记录,并且比典型的迁移/快照错误消息更容器理解。

LXD 调试消息

如上所述,你可以使用 -debug 选项将守护进程切换为执行调试日志记录。另一种方法是连接到守护进程的事件接口,它将显示所有日志条目,而不管配置的日志级别(即使是远程工作)。

举例说,对于 lxc init ubuntu:16.04 xen 来说,

lxd.log 会是这样:

INFO[02-24|18:14:09] Starting container action=start created=2017-02-24T23:11:45+0000 ephemeral=false name=xen stateful=false used=1970-01-01T00:00:00+0000
INFO[02-24|18:14:10] Started container action=start created=2017-02-24T23:11:45+0000 ephemeral=false name=xen stateful=false used=1970-01-01T00:00:00+0000

lxc monitor –type=logging 会是:

metadata:
  context: {}
  level: dbug
  message: 'New events listener: 9b725741-ffe7-4bfc-8d3e-fe620fc6e00a'
timestamp: 2017-02-24T18:14:01.025989062-05:00
type: logging

metadata:
  context:
    ip: '@'
    method: GET
    url: /1.0
  level: dbug
  message: handling
timestamp: 2017-02-24T18:14:09.341283344-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
  level: dbug
  message: StorageCoreInit
timestamp: 2017-02-24T18:14:09.341536477-05:00
type: logging

metadata:
  context:
    ip: '@'
    method: GET
    url: /1.0/containers/xen
  level: dbug
  message: handling
timestamp: 2017-02-24T18:14:09.347709394-05:00
type: logging

metadata:
  context:
    ip: '@'
    method: PUT
    url: /1.0/containers/xen/state
  level: dbug
  message: handling
timestamp: 2017-02-24T18:14:09.357046302-05:00
type: logging

metadata:
  context: {}
  level: dbug
  message: 'New task operation: 2e2cf904-c4c4-4693-881f-57897d602ad3'
timestamp: 2017-02-24T18:14:09.358387853-05:00
type: logging

metadata:
  context: {}
  level: dbug
  message: 'Started task operation: 2e2cf904-c4c4-4693-881f-57897d602ad3'
timestamp: 2017-02-24T18:14:09.358578599-05:00
type: logging

metadata:
  context:
    ip: '@'
    method: GET
    url: /1.0/operations/2e2cf904-c4c4-4693-881f-57897d602ad3/wait
  level: dbug
  message: handling
timestamp: 2017-02-24T18:14:09.366213106-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
  level: dbug
  message: StoragePoolInit
timestamp: 2017-02-24T18:14:09.369636451-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
  level: dbug
  message: StoragePoolCheck
timestamp: 2017-02-24T18:14:09.369771164-05:00
type: logging

metadata:
  context:
    container: xen
    driver: storage/zfs
  level: dbug
  message: ContainerMount
timestamp: 2017-02-24T18:14:09.424696767-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
    name: xen
  level: dbug
  message: ContainerUmount
timestamp: 2017-02-24T18:14:09.432723719-05:00
type: logging

metadata:
  context:
    container: xen
    driver: storage/zfs
  level: dbug
  message: ContainerMount
timestamp: 2017-02-24T18:14:09.721067917-05:00
type: logging

metadata:
  context:
    action: start
    created: 2017-02-24 23:11:45 +0000 UTC
    ephemeral: "false"
    name: xen
    stateful: "false"
    used: 1970-01-01 00:00:00 +0000 UTC
  level: info
  message: Starting container
timestamp: 2017-02-24T18:14:09.749808518-05:00
type: logging

metadata:
  context:
    ip: '@'
    method: GET
    url: /1.0
  level: dbug
  message: handling
timestamp: 2017-02-24T18:14:09.792551375-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
  level: dbug
  message: StorageCoreInit
timestamp: 2017-02-24T18:14:09.792961032-05:00
type: logging

metadata:
  context:
    ip: '@'
    method: GET
    url: /internal/containers/23/onstart
  level: dbug
  message: handling
timestamp: 2017-02-24T18:14:09.800803501-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
  level: dbug
  message: StoragePoolInit
timestamp: 2017-02-24T18:14:09.803190248-05:00
type: logging

metadata:
  context:
    driver: storage/zfs
  level: dbug
  message: StoragePoolCheck
timestamp: 2017-02-24T18:14:09.803251188-05:00
type: logging

metadata:
  context:
    container: xen
    driver: storage/zfs
  level: dbug
  message: ContainerMount
timestamp: 2017-02-24T18:14:09.803306055-05:00
type: logging

metadata:
  context: {}
  level: dbug
  message: 'Scheduler: container xen started: re-balancing'
timestamp: 2017-02-24T18:14:09.965080432-05:00
type: logging

metadata:
  context:
    action: start
    created: 2017-02-24 23:11:45 +0000 UTC
    ephemeral: "false"
    name: xen
    stateful: "false"
    used: 1970-01-01 00:00:00 +0000 UTC
  level: info
  message: Started container
timestamp: 2017-02-24T18:14:10.162965059-05:00
type: logging

metadata:
  context: {}
  level: dbug
  message: 'Success for task operation: 2e2cf904-c4c4-4693-881f-57897d602ad3'
timestamp: 2017-02-24T18:14:10.163072893-05:00
type: logging

lxc monitor 的格式有点不同于每个条目都缩合成一行的日志文件,但更重要的是,你可以看到所有 level:dbug 条目。

如何报告 bug

LXD 的 bug

最好报告 bug 的地方是 https://github.com/lxc/lxd/issues。确保完整填写了 bug 报告模板中的内容,这些信息可以节省我们我们时间来复现环境。

Ubuntu 的 bug

如果你发现 Ubuntu 包本身有问题,无法安装、升级或删除。或者遇到 LXD init 脚本的问题。报告此类错误的最好是在 Launchpad 上。

在 Ubuntu 系统上,你可以使用:ubuntu-bug lxd ,它将自动包括一些日志文件和包信息供我们查看。

CRIU 的 bug

与 CRIU 相关的 Bug,你可以通过 CRIU 的错误输出发现,你应该在 Launchpad 上报告这些:ubuntu-bug criu

请注意,通过 LXD 使用 CRIU 属于测试版功能,除非你愿意通过 Canonical 的支持合同付费支持,要么可能需要一段时间才能查看你的错误报告。

贡献给 LXD

LXD 用 Go 写成并托管在 Github。我们欢迎任外部的贡献。为 LXD 贡献不需要 CLA 或类似的法律协议签署,只是通常的开发者所有权证书(Signed-off-by: 行)。

在我们的问题追踪器工具中,我们列有许多潜在的功能需求,新的贡献者可以以此作为良好的起点。通常最好在开始处理代码先发出 issue,这样每个人都知道你正在做这项工作,以便我们可以提供一些早期反馈。

从源码源码构建 LXD

这里有上游的维护说明:https://github.com/lxc/lxd#building-from-source

你需要在 Github 上 fork 上游仓库,然后将你的更改推送到你的分支。我们建议每天 rebase 上游的 LXD,因为我们倾向于定期合并更改。

运行测试套件

LXD 维护了两套测试集,单元测试和集成测试。你可以用下面的命令测试所有:

sudo -E make check

要只运行单元测试,使用:

sudo -E go test ./...

要运行集成测试,使用:

cd test
sudo -E ./main.sh

后者支持相当多的环境变量来测试各种存储后端、禁用网络测试、使用 ramdisk 或只是调整日志输出。其中一些是:

  • LXD_BACKENDbtrfsdirlvmzfs” 之一(默认为 dir
    运行 LXD 存储驱动程序相关的所有测试。
  • LXD_CONCURRENTtruefalse(默认为 false
    这启用一些额外的并发测试。
  • LXD_DEBUGtruefalse(默认为 false
    记录所有 shell 命令,并在调试模式下运行所有​​ LXD 命令。
  • LXD_INSPECTtruefalse(默认为 false
    测试程序会在故障时挂起,以便你可以检查环境。
  • LXD_LOGS:将所有 LXD 日志文件转储到的目录(默认为 “”)
    所有生成的 LXD 守护进程的 logs 目录将被复制到此路径。
  • LXD_OFFLINEtruefalse(默认为 false
    禁用任何依赖于外部网络连接的测试。
  • LXD_TEST_IMAGE: unified 格式的 LXD 镜像的路径(默认为 “”)
    可以使用自定义测试镜像,而不是默认的最小 busybox 镜像。
  • LXD_TMPFStruefalse(默认为 false
    tmpfs 安装中运行整个测试套件,这会使用相当多的内存,但会使测试速度明显更快。
  • LXD_VERBOSEtruefalse(默认为 false
    不太极端的 LXD_DEBUG 版本。shell 命令仍然会记录,但 -debug 不会传递给 LXC 命令,LXD 守护进程只能使用 -verbose 运行。

测试程序将在实际运行之前提醒你任何缺失的依赖项。在相当快的机器上运行该测试可在 10 分钟内完成。

发送你的分支

发送拉取请求(PR)之前,你需要确认:

  • 你已经 rebase 了上游分支
  • 你的所有提交信息都包括 Signed-off-by: First Last <email> 这行
  • 已删除任何你的临时调试代码
  • 你已经将相关的提交 squash 在一起,以保持你的分支容易审查
  • 单元和集成测试全部通过

一切完成后,在 Github 上发起一个拉取请求。我们的 Jenkins 将验证提交是否全部有 signed-off,在 MacOS 和 Windows 上的测试将自动执行,如果看起来不错,我们将触发一个完整的 Jenkins 测试,它将在所有存储后端、32 位和 64 位以及我们关心的所有 Go 版本上测试你的分支。

假设我们有人触发了 Jenkins,这通常需要不到一个小时的时间。

一旦所有测试完成,我们对代码本身感到满意,你的分支将会被合并,你的代码会出现在下一个 LXD 发布中。如果更改适用于 LXD stable-2.0 分支,我们将为你向后移植。

总结

我希望这个系列的博客文章有助于你了解什么是 LXD,以及它可以做什么!

本系列的范围仅限于 LXD(2.0.x),但我们也为那些想要最新功能的用户提供每月功能版本。你可以找到一些其他涵盖了原来的 LXD 2.0系列文章中列出的功能的博客文章。

额外的信息

LXD 的主站在: https://linuxcontainers.org/lxd

LXD 的 GitHub 开发仓库: https://github.com/lxc/lxd

LXD 的邮件列表: https://lists.linuxcontainers.org

LXD 的 IRC 频道:#lxcontainers on irc.freenode.net

在线尝试 LXD: https://linuxcontainers.org/lxd/try-it


作者简介:我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者,目前在加拿大魁北克蒙特利尔的家所在的 Canonical 有限公司担任 LXD 的技术主管。


via: https://stgraber.org/2017/02/27/lxd-2-0-debugging-and-contributing-to-lxd-1212/

作者:Stéphane Graber 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这是 LXD 2.0 系列介绍文章的第十一篇。

  1. LXD 入门
  2. 安装与配置
  3. 你的第一个 LXD 容器
  4. 资源控制
  5. 镜像管理
  6. 远程主机及容器迁移
  7. LXD 中的 Docker
  8. LXD 中的 LXD
  9. 实时迁移
  10. LXD 和 Juju
  11. LXD 和 OpenStack
  12. 调试,及给 LXD 做贡献

介绍

首先对这次的延期抱歉。为了让一切正常我花了很长时间。我第一次尝试是使用 devstack 时遇到了一些必须解决问题。 然而即使这样,我还是不能够使网络正常。

我终于放弃了 devstack,并使用用户友好的 Juju 尝试使用 “conjure-up” 部署完整的 Ubuntu OpenStack。它终于工作了!

下面是如何运行一个完整的 OpenStack,使用 LXD 容器而不是 VM,并在 LXD 容器中运行所有这些(嵌套的!)。

要求

这篇文章假设你有一个可以工作的 LXD 设置,提供容器网络访问,并且你有一个非常强大的 CPU,大约 50GB 给容器空间和至少 16G B的内存。

记住,我们在这里运行一个完整的 OpenStack,这东西不是很轻量!

设置容器

OpenStack 由大量不同做不同事情的组件组成。 一些需要一些额外的特权,为了可以使设置更简单,我们将使用特权容器。

我们将配置支持嵌套的容器,预加载所有需要的内核模块,并允许它访问 /dev/mem(显然是需要的)。

请注意,这意味着 LXD 容器的大部分安全特性对该容器被禁用。 然而由 OpenStack 自身产生的容器将是无特权的,并且可以正常使用 LXD 的安全特性。

lxc launch ubuntu:16.04 openstack -c security.privileged=true -c security.nesting=true -c "linux.kernel_modules=iptable_nat, ip6table_nat, ebtables, openvswitch"
lxc config device add openstack mem unix-char path=/dev/mem

LXD 中有一个小 bug,它会尝试加载已经加载到主机上的内核模块。这已在LXD 2.5中得到修复,并将在LXD 2.0.6 中修复,但在此之前,可以使用以下方法:

lxc exec openstack -- ln -s /bin/true /usr/local/bin/modprobe

我们需要加几条 PPA 并安装 conjure-up,它是我们用来安装 OpenStack 的部署工具。

lxc exec openstack -- apt-add-repository ppa:conjure-up/next -y
lxc exec openstack -- apt-add-repository ppa:juju/stable -y
lxc exec openstack -- apt update
lxc exec openstack -- apt dist-upgrade -y
lxc exec openstack -- apt install conjure-up -y

最后一步是在容器内部配置 LXD 网络。

所有问题都选择默认,除了:

  • 使用 dir 存储后端( zfs 不在嵌套容器中用)
  • 不要配置 IPv6 网络(conjure-up/juju 不太兼容它)
lxc exec openstack -- lxd init

现在配置完容器了,现在我们部署 OpenStack!

用 conjure-up 部署 OpenStack

如先前提到的,我们用 conjure-up 部署 OpenStack。

这是一个很棒的用户友好的可以与 Juju 交互来部署复杂服务的工具。

首先:

lxc exec openstack -- sudo -u ubuntu -i conjure-up
  • 选择 “OpenStack with NovaLXD”
  • 选择 “localhost” 作为部署目标(使用 LXD)
  • 点击 “Deploy all remaining applications”

接下来会部署 OpenStack。整个过程会花费一个多小时,这取决于你运行的机器。你将看到所有服务会被分配一个容器,然后部署并最终互连。

Conjure-Up deploying OpenStack

部署完成后会显示一个安装完成的界面。它会导入一些初始镜像、设置 SSH 权限、配置网络最后会显示面板的 IP 地址。

访问面板并生成一个容器

面板运行在一个容器中,因此你不能直接从浏览器中访问。

最简单的方法是设置一条 NAT 规则:

lxc exec openstack -- iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to <IP>

其中 <ip> 是 conjure-up 在安装结束时给你的面板 IP 地址。

你现在可以获取 “openstack” 容器的 IP 地址(来自 lxc info openstack),并将浏览器指向:http:///horizon 。

第一次加载可能需要几分钟。 一旦显示了登录界面,输入默认登录名和密码(admin/openstack),你就会看到OpenStack的欢迎面板!

oslxd-dashboard

现在可以选择左边的 “Project” 选项卡,进入 “Instances” 页面。 要启动一个使用 nova-lxd 的新实例,点击 “Launch instance”,选择你想要的镜像,网络等,接着你的实例就产生了。

一旦它运行后,你可以为它分配一个浮动 IP,它将允许你从你的 “openstack” 容器中访问你的实例。

总结

OpenStack 是一个非常复杂的软件,你也不会想在家里或在单个服务器上运行它。 但是,不管怎样在你的机器上包含这些服务在一个容器中都是非常有趣的。

conjure-up 是部署这种复杂软件的一个很好的工具,背后使用 Juju 驱动部署,为每个单独的服务使用 LXD 容器,最后是实例本身。

它也是少数几个容器嵌套多层并实际上有意义的情况之一!

额外信息

conjure-up 网站: http://conjure-up.io

Juju 网站: http://www.ubuntu.com/cloud/juju

LXD 的主站在: https://linuxcontainers.org/lxd

LXD 的 GitHub 仓库: https://github.com/lxc/lxd

LXD 的邮件列表: https://lists.linuxcontainers.org

LXD 的 IRC 频道: #lxcontainers on irc.freenode.net

如果你不想或者不能在你的机器上安装 LXD ,你可以在 web 上试试在线版的 LXD。


作者简介:我是 Stéphane Graber。我是 LXC 和 LXD 项目的领导者,目前在加拿大魁北克蒙特利尔的家所在的 Canonical 有限公司担任 LXD 的技术主管。


via: https://www.stgraber.org/2016/10/26/lxd-2-0-lxd-and-openstack-1112/

作者:Stéphane Graber 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出