介绍
Linux 容器 是一组进程,通过使用 Linux 内核安全功能(例如命名空间和控制组)与系统的其余部分隔离。 它是一个类似于虚拟机的结构,但它更轻量级; 您没有运行额外内核或模拟硬件的开销。 这意味着您可以轻松地在同一台服务器上创建多个容器。
例如,假设您有一台为您的客户运行多个网站的服务器。 在传统安装中,每个网站都是 Apache 或 Nginx Web 服务器的同一实例的虚拟主机。 但是使用 Linux 容器,每个网站都可以设置在自己的容器中,并带有自己的 Web 服务器。 使用 Linux 容器,您可以将应用程序及其依赖项捆绑在一个容器中,而不会影响系统的其余部分。
LXD 允许您创建和管理这些容器。 LXD 提供管理程序服务来管理容器的整个生命周期。 在本教程中,您将配置 LXD 并使用它在容器中运行 Nginx。 然后,您将流量路由到容器,以使网站可以从 Internet 访问。
先决条件
要完成本教程,您需要以下内容:
- 一台 Ubuntu 16.04 服务器,按照教程 Initial Server Setup with Ubuntu 16.04 进行配置,具有 sudo 非 root 用户和防火墙。
- 或者,按照教程 DigitalOcean 块存储入门 添加 20GB 或更多块存储。 您可以使用它来存储与容器相关的所有数据。
第 1 步 — 配置 LXD
LXD 已经安装在 Ubuntu 上,但需要适当配置才能在服务器上使用它。 您必须设置您的用户帐户来管理容器,然后配置存储后端的类型来存储容器并配置网络。
使用非 root 用户帐户登录服务器。 然后将您的用户添加到 lxd
组,以便您可以使用它来执行所有容器管理任务:
sudo usermod --append --groups lxd sammy
注销服务器并重新登录,以便您的新 SSH 会话将使用新的组成员身份进行更新。 登录后,您可以开始配置 LXD。
现在配置存储后端。 LXD 推荐的存储后端是 ZFS 文件系统,存储在预先分配的文件中或使用 Block Storage 存储。 要在 LXD 中使用 ZFS 支持,请更新您的软件包列表并安装 zfsutils-linux
软件包:
sudo apt-get update sudo apt-get install zfsutils-linux
您现在可以配置 LXD。 使用 lxd init
命令启动 LXD 初始化过程:
sudo lxd init
系统将提示您指定存储后端的详细信息。 完成该配置后,您将为容器配置网络。
首先,系统会询问您是否要配置新的存储池。 你应该回答yes.
。
Do you want to configure a new storage pool (yes/no) [default=yes]? yes
然后系统会提示您选择存储后端,您将有两个选择:dir
或 zfs
。 dir
选项告诉 LXD 将容器存储在服务器文件系统的目录中。 zfs
选项使用 ZFS 组合文件系统和逻辑卷管理器。
我们将使用 zfs
选项。 通过使用 zfs
,我们获得了存储效率和更好的响应能力。 例如,如果我们从同一个初始容器镜像创建十个容器,它们都只使用一个容器镜像的磁盘空间。 从那时起,只有他们对初始容器镜像所做的更改才会存储在存储后端。
OutputName of the storage backend to use (dir or zfs) [default=zfs]: zfs
选择 zfs
后,系统会要求您创建一个新的 ZFS 池并命名该池。 选择yes
创建池,调用池lxd
:
OutputCreate a new ZFS pool (yes/no) [default=yes]? yes Name of the new ZFS pool [default=lxd]: lxd
然后会询问您是否要使用现有的块设备:
OutputWould you like to use an existing block device (yes/no) [default=no]?
如果你说 yes
,你必须告诉 LXD 在哪里可以找到那个设备。 如果你说 no
,LXD 将使用预先分配的文件。 使用此选项,您将使用服务器本身的可用空间。
接下来有两个部分,具体取决于您是要使用预分配文件还是块设备。 根据您的情况执行适当的步骤。 指定存储机制后,您将为容器配置网络选项。
选项 1 – 使用预分配文件
如果您无权访问单独的块存储设备来存储容器,则可以使用预分配文件。 按照以下步骤将 LXD 配置为使用预分配的文件来存储容器。
首先,当要求使用现有的块设备时,输入 no
:
OutputWould you like to use an existing block device (yes/no) [default=no]? no
接下来,您将被要求指定 循环设备 的大小,这就是 LXD 所说的预分配文件。 为预分配的文件使用建议的默认大小:
OutputSize in GB of the new loop device (1GB minimum) [default=15]: 15
根据经验,15GB 确实是您应该创建的最小大小; 您想预先分配足够的空间,以便在创建容器后至少有 10GB 的可用空间。
配置设备后,系统会要求您配置网络设置。 进入步骤2继续设置。
选项 2 – 使用块设备
如果你打算使用块存储作为你的存储后端,你需要找到指向你创建的块存储卷的设备,以便在 LXD 的配置中指定它。 进入DigitalOcean控制面板中的Volumes选项卡,找到你的音量,点击弹出的More,然后点击配置说明。
通过查看格式化卷的命令找到设备。 具体来说,查找 sudo mkfs.ext4 -F
命令中指定的路径。 不要从该页面运行任何命令,因为我们只需要找到正确的设备名称来提供给 LXD。 下图显示了卷的设备名称示例。 您只需要红线下划线的部分:
您还可以使用以下命令识别设备名称:
ls -l /dev/disk/by-id/ total 0 lrwxrwxrwx 1 root root 9 Sep 16 20:30 scsi-0DO_Volume_volume-fra1-01 -> ../../sda
在这种情况下,卷的设备名称是 /dev/disk/by-id/scsi-0D0_Volume_volume-fra1-01
,尽管您的可能不同。
确定卷的设备名称后,继续 LXD 安装。 当系统提示您使用现有的块设备时,选择 yes
并提供设备的路径:
Output of the "lxd init" commandWould 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
指定磁盘后,系统会要求您配置网络选项。
第 2 步 — 配置网络
配置存储后端后,系统会提示您为 LXD 配置网络。
首先,LXD 询问您是否希望通过网络访问它。 选择 yes
可以让您从本地计算机管理 LXD,而无需通过 SSH 连接到该服务器。 保持 no
的默认值:
Output of the "lxd init" command — LXD over the networkWould you like LXD to be available over the network (yes/no) [default=no]? no
如果您想启用此选项,请阅读 LXD 2.0:远程主机和容器迁移 了解更多信息。
然后我们被要求为 LXD 容器配置一个网桥。 这启用了以下功能:
- 每个容器都会自动获得一个私有 IP 地址。
- 容器可以通过专用网络相互通信。
- 每个容器都可以发起到 Internet 的连接。
- 您创建的容器仍然无法从 Internet 访问; 除非您明确启用它,否则您无法从 Internet 建立连接并访问容器。 您将在下一步中学习如何允许访问特定容器。
当要求配置 LXD 网桥时,选择 yes
:
Output of the "lxd init" command — Networking for the containersDo you want to configure the LXD bridge (yes/no) [default=yes]? yes
然后您会看到以下对话框:
确认您要设置网桥。
系统会要求您命名这座桥。 接受默认值。
系统将要求您执行 IPv4 和 IPv6 的网络配置。 在本教程中,我们将只使用 IPv4。
当要求设置 IPv4 子网时,选择 是 。 您将被告知它为您配置了一个随机子网。 选择 确定 继续。
当提示输入有效的 IPv4 地址时,接受默认值。
当提示输入有效的 CIDR 掩码时,接受默认值。
当提示输入第一个 DHCP 地址时,接受默认值。 对最后一个 DHCP 地址以及 DHCP 客户端的最大数量执行相同的操作。
当要求对 IPv4 流量进行 NAT 时,选择 Yes。
当要求配置 IPv6 子网时,选择 No。 网络设置完成后,您将看到以下输出:
OutputWarning: Stopping lxd.service, but it can still be activated by: lxd.socket LXD has been successfully configured.
您已准备好创建容器。
第三步——创建 Nginx 容器
您已成功配置 LXD,现在可以创建和管理您的第一个容器。 您可以使用 lxc
命令管理容器。
使用 lxc list
查看可用的已安装容器:
lxc list
您将看到以下输出:
Output of the "lxd list" commandGenerating a client certificate. This may take a minute... If this is your first time using LXD, you should also run: sudo lxd init To start your first container, try: lxc launch ubuntu:16.04 +------+-------+------+------+------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+-------+------+------+------+-----------+
由于这是 lxc
命令第一次与 LXD 管理程序通信,因此输出让您知道该命令自动创建了一个客户端证书,用于与 LXD 进行安全通信。 然后,它显示了一些有关如何启动容器的信息。 最后,该命令显示了一个空的容器列表,这是预期的,因为我们还没有创建任何容器。
让我们创建一个运行 Nginx 的容器。 为此,我们将使用 lxc launch
命令创建并启动一个名为 webserver
的 Ubuntu 16.04 容器。
创建 webserver
容器:
lxc launch ubuntu:x webserver
ubuntu:x
中的x
是Ubuntu 16.04代号Xenial首字母的快捷方式。 ubuntu:
是 LXD 映像的预配置存储库的标识符。 您也可以使用 ubuntu:16.04
作为图像名称。
注意:您可以通过运行 lxc image list ubuntu:
和其他发行版通过运行 lxc image list images:
找到所有可用 Ubuntu 映像的完整列表。
因为这是您第一次创建容器,所以该命令会从 Internet 下载容器映像并将其缓存到本地,以便您创建新容器时,它会更快地创建。 创建新容器时,您将看到此输出:
OutputGenerating a client certificate. This may take a minute... If this is your first time using LXD, you should also run: sudo lxd init To start your first container, try: lxc launch ubuntu:16.04 Creating webserver Retrieving image: 100% Starting webserver
现在容器正在运行,使用 lxc list
命令显示有关它的信息:
lxc list
输出显示一个表格,其中包含每个容器的名称、当前状态、IP 地址、类型以及是否拍摄了快照。
输出
+-----------+---------+-----------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-----------+---------+-----------------------+------+------------+-----------+ | webserver | RUNNING | 10.10.10.100 (eth0) | | PERSISTENT | 0 | +-----------+---------+-----------------------+------+------------+-----------+
注意: 如果您在 LXD 中启用了 IPv6,则 lxc list
命令的输出可能对您的屏幕来说太宽。 您可以改用 lxc list --columns ns4tS
,它只显示名称、状态、IPv4、类型以及是否有可用的快照。
记下容器的 IPv4 地址。 您需要它来配置防火墙以允许来自外部世界的流量。
现在让我们在容器内设置 Nginx:
第 4 步 — 配置 Nginx 容器
让我们连接到 webserver
容器并配置 Web 服务器。
使用 lxc exec
命令连接到容器,该命令获取容器的名称和要执行的命令:
lxc exec webserver -- sudo --login --user ubuntu
第一个 --
字符串表示 lxc
的命令参数应该停在那里,该行的其余部分将作为要在容器内执行的命令传递。 命令为sudo --login --user ubuntu
,为容器内预配置的账号ubuntu
提供登录shell。
注意:如果需要以root身份连接容器,请改用命令lxc exec webserver -- /bin/bash
。
进入容器后,您的 shell 提示符现在如下所示。
Outputubuntu@webserver:~$
容器中的这个 ubuntu 用户预先配置了 sudo
访问权限,并且可以在不提供密码的情况下运行 sudo
命令。 该外壳仅限于容器的范围。 您在此 shell 中运行的任何内容都保留在容器中,并且无法逃逸到主机服务器。
让我们在这个容器中设置 Nginx。 更新容器内 Ubuntu 实例的包列表并安装 Nginx:
sudo apt-get update sudo apt-get install nginx
然后编辑该站点的默认网页并添加一些文本,明确表明该站点托管在 webserver
容器中。 打开文件/var/www/html/index.nginx-debian.html
:
sudo 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 服务器是否正常工作。 您将需要之前使用 lxd list
命令找到的 Web 容器的 IP 地址。
curl http://10.10.10.100/
输出应该是:
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 访问它。 让我们将外部请求路由到这个容器,以便全世界都可以访问我们的网站。
第 5 步 - 将传入连接转发到 Nginx 容器
最后一个难题是将 Web 服务器容器连接到 Internet。 Nginx 安装在容器中,默认情况下无法从 Internet 访问。 我们需要设置我们的服务器,将它可能在端口 80
上从 Internet 接收到的任何连接转发到 webserver
容器。 为此,我们将创建一个 iptables
规则来转发连接。 您可以在 IPtables 防火墙的工作原理 和 IPtables Essentials:通用防火墙规则和命令 中了解有关 IPTables 的更多信息。
iptables
命令需要两个 IP 地址:服务器的公共 IP 地址(your_server_ip
)和 nginx
容器的私有 IP 地址(your_webserver_container_ip
) ,您可以使用 lxc list
命令获取。
执行此命令以创建规则:
PORT=80 PUBLIC_IP=your_server_ip CONTAINER_IP=your_container_ip \ sudo -E bash -c 'iptables -t nat -I PREROUTING -i eth0 -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 eth0
指定接口 eth0,这是 Droplets 上默认的公共接口。-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
。 只需更改突出显示的值。
您可以通过运行以下命令列出 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
命令从本地计算机访问 Web 服务器来测试 Web 服务器实际上是否可以从 Internet 访问,如下所示:
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-get install iptables-persistent
安装软件包时,系统会提示您保存当前的防火墙规则。 接受并保存所有当前规则。
当您重新启动计算机时,防火墙规则将出现。 另外,你的 LXD 容器中的 Nginx 服务会自动重启。
现在您已经设置了所有内容,让我们看看如何将其拆除。
第 5 步 — 停止和移除容器
您可能决定要取下容器并更换它。 让我们来看看这个过程:
要停止容器,请使用 lxc stop
:
lxc stop webserver
使用 lxc list
命令验证状态。
Output+-----------+---------+------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-----------+---------+------+------+------------+-----------+ | webserver | STOPPED | | | PERSISTENT | 0 | +-----------+---------+------+------+------------+-----------+
要移除容器,请使用 lxc delete
:
lxc delete webserver
再次运行 lxc list
表明没有容器在运行:
Output+------+-------+------+------+------+-----------+ | 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 容器中运行的 Nginx 建立了一个网站。 从这里,您可以配置更多网站,每个网站都限制在自己的容器中,并使用反向代理将流量引导到适当的容器。 教程 How to Host Multiple Web Sites with Nginx and HAProxy Using LXD on Ubuntu 16.04 将引导您完成设置。
LXD 还允许您拍摄容器的完整状态的快照,从而可以轻松地创建备份并在以后回滚容器。 如果你在两台不同的服务器上安装 LXD,那么就可以通过 Internet 连接它们并在服务器之间迁移容器。
有关 LXD 的更多信息,请参阅 LXD 维护者撰写的关于 LXD 2.0 的系列博文 。
您也可以 在线尝试 LXD 并按照基于网络的教程进行更多练习。