如何使用Ubuntu 16.04上的LXD托管使用Nginx和HAProxy的多个网站

介绍

Linux容器是通过使用Linux内核安全功能(如命名空间和控制组)与系统其余部分隔离的进程分组。 它是一个类似于虚拟机的结构,但它的重量更轻; 您没有运行额外的内核或模拟硬件的开销。 这意味着您可以轻松地在同一台服务器上创建多个容器。 使用Linux容器,您可以运行整个操作系统的多个实例,限制在同一台服务器上,或将应用程序及其依赖项捆绑在容器中,而不会影响系统的其余部分。

例如,假设您有一台服务器,并为您的客户设置了几个服务,包括网站。 在传统的安装中,每个网站都将是Apache或Nginx Web服务器的同一个实例的虚拟主机。 但是使用Linux容器,每个网站都将在自己的容器中配置自己的Web服务器。

我们可以使用LXD来创建和管理这些容器。 LXD提供管理程序服务来管理容器的整个生命周期。

在本教程中,您将使用LXD在同一台服务器上安装两个基于Nginx的网站,每个网站都限于自己的容器。 然后,您将在第三个容器中安装HAProxy,作为反向代理。 然后,您将会将流量路由到HAProxy容器,以使两个网站都可以从Internet访问。

先决条件

要完成本教程,您需要以下内容:

第1步 - 将用户添加到lxd

使用非root用户帐户登录服务器。 我们将使用此非用户帐户来执行所有容器管理任务。 要使其正常工作,您必须先将此用户添加到lxd组。 使用以下命令执行此操作:

sudo usermod --append --groups lxd sammy

退出服务器并重新登录,以便新的SSH会话将使用新的组成员资格进行更新。 登录后,您可以开始配置LXD。

第2步 - 配置LXD

在使用LXD之前,必须正确配置LXD。 最重要的配置决定是用于存储容器的存储后端的类型。 推荐的LXD存储后端是ZFS文件系统,存储在预先分配的文件中或通过使用块存储 要在LXD中使用ZFS支持,请安装zfsutils-linux软件包:

sudo apt-get update
sudo apt-get install zfsutils-linux

安装完成后,就可以初始化LXD了。 在初始化期间,系统将提示您指定ZFS存储后端的详细信息。 根据是否要使用预先分配的文件或块存储,还有两个部分。 按照你的情况适当的步骤。 指定存储机制后,您将配置容器的网络选项。

选项1 - 使用预先分配的文件

请按照以下步骤配置LXD以使用预先分配的文件来存储容器。 首先,执行以下命令启动LXD初始化过程:

sudo lxd init

系统将提示您提供几条信息,如以下输出所示。 我们将选择所有默认值,包括预分配文件的建议大小,称为循环设备

OutputName of the storage backend to use (dir or zfs) [default=zfs]: zfs
Create a new ZFS pool (yes/no) [default=yes]? yes
Name of the new ZFS pool [default=lxd]: lxd
Would you like to use an existing block device (yes/no) [default=no]? no
Size in GB of the new loop device (1GB minimum) [default=15]: 15
Would you like LXD to be available over the network (yes/no) [default=no]? no
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes
Warning: Stopping lxd.service, but it can still be activated by:
  lxd.socket
LXD has been successfully configured.

建议的大小是从服务器的可用磁盘空间自动计算的。

配置设备后,您将配置网络设置,我们将在下一个可选部分进行探索。

选项2 - 使用块存储

如果要使用Block Storage,您需要找到指向您创建的块存储卷的设备,以便在LXD的配置中指定它。 转到DigitalOcean控制面板 l 选项卡,找到您的卷,单击更多弹出窗口,然后单击配置说明

通过查看命令格式化卷来找到设备。 具体来说,查找sudo mkfs.ext4 -F命令中指定的路径。 下图显示了一个卷的示例。 你只需要下划线的部分:

[配置说明显示创建的块存储的设备。](httpss://assets.digitalocean.com/articles/lxd containers ubuntu_1604 / 6rDyC1l.png)

在这种情况下,卷的名称是/dev/disk/by-id/scsi-0D0_Volume_volume-fra1-01 ,尽管你可能有所不同。

识别卷后,返回终端并发出以下命令开始LXD初始化过程。

sudo lxd init

您会看到一系列问题。 回答以下输出中显示的问题:

OutputName of the storage backend to use (dir or zfs) [default=zfs]: zfs
Create a new ZFS pool (yes/no) [default=yes]? yes
Name of the new ZFS pool [default=lxd]: 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

然后使用剩余问题的默认值:

Output of the "lxd init" commandWould you like LXD to be available over the network (yes/no) [default=no]? no
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes
Warning: Stopping lxd.service, but it can still be activated by:
  lxd.socket
LXD has been successfully configured.

进程完成后,您将配置网络。

配置网络

初始化过程将向我们展示一系列屏幕,如下图所示,我们可以配置容器的网桥,以便他们可以获得私有IP地址,相互通信,并可以访问互联网。

[LXD网络配置](http://assets.digitalocean.com/articles/lxd containers ubuntu_1604 / u9D79uB.png)

使用每个选项的默认值,但是当询问IPv6网络时,选择 ,因为我们在本教程中不会使用它。

完成网络配置后,您就可以创建容器了。

第3步 - 创建容器

我们已经成功配置了LXD。 我们已经指定了存储后端的位置,并为任何新创建的容器配置了默认网络。 我们准备创建和管理一些容器,我们将使用lxc命令。

我们试试我们的第一个命令,其中列出了可用的已安装容器:

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进行安全通信。 然后,它显示有关如何启动容器的一些信息。 最后,该命令显示一个空的容器列表,这是预期的,因为我们还没有创建任何容器。

我们创建三个容器。 我们将为每个Web服务器创建一个,反向代理的第三个容器。 逆向代理的目的是将来自Internet的传入连接引导到容器中的正确Web服务器。

我们将使用lxc launch命令创建并启动名为web1的Ubuntu 16.04( ubuntu:x )容器。 ubuntu:xx ubuntu:x是Ubuntu 16.04的代号Xenial的第一个字母的快捷方式。 ubuntu:是LXD映像预配置存储库的标识符。

注意 :您可以通过运行lxc image list ubuntu:和其他发行版通过运行lxc image list images:来查找所有可用的Ubuntu映像的完整列表。

执行以下命令创建容器:

lxc launch ubuntu:x web1
lxc launch ubuntu:x web2
lxc launch ubuntu:x haproxy

因为这是我们第一次创建一个容器,所以第一个命令从Internet下载容器映像并将其缓存在本地。 接下来的两个容器将被快速创建。

在这里,您可以看到创建容器web1的示例输出。

OutputCreating web1
Retrieving image: 100%
Starting web1

现在我们已经创建了三个空的容器,我们使用lxc list命令显示有关它们的信息:

lxc list

输出显示具有每个容器的名称,其当前状态,其IP地址,其类型以及是否存在快照的表。

输出
+---------+---------+-----------------------+------+------------+-----------+
|  NAME   |  STATE  |         IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
+---------+---------+-----------------------+------+------------+-----------+
| haproxy | RUNNING | 10.10.10.10 (eth0)    |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
| web1    | RUNNING | 10.10.10.100 (eth0)   |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+
| web2    | RUNNING | 10.10.10.200 (eth0)   |      | PERSISTENT | 0         |
+---------+---------+-----------------------+------+------------+-----------+

记下容器名称及其对应的IPv4地址。 您将需要他们来配置您的服务。

第4步 - 配置Nginx容器

我们连接到web1容器并配置第一个Web服务器。

要连接,我们使用lxc exec命令,它使用容器的名称和要执行的命令。 执行以下命令连接到容器:

lxc exec web1 -- sudo --login --user ubuntu

-- string表示lxc的命令参数应该停在那里,其余的行将作为要在容器内执行的命令传递。 该命令是sudo --login --user ubuntu ,它为容器内的预配置帐户ubuntu提供了一个登录shell。

注意:如果您需要以root身份连接到容器,则可以使用命令lxc exec web1 -- /bin/bash

一旦进入容器,我们的shell提示符现在看起来如下。

Outputubuntu@web1:~$

容器中的这个ubuntu用户已经预配置了sudo访问,并且可以在不提供密码的情况下运行sudo命令。 这个外壳在容器的范围内是有限的。 我们在这个shell中运行的任何东西都保留在容器中,不能转发到主机服务器。

我们来更新容器中的Ubuntu实例的软件包列表,并安装Nginx:

sudo apt-get update
sudo apt-get install nginx

我们来编辑这个网站的默认网页,并添加一些文字,说明这个网站是托管在web1容器中的。 打开文件/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 web1!</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 web1!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...

我们在两个地方编辑了这个文件,并on LXD container web1特别添加了这个文本。 保存文件并退出编辑器。

现在退出容器并返回主机服务器:

logout

web2容器重复此过程。 登录,安装Nginx,然后编辑文件/var/www/html/index.nginx-debian.html来提到web2 然后退出web2容器。

让我们使用curl来测试容器中的Web服务器是否正常工作。 我们需要先前显示的Web容器的IP地址。

curl http://10.10.10.100/

输出应为:

Output of "curl http://10.10.10.100/" command<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</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 web1!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...

测试第二个容器,使用curl命令及其IP地址来验证它是否也正确设置。 配置两个容器,我们可以继续设置HAProxy。

第5步 - 配置HAProxy容器

我们将在这些容器之前设置HAProxy作为代理。 如果您需要更多关于如何工作的背景知识,请查看HAProxy和负载平衡概念简介 我们将根据我们使用的域名将流量引导到每个容器。 我们将在example.com的配置示例中使用域example.com ,这是本教程中的文档的特殊保留域 我们将在主机名example.comwww.example.com上提供第一个网站。 第二个网站将在www2.example.com 替换您自己的域名代替这些域名。

登录到haproxy容器:

lxc exec haproxy -- sudo --login --user ubuntu

更新安装包列表并安装HAProxy:

sudo apt-get update
sudo apt-get install haproxy

安装完成后,我们可以配置HAProxy。 HAProxy的配置文件位于/etc/haproxy/haproxy.cfg 用你喜欢的文本编辑器打开文件。

sudo nano /etc/haproxy/haproxy.cfg

首先,我们将对defaults部分进行几个修改。 我们将添加forwardfor选项,以便我们保留Web客户端的真正源IP,并且我们将添加http-server-close选项,这样可以实现会话重用和更低的延迟。

/etc/haproxy/haproxy.conf
global
...
defaults
    log global
    mode    http
    option  httplog
    option  dontlognull
    option   forwardfor
    option   http-server-close
    timeout connect 5000
    timeout client  50000
    timeout server  50000
...

接下来,我们将配置前端指向我们的两个后端容器。 添加一个名为www_frontend的新的frontend部分,如下所示:

/etc/haproxy/haproxy.conf
frontend www_frontend
    bind *:80     # Bind to port 80 (www) on the container

    # It matches if the HTTP Host: field mentions any of the hostnames (after the '-i').
    acl host_web1 hdr(host) -i example.com www.example.com
    acl host_web2 hdr(host) -i web2.example.com

    # Redirect the connection to the proper server cluster, depending on the match.
    use_backend web1_cluster if host_web1
    use_backend web2_cluster if host_web2

acl命令与Web服务器的主机名匹配,并将请求重定向到相应的backend部分。

然后我们定义两个新的backend部分,每个Web服务器一个,并分别命名为web1_cluster和web2_cluster。 将以下代码添加到文件中以定义后端:

/etc/haproxy/haproxy.conf
backend web1_cluster
    balance leastconn
    # We set the X-Client-IP HTTP header. This is useful if we want the web server to know the real client IP.
    http-request set-header X-Client-IP %[src]
    # This backend, named here "web1", directs to container "web1.lxd" (hostname).
    server web1 web1.lxd:80 check

backend web2_cluster
    balance leastconn
    http-request set-header X-Client-IP %[src]
    server web2 web2.lxd:80 check

balance选项表示负载balance策略。 在这种情况下,我们选择的连接数量最少。 http-request选项设置一个具有真实Web客户端IP的HTTP头。 如果我们没有设置此标题,则Web服务器将记录HAProxy IP地址作为所有连接的源IP,从而更难分析您的流量来源。 server选项指定服务器( web1 )的任意名称,后跟服务器的主机名和端口。

LXD为容器提供一个DNS服务器,所以web1.lxd解析为与web1容器关联的IP。 其他容器有自己的主机名,如web2.lxdhaproxy.lxd

check参数告诉HAPRoxy在Web服务器上执行运行状况检查,以确保它可用。

要测试配置是否有效,请运行以下命令:

/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c

输出应该是

输出
Configuration file is valid

让我们重新加载HAProxy,以便它读取新的配置。

sudo systemctl reload haproxy

现在退出容器以返回到主机。

logout

我们已将HAProxy配置为反向代理,将其在端口80接收的任何连接转发到其他两个容器中的相应Web服务器。 我们来测试一下, haproxy实际上是将请求转发到正确的Web容器。 执行此命令:

curl --verbose --header 'Host: web2.example.com' http://10.10.10.10

这向HAProxy发出请求,并设置一个HTTP host头,HAProxy应该使用它来将连接重定向到相应的Web服务器。

输出应该是

Output of "curl --verbose --header 'Host: web2.example.com' http://10.10.10.10" command...
> GET / HTTP/1.1
> Host: web2.example.com
> User-Agent: curl/7.47.0
> Accept: */*
> 
...
< 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web2!</title>
<style>
...

HAProxy正确地理解了请求并将其转发到web2容器。 在那里,Web服务器提供了我们之前编辑的默认索引页,并显示了on LXD container web2的文本。 现在让我们将外部请求传递给HAProxy,以便世界可以访问我们的网站。

第6步 - 转发到HAProxy容器的传入连接

最后一个谜题是将反向代理连接到互联网。 我们需要设置我们的服务器,将其从端口80上的任何连接转发到haproxy容器。

HAProxy安装在容器中,默认情况下,无法从Internet访问。 为了解决这个问题,我们将创建一个iptables规则来转发连接。

iptables命令需要两个IP地址:服务器的公网IP地址( your_server_ip )和haproxy容器的私有IP地址( your_haproxy_ip ),您可以使用lxc list命令获取该IP地址。

执行此命令创建规则:

sudo iptables -t nat -I PREROUTING -i eth0 -p TCP -d your_server_ip/32 --dport 80 -j DNAT --to-destination your_haproxy_ip:80

命令分解如下:

  • -t nat指定我们正在使用nat表。
  • -I PREROUTING指定我们将规则添加到PREROUTING链。
  • -i eth0指定接口eth0 ,它是Droplet上的默认公共接口。
  • -p TCP表示我们正在使用TCP协议。
  • -d your_server_ip /32指定规则的目标IP地址。
  • --dport 80 :指定目标端口。
  • -j DNAT说我们要跳转到目标NAT(DNAT)。
  • --to-destination your_haproxy_ip :80表示我们希望请求使用HAProxy转到容器的IP地址。

了解有关IPTables的更多信息,了解Iptables防火墙的工作原理IPtables Essentials:常见的防火墙规则和命令

最后,要保存这个iptables命令,以便在重新启动后重新应用,我们安装iptables-persistent包:

sudo apt-get install iptables-persistent

安装软件包时,系统将提示您保存当前的iptables规则。 接受并保存所有当前的iptables规则。

如果您已经设置了两个FQDN,那么您应该可以使用Web浏览器连接到每个网站。 试试看。

要测试两个Web服务器实际上可以从Internet访问,请使用curl命令从本地计算机访问每个Web服务器:

curl --verbose --header 'Host: example.com' 'http://your_server_ip'
curl --verbose --header 'Host: web2.example.com' 'http://your_server_ip'

这些命令使HTTP连接到服务器的公共IP地址,并使用Hheadroxy将用于处理请求的--header选项添加HTTP头字段,就像您在第5步中所做的那样。

这是第一个curl命令的输出:

Output*   Trying your_server_ip...
* Connected to your_server_ip (your_server_ip) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> 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 web1!</title>
<style>
    body {
...

这是第二个curl命令的输出:

Output*   Trying your_server_ip...
* Connected to your_server_ip (your_server_ip) port 80 (#0)
> GET / HTTP/1.1
> Host: web2.example.com
> 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 web2!</title>
<style>
    body {
...

在这两种情况下,都会显示正确的网站。

结论

您已经设置了两个网站,每个都在自己的容器中,HAProxy指示流量。 您可以复制此过程来配置更多的网站,每个网站都限于自己的容器。

您还可以在新的容器中添加MySQL,然后安装像WordPress这样的CMS来运行每个网站。 您还可以使用此过程来支持旧版本的软件。 例如,如果CMS的安装需要较早版本的软件,如PHP5,那么您可以在容器( lxc launch ubuntu:t )中安装Ubuntu 14.04,而不是尝试降级Ubuntu 16.04上提供的软件包管理器版本。

最后,LXD能够对容器的完整状态进行快照,这样可以在稍后的时间内轻松创建备份和卷容器。 另外,如果我们在两个不同的服务器上安装LXD,那么可以通过互联网连接他们并在服务器之间迁移容器。

赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏