如何在Ubuntu18.04上设置和使用LXD
作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。
介绍
Linux 容器 是一组与系统其余部分分离的进程。 对于最终用户来说,Linux 容器就像一个虚拟机,但它更轻量级。 您没有运行额外 Linux 内核的开销,并且容器不需要任何 CPU 硬件虚拟化支持。 这意味着您可以在同一台服务器上创建比虚拟机更多的容器。
想象一下,您有一个应该为您的客户运行多个网站的服务器。 一方面,每个网站都可以是 Apache 或 Nginx Web 服务器的同一实例的虚拟主机/服务器块。 另一方面,在使用虚拟机时,您将为每个网站创建一个单独的嵌套虚拟机。 Linux 容器位于虚拟主机和虚拟机之间。
LXD 允许您创建和管理这些容器。 LXD 提供管理程序服务来管理容器的整个生命周期。 在本教程中,您将配置 LXD 并使用它在容器中运行 Nginx。 然后,您将流量从 Internet 路由到容器,以使示例网页可访问。
先决条件
要完成本教程,您需要以下内容:
- 运行 Ubuntu 18.04 的 服务器。 要设置服务器,包括非 root sudo 用户和防火墙,您可以 创建一个运行 Ubuntu 18.04 的 DigitalOcean Droplet,然后按照我们的 初始服务器设置指南 。 记下您的服务器的公共 IP 地址。 我们稍后将其称为
your_server_ip
。 - 至少 5GB 的块存储。 要进行此设置,您可以按照 DigitalOcean 的块存储卷快速入门 。 在 Block Storage 的配置中,选择
Manually Format & Mount
以便 LXD 根据需要进行准备。 您将使用它来存储与容器相关的所有数据。
注: LXD 预装在 Ubuntu 18.04 中,安装的 LXD 包为 deb 包。 但从 Ubuntu 20.04 开始,较新版本的 LXD 现在只能作为 snap 软件包提供。
因此,Ubuntu 18.04 是最后一个将 LXD 作为 deb 包的 Ubuntu 版本。 此 LXD deb 软件包在 2023 年之前提供标准支持,并在 2028 年结束生命周期。 请参阅下表以帮助您确定包装格式。
特征 | deb 包 | 快照包 |
---|---|---|
可用的 LXD 版本 | 3.0 | 2.0、3.0、4.0、4.x |
内存要求 | 最小的 | 中等,用于 snapd 服务
|
升级注意事项 | 你可以决定不升级 LXD | 可以将 LXD 升级最多推迟 60 天 |
从其他包格式切换的能力 | 不支持 | 可以从 deb 切换到 snap |
按照本教程的其余部分在 Ubuntu 18.04 中使用 deb 包中的 LXD。 但是,如果您想在 Ubuntu 18.04 中使用 LXD snap 包,请参阅 [TODO-TUTORIAL-FOR-LXD-IN-UBUNTU-20.04]。
第 1 步 — 配置 LXD
LXD 在 Ubuntu 18.04 中作为 deb 包提供。 它是预先安装的,但您必须先对其进行配置,然后才能使用它。 LXD 由 LXD 服务和帮助您配置服务的默认客户端实用程序组成。 此客户端实用程序是 lxc
。 如果您将其作为 root
运行,或者您的非 root 帐户是 lxd
Unix 组的成员,则客户端实用程序可以访问 LXD 服务。 在下文中,我们将展示如何将您的非 root 用户帐户添加到 lxd
Unix 组,然后继续配置存储后端。
将您的非 root 帐户添加到 lxd
Unix 组
设置非 root 帐户时,使用以下命令将它们添加到 lxd
组。 adduser
命令将用户帐户和 Unix 组作为参数,以便将用户帐户添加到现有的 Unix 组中:
sudo adduser sammy lxd
现在申请新的会员资格:
su sammy
输入您的密码并按 ENTER
。
最后,确认您的用户现在已添加到 lxd
组:
id -nG
您将收到如下输出:
sammy sudo lxd
现在您已准备好继续配置 LXD。
准备存储后端
首先,您将配置存储后端。
当您在 Ubuntu 上运行 LXD 时,推荐的存储后端是 ZFS 文件系统。 ZFS 还可以很好地与 DigitalOcean 块存储 配合使用。 要在 LXD 中启用 ZFS 支持,首先更新您的包列表,然后安装 zfsutils-linux
辅助包:
sudo apt update sudo apt install -y zfsutils-linux
我们几乎准备好运行 LXD 初始化脚本。
在此之前,您必须识别并记下块存储的设备名称。
为此,请使用 ls
检查 /dev/disk/by-id/
目录:
ls -l /dev/disk/by-id/
在此具体示例中,设备名称的完整路径为 /dev/disk/by-id/scsi-0DO_Volume_volume-fra1-0
:
Outputtotal 0 lrwxrwxrwx 1 root root 9 Sep 16 20:30 scsi-0DO_Volume_volume-fra1-0 -> ../../sda
记下存储设备的完整文件路径。 您将在以下小节中使用它。
您现在已准备好初始化 LXD。 使用 sudo lxd init
命令初始化 LXD:
sudo lxd init
将出现提示。 接下来的两部分将引导您完成每个问题的适当答案。
为 LXD 配置存储选项
首先,程序会询问您是否要启用 LXD 集群。 对于本教程,按 ENTER
接受默认的 no
,或键入 no
然后按 ENTER
。 LXD 集群是一个高级主题,可为您的 LXD 设置启用高可用性,并且需要在集群中运行至少三个 LXD 服务器:
OutputWould you like to use LXD clustering? (yes/no) [default=no]: no
接下来的六个提示处理存储池。 给出以下答复:
- 按
ENTER
配置新的存储池。 - 按
ENTER
接受默认存储池名称。 - 按
ENTER
接受默认的zfs
存储后端。 - 按
ENTER
创建一个新的 ZFS 池。 - 键入
yes
以使用现有的块设备。 - 最后,输入块存储设备名称的完整路径(这是您之前记录的内容。 它应该类似于:
/dev/disk/by-id/device_name
)。
您的答案将如下所示:
OutputDo you want to configure a new storage pool? (yes/no) [default=yes]: yes Name of the new storage pool [default=default]: default Name of the storage backend to use (btrfs, dir, lvm, zfs) [default=zfs]: zfs Create a new ZFS pool? (yes/no) [default=yes]: yes Would you like to use an existing block device? (yes/no) [default=no]: yes Path to the existing block device: /dev/disk/by-id/scsi-0DO_Volume_volume-fra1-01
您现在已经为 LXD 配置了存储后端。 继续使用 LXD 的 init
脚本,您现在将配置一些网络选项。
为 LXD 配置网络选项
LXD 现在询问您是否要连接到 MAAS(Metal As A Server)服务器。 MAAS 是一种软件,它使裸机服务器看起来像虚拟机,并且像虚拟机一样被处理。
我们在独立模式下运行 LXD,因此接受默认值并回答 no
:
OutputWould you like to connect to a MAAS server? (yes/no) [default=no]: no
然后要求您为 LXD 容器配置网桥。 这启用了以下功能:
- 每个容器都会自动获得一个私有 IP 地址。
- 每个容器都可以通过专用网络相互通信。
- 每个容器都可以启动到 Internet 的连接。
- 默认情况下,每个容器都无法从 Internet 访问; 除非您明确启用它,否则您无法从 Internet 启动连接并到达容器。 您将在下一步中学习如何允许访问特定容器。
当要求创建新的本地网桥时,选择 yes
:
OutputWould you like to create a new local network bridge? (yes/no) [default=yes]: yes
然后接受默认名称,lxdbr0
:
OutputWhat should the new bridge be called? [default=lxdbr0]: lxdbr0
接受网桥的私有 IP 地址范围的自动选择:
OutputWhat IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: auto What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: auto
最后,LXD 提出以下杂项问题:
当询问您是否要通过网络管理 LXD 时,请按 ENTER
或回答 no
:
OutputWould you like LXD to be available over the network? (yes/no) [default=no]: no
当询问您是否要自动更新陈旧的容器映像时,请按 ENTER
或回答 yes
:
OutputWould you like stale cached images to be updated automatically? (yes/no) [default=yes] yes
当询问您是否要查看并保留您刚刚创建的 YAML 配置时,如果您愿意,请回答 yes
。 否则,您按 ENTER
或回答 no
:
OutputWould you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: no
您现在已经为 LXD 配置了网络和存储选项。 接下来,您将创建您的第一个 LXD 容器。
第 2 步——创建和配置 LXD 容器
现在您已经成功配置了 LXD,您可以创建和管理您的第一个容器了。 在 LXD 中,您可以使用 lxc
命令后跟一个操作来管理容器,例如 list
、launch
、start
、stop
和delete
。
使用 lxc list
查看可用的已安装容器:
lxc list
由于这是 lxc
命令第一次与 LXD 管理程序通信,因此它显示了有关如何启动容器的一些信息。 最后,该命令显示一个空的容器列表。 这是预期的,因为我们还没有创建任何东西:
Output of the "lxd list" commandTo start your first container, try: lxc launch ubuntu:18.04 +------+-------+------+------+------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+-------+------+------+------+-----------+
现在创建一个运行 Nginx 的容器。 为此,首先使用 lxc launch
命令创建并启动一个名为 webserver
的 Ubuntu 18.04 容器。
创建 webserver
容器。 ubuntu:18.04
中的 18.04
是 Ubuntu 18.04 的快捷方式。 ubuntu:
是 LXD 映像的预配置存储库的标识符。 您还可以使用 ubuntu:bionic
作为图像名称:
lxc launch ubuntu:18.04 webserver
注意:您可以通过运行 lxc image list ubuntu:
和其他 Linux 发行版通过运行 lxc image list images:
找到所有可用 Ubuntu 映像的完整列表。 ubuntu:
和 images:
都是容器镜像的存储库。 对于每个容器镜像,您可以使用命令 lxc image info ubuntu:18.04
获取更多信息。 虽然我们出于本教程的目的使用 Ubuntu 18.04 启动容器,但您可以为自己的项目选择任何可用的 Ubuntu 版本。
因为这是您第一次创建容器,所以此命令会从 Internet 下载容器映像并将其缓存。 新容器完成下载后,您将看到以下输出:
OutputCreating webserver Starting webserver
启动 webserver
容器后,使用 lxc list
命令显示有关它的信息。 我们添加了 --columns ns4
以便仅显示 name
、state
和 IPv4
地址的列。 默认的 lxc list
命令再显示三列:IPv6 地址、容器是持久的还是临时的,以及每个容器是否有可用的快照:
lxc list --columns ns4
输出显示了一个表,其中包含每个容器的名称、当前状态、IP 地址和类型:
Output+-----------+---------+------------------------------------+ | NAME | STATE | IPV4 | +-----------+---------+------------------------------------+ | webserver | RUNNING | your_webserver_container_ip (eth0) | +-----------+---------+------------------------------------+
LXD 的 DHCP 服务器提供此 IP 地址,在大多数情况下,即使服务器重新启动,它也会保持不变。 但是,在以下步骤中,您将创建 iptables
规则以将连接从 Internet 转发到容器。 因此,您应该指示 LXD 的 DHCP 服务器始终为容器提供相同的 IP 地址。
以下命令集将配置容器以获取静态 IP 分配。 首先,您将覆盖从默认 LXD 配置文件继承的 eth0
设备的网络配置。 这允许您设置静态 IP 地址,以确保 Web 流量进出容器的正确通信。
具体来说,lxc config device
是执行 config
动作以配置 device
的命令。 第一行有子操作 override
来覆盖容器 webserver
中的设备 eth0
。 第二行的子操作将 webserver
容器的 eth0
设备的 ipv4.address
字段设置为 DHCP 服务器在开始时提供的 IP 地址.
运行第一个 config
命令:
lxc config device override webserver eth0
您将收到如下输出:
OutputDevice eth0 overridden for webserver
现在设置静态IP:
lxc config device set webserver eth0 ipv4.address your_webserver_container_ip
如果命令成功,您将不会收到任何输出。
重启容器:
lxc restart webserver
现在检查容器的状态:
lxc list
您应该看到容器是 RUNNING
并且 IPV4
地址是您的静态地址。
您已准备好在容器内安装和配置 Nginx。
第 3 步 — 在 LXD 容器中配置 Nginx
在此步骤中,您将连接到 webserver
容器并配置 Web 服务器。
使用 lxc shell
命令连接到容器,该命令获取容器的名称并在容器内启动一个 shell:
lxc shell webserver
进入容器后,您的 shell 提示符将如下所示:
[environment second]
这个shell,即使是root shell,也仅限于容器。 您在此 shell 中运行的任何内容都保留在容器中,并且无法逃逸到主机服务器。
注意: 将shell放入容器时,您可能会看到mesg: ttyname failed: No such device
等警告。 当容器中的 shell 尝试从配置文件 /root/.profile
运行命令 mesg
时,会产生此消息。 您可以放心地忽略它。 为避免看到它,您可以从 /root/.profile
中删除命令 mesg n || true
。
进入容器后,更新包列表并安装 Nginx:
apt update apt install nginx
安装 Nginx 后,您现在将编辑默认的 Nginx 网页。 具体来说,您将添加两行文本,以便清楚地表明该站点托管在 webserver
容器内。
使用 nano
或您喜欢的编辑器,打开文件 /var/www/html/index.nginx-debian.html
:
nano /var/www/html/index.nginx-debian.html
将两个突出显示的短语添加到文件中:
/var/www/html/index.nginx-debian.html<!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container webserver!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx on LXD container webserver!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> ...
您在两个地方编辑了文件,并专门添加了文本 on LXD container webserver
。 保存文件并退出文本编辑器。
现在退出容器:
logout
服务器默认提示返回后,使用 curl
测试容器中的 Web 服务器是否正常工作。 为此,您需要使用之前使用 lxc list
命令找到的 Web 容器的 IP 地址。
使用 curl
测试您的 Web 服务器:
curl http://your_webserver_container_ip
您将收到 Nginx 默认的 HTML 欢迎页面作为输出。 请注意,它包括您的编辑:
Output<!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container webserver!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx on LXD container webserver!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> ...
Web 服务器正在工作,但您只能在使用私有 IP 的主机上访问它。 在下一步中,您会将外部请求路由到此容器,以便全世界都可以通过 Internet 访问您的网站。
第 4 步 - 使用 LXD 将传入连接转发到 Nginx 容器
现在您已经配置了 Nginx,是时候将 webserver 容器连接到互联网了。 首先,您需要设置服务器以将它可能在端口 80
上接收到的任何连接转发到 webserver
容器。 为此,您将创建一个 iptables
规则来转发网络连接。 您可以在我们的教程 IPtables 防火墙的工作原理 和 IPtables Essentials:通用防火墙规则和命令 中了解有关 IPTables 的更多信息。
这个 iptables
命令需要两个 IP 地址:服务器的公共 IP 地址(your_server_ip
)和 webserver
容器的私有 IP 地址(your_webserver_container_ip
) ,您可以使用 lxc list
命令获取。
执行此命令以创建新的 IPtables 规则:
PORT=80 PUBLIC_IP=your_server_ip CONTAINER_IP=your_container_ip IFACE=eth0 sudo -E bash -c 'iptables -t nat -I PREROUTING -i $IFACE -p TCP -d $PUBLIC_IP --dport $PORT -j DNAT --to-destination $CONTAINER_IP:$PORT -m comment --comment "forward to the Nginx container"'
让我们研究一下这个命令:
-t nat
指定我们使用nat
表进行地址转换。-I PREROUTING
指定我们将规则添加到 PREROUTING 链。-i $IFACE
指定接口eth0
,这是Droplet在主机上的默认公网接口。-p TCP
表示我们正在使用 TCP 协议。-d $PUBLIC_IP
指定规则的目标 IP 地址。--dport $PORT
:指定目的端口(如80
)。-j DNAT
表示我们要跳转到目标 NAT (DNAT)。--to-destination $CONTAINER_IP:$PORT
表示我们希望请求到达特定容器的 IP 地址和目标端口。
注意: 可以重复使用该命令设置转发规则。 重置行首的变量 PORT
、PUBLIC_IP
、CONTAINER_IP
和 IFACE
。 只需更改突出显示的值。
现在列出您的 IPTables 规则:
sudo iptables -t nat -L PREROUTING
你会看到这样的输出:
[secondary_label Output] Chain PREROUTING (policy ACCEPT) target prot opt source destination DNAT tcp -- anywhere your_server_ip tcp dpt:http /* forward to this container */ to:your_container_ip:80 ...
现在测试网络服务器是否可以从互联网访问
使用本地机器上的 curl
命令测试连接:
curl --verbose 'http://your_server_ip'
您将看到标题后面是您在容器中创建的网页的内容:
Output* Trying your_server_ip... * Connected to your_server_ip (your_server_ip) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.10.0 (Ubuntu) ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container webserver!</title> <style> body { ...
这确认请求将发送到容器。
最后,您将保存防火墙规则,以便在重新启动后重新应用。
为此,首先安装 iptables-persistent
包:
sudo apt install iptables-persistent
安装软件包时,应用程序会提示您保存当前的防火墙规则。 接受并保存所有当前规则。
当您重新启动计算机时,将加载防火墙规则。 另外,你的 LXD 容器中的 Nginx 服务会自动重启。
您已成功配置 LXD。 在最后一步中,您将学习如何停止和销毁服务。
第 5 步 — 使用 LXD 停止和删除容器
您可能决定要取下容器并将其删除。 在此步骤中,您将停止并移除您的容器。
首先,停止容器:
lxc stop webserver
使用 lxc list
命令验证状态:
lxc list
您将看到容器的状态显示为 STOPPED
:
Output+-----------+---------+------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-----------+---------+------+------+------------+-----------+ | webserver | STOPPED | | | PERSISTENT | 0 | +-----------+---------+------+------+------------+-----------+
要移除容器,请使用 lxc delete
:
lxc delete webserver
再次运行 lxc list
表明没有容器在运行:
lxc list
该命令将输出以下内容:
+------+-------+------+------+------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+-------+------+------+------+-----------+
使用 lxc help
命令查看其他选项。
要删除将流量路由到容器的防火墙规则,请首先使用此命令在规则列表中找到该规则,该命令将行号与每个规则相关联:
sudo iptables -t nat -L PREROUTING --line-numbers
您将看到以行号为前缀的规则,如下所示:
OutputChain PREROUTING (policy ACCEPT) num target prot opt source destination 1 DNAT tcp -- anywhere your_server_ip tcp dpt:http /* forward to the Nginx container */ to:your_container_ip
使用该行号删除规则:
sudo iptables -t nat -D PREROUTING 1
再次列出规则以确保删除:
sudo iptables -t nat -L PREROUTING --line-numbers
规则被删除:
OutputChain PREROUTING (policy ACCEPT) num target prot opt source destination
现在保存更改,以便在您重新启动服务器时规则不会返回:
sudo netfilter-persistent save
您现在可以使用自己的设置启动另一个容器并添加新的防火墙规则以将流量转发给它。
结论
在本教程中,您安装并配置了 LXD。 然后,您使用在 LXD 容器中运行的 Nginx 创建了一个网站,并通过 IPtables 将其公开。
从这里,您可以配置更多网站,每个网站都限制在自己的容器中,并使用反向代理将流量引导到适当的容器。 教程 How to Host Multiple Web Sites with Nginx and HAProxy Using LXD on Ubuntu 16.04 将引导您完成该设置。
有关如何使用 LXD 的更多信息,请参阅 LXD 参考文档 。
要练习 LXD,您可以 在线尝试 LXD 并按照基于网络的教程进行操作。
要获得 LXD 的用户支持,请访问 LXD 论坛 。