如何在 Ubuntu 14.04 上设置具有 Keepalived 和保留 IP 的高可用性 Web 服务器
介绍
高可用性是系统设计的一项功能,它允许应用程序在发生故障时自动重启或将工作重新路由到另一个有能力的系统。在服务器方面,建立高可用性系统需要几种不同的技术。必须有一个可以重定向工作的组件,并且必须有一种机制来监视故障并在检测到中断时转换系统。
keepalived
守护进程可用于监控服务或系统,并在出现问题时自动故障转移到备用服务器。在本指南中,我们将演示如何使用 keepalived
设置高可用性 Web 服务。我们将配置一个保留 IP 地址,该地址可以在两个可用的 Web 服务器之间移动。如果主服务器出现故障,保留的 IP 将自动移动到第二个服务器,从而恢复服务。
先决条件
为了完成本指南,您需要在您的 DigitalOcean 帐户上创建两个 Ubuntu 14.04 服务器。两台服务器必须位于同一数据中心内,并且应启用专用网络。
在这些服务器中的每一个上,您都需要一个配置有 sudo
访问权限的非根用户。您可以按照我们的 Ubuntu 14.04 初始服务器设置指南来了解如何设置这些用户。
当您准备好开始时,使用您的非 root 用户登录到您的两个服务器。
安装和配置 Nginx
虽然 keepalived
通常用于监控和故障转移负载均衡器,但为了降低我们的操作复杂性,我们将在本指南中使用 Nginx 作为简单的 Web 服务器。
首先更新每台服务器上的本地包索引。然后我们可以安装 Nginx:
- sudo apt-get update
- sudo apt-get install nginx
在大多数情况下,对于高可用性设置,您会希望两台服务器提供完全相同的内容。但是,为了清楚起见,在本指南中,我们将使用 Nginx 来指示两个服务器中的哪一个在任何给定时间为我们的请求提供服务。为此,我们将更改每个主机上的默认 index.html
页面。现在打开文件:
- sudo nano /usr/share/nginx/html/index.html
在您的第一台服务器上,将文件的内容替换为:
<h1>Primary</h1>
在您的第二台服务器上,将文件的内容替换为:
<h1>Secondary</h1>
完成后保存并关闭文件。
构建并安装 Keepalived
接下来,我们将在我们的服务器上安装 keepalived
守护进程。 Ubuntu 的默认存储库中有一个 keepalived
版本,但它已经过时并且存在一些错误,导致我们的配置无法正常工作。相反,我们将从源代码安装最新版本的 keepalived
。
在开始之前,我们应该获取构建软件所需的依赖项。 build-essential
元包将提供我们需要的编译工具,而libssl-dev
包包含keepalived
需要的SSL库针对:
- sudo apt-get install build-essential libssl-dev
一旦依赖关系到位,我们就可以下载 keepalived
的 tarball。访问此页面以查找最新版本的软件。右键点击最新版本,复制链接地址。回到您的服务器,移至您的主目录并使用 wget
获取您复制的链接:
- cd ~
- wget http://www.keepalived.org/software/keepalived-1.2.19.tar.gz
使用 tar
命令展开存档,然后移至生成的目录:
- tar xzvf keepalived*
- cd keepalived*
通过键入以下内容构建并安装守护程序:
- ./configure
- make
- sudo make install
守护程序现在应该安装在系统上。
创建一个 Keepalived Upstart 脚本
keepalived
安装将所有二进制文件和支持文件移动到我们系统上的位置。但是,没有包含的一个部分是我们的 Ubuntu 14.04 系统的 Upstart 脚本。
我们可以创建一个非常简单的 Upstart 脚本来处理我们的 keepalived
服务。打开 /etc/init
目录中名为 keepalived.conf
的文件以开始使用:
- sudo nano /etc/init/keepalived.conf
在内部,我们可以从 keepalived
提供的功能的简单描述开始。我们将使用包含的 man
页面中的描述。接下来我们将指定启动和停止服务的运行级别。我们希望此服务在所有正常条件下(运行级别 2-5)都处于活动状态,并在所有其他运行级别下停止(例如,当重启、关机或启动单用户模式时):
description "load-balancing and high-availability service"
start on runlevel [2345]
stop on runlevel [!2345]
因为此服务对于确保我们的 Web 服务保持可用是不可或缺的,所以我们希望在发生故障时重新启动此服务。然后我们可以指定将启动服务的实际 exec
行。我们需要添加 --dont-fork
选项,以便 Upstart 可以正确跟踪 pid
:
description "load-balancing and high-availability service"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
exec /usr/local/sbin/keepalived --dont-fork
完成后保存并关闭文件。
创建 Keepalived 配置文件
有了我们的 Upstart 文件,我们现在可以继续配置 keepalived
。
该服务在 /etc/keepalived
目录中查找其配置文件。现在在您的两台服务器上创建该目录:
- sudo mkdir -p /etc/keepalived
收集您的服务器的私有 IP 地址
在我们创建配置文件之前,我们需要找到我们两台服务器的私有 IP 地址。在 DigitalOcean 服务器上,您可以通过键入以下内容通过元数据服务获取我们的私有 IP 地址:
- curl http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address && echo
Output10.132.7.107
这也可以通过键入以下内容使用 iproute2
工具找到:
- ip -4 addr show dev eth1
您正在寻找的价值将在这里找到:
Output3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 10.132.7.107/16 brd 10.132.255.255 scope global eth1
valid_lft forever preferred_lft forever
从您的两个系统复制此值。我们需要在下面的配置文件中引用这些地址。
创建主服务器的配置
接下来,在您的主服务器上,创建主要的 keepalived
配置文件。守护进程在 /etc/keepalived
目录中查找名为 keepalived.conf
的文件:
- sudo nano /etc/keepalived/keepalived.conf
在内部,我们将通过打开一个 vrrp_script
块来为我们的 Nginx 服务定义健康检查。这将允许 keepalived
监控我们的网络服务器是否有故障,以便它可以发出进程已关闭的信号并开始恢复措施。
我们的检查将非常简单。每两秒钟,我们将检查一个名为 nginx
的进程是否仍在声明一个 pid
:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
接下来,我们将打开一个名为 vrrp_instance
的块。这是定义 keepalived
实现高可用性的方式的主要配置部分。
我们将首先告诉 keepalived
通过我们的私有接口 eth1
与其对等方通信。由于我们正在配置我们的主服务器,我们会将 state
配置设置为 \MASTER。这是 keepalived
将使用的初始值,直到守护程序可以联系其对等方并举行选举。
在选举期间,priority
选项用于决定选举哪个成员。该决定仅基于哪个服务器具有此设置的最高数量。我们将使用 \200 作为我们的主服务器:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
}
接下来,我们将为这个集群组分配一个由两个节点共享的 ID。我们将在此示例中使用 \33。我们需要将 unicast_src_ip
设置为我们之前检索到的主服务器的私有 IP 地址。我们将设置 unicast_peer
为我们的辅助服务器的私人IP地址:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
virtual_router_id 33
unicast_src_ip primary_private_IP
unicast_peer {
secondary_private_IP
}
}
接下来,我们可以为我们的 keepalived
守护进程设置一些简单的身份验证,以便相互通信。这只是确保相关服务器合法的基本措施。创建一个 authentication
子块。在内部,通过设置 auth_type
指定密码验证。对于 auth_pass
参数,设置将由两个节点使用的共享密钥。不幸的是,只有前八个字符是重要的:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
virtual_router_id 33
unicast_src_ip primary_private_IP
unicast_peer {
secondary_private_IP
}
authentication {
auth_type PASS
auth_pass password
}
}
接下来,我们将告诉 keepalived
使用我们在文件顶部创建的例程,标记为 chk_nginx
,以确定本地系统的健康状况。最后,我们将设置一个 notify_master
脚本,每当该节点成为对的“主”时执行该脚本。该脚本将负责触发保留 IP 地址重新分配。我们将创建该脚本暂时:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state MASTER
priority 200
virtual_router_id 33
unicast_src_ip primary_private_IP
unicast_peer {
secondary_private_IP
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
chk_nginx
}
notify_master /etc/keepalived/master.sh
}
设置完上述信息后,保存并关闭文件。
创建辅助服务器的配置
接下来,我们将在我们的辅助服务器上创建配套脚本。在辅助服务器上的 /etc/keepalived/keepalived.conf
打开一个文件:
- sudo nano /etc/keepalived/keepalived.conf
在内部,我们将使用的脚本在很大程度上等同于主服务器的脚本。我们需要更改的项目是:
state
:这应该在辅助服务器上更改为“BACKUP”,以便节点在选举发生之前初始化为备份状态。priority
:这应该设置为比主服务器低的值。我们将在本指南中使用值“100”。unicast_src_ip
:这应该是辅助服务器的私有IP地址。unicast_peer
:这应该包含主服务器的私有 IP 地址。
当您更改这些值时,辅助服务器的脚本应如下所示:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
interface eth1
state BACKUP
priority 100
virtual_router_id 33
unicast_src_ip secondary_private_IP
unicast_peer {
primary_private_IP
}
authentication {
auth_type PASS
auth_pass password
}
track_script {
chk_nginx
}
notify_master /etc/keepalived/master.sh
}
输入脚本并更改适当的值后,保存并关闭文件。
创建保留 IP 转换脚本
接下来,我们需要创建一对脚本,只要本地 keepalived
实例成为主服务器,我们就可以使用它们将保留 IP 地址重新分配给当前 Droplet。
下载保留 IP 分配脚本
首先,我们将下载一个通用的 Python 脚本(由 DigitalOcean 社区管理员编写),该脚本可用于使用 DigitalOcean API 将保留 IP 地址重新分配给 Droplet。我们应该将此文件下载到 /usr/local/bin
目录:
- cd /usr/local/bin
- sudo curl -LO http://do.co/assign-ip
此脚本允许您通过运行重新分配现有的保留 IP:
- python /usr/local/bin/assign-ip reserved_ip droplet_ID
这仅在您将名为 DO_TOKEN
的环境变量设置为您帐户的有效 DigitalOcean API 令牌时才有效。
创建一个 DigitalOcean API 令牌
为了使用上面的脚本,我们需要在我们的帐户中创建一个 DigitalOcean API 令牌。
在控制面板中,单击顶部的“API”链接。在 API 页面的右侧,单击“生成新令牌”:

在下一页上,为您的令牌选择一个名称,然后单击“生成令牌”按钮:

在 API 页面上,您的新令牌将显示:

立即复制令牌。为了安全起见,以后无法再次显示此令牌。如果你丢失了这个令牌,你将不得不销毁它并创建另一个。
为您的基础设施配置保留 IP
接下来,我们将创建并分配一个保留 IP 地址以供我们的服务器使用。
在 DigitalOcean 控制面板中,单击“网络”选项卡并选择“保留 IP”导航项。从列表中选择您指定为“主要”服务器的 Droplet:

一个新的保留 IP 地址将在您的帐户中创建并分配给指定的 Droplet:

如果您在 Web 浏览器中访问保留 IP,您应该会看到“主”服务器 index.html
页面:

将保留的 IP 地址复制下来。您将在下面的脚本中需要此值。
创建包装器脚本
现在,我们有了创建包装器脚本所需的项目,该包装器脚本将使用正确的凭据调用我们的 /usr/local/bin/assign-ip
脚本。
现在通过键入以下内容在两台服务器上创建文件:
- sudo nano /etc/keepalived/master.sh
在内部,首先分配并导出一个名为 DO_TOKEN
的变量,该变量保存您刚刚创建的 API 令牌。在此之下,我们可以分配一个名为 IP
的变量来保存您的保留 IP 地址:
export DO_TOKEN='digitalocean_api_token'
IP='reserved_ip_addr'
接下来,我们将使用 curl
向元数据服务询问我们当前所在服务器的 Droplet ID。这将分配给名为 ID
的变量。我们还将询问这个 Droplet 当前是否有分配给它的保留 IP 地址。我们将该请求的结果存储在名为 HAS_RESERVED_IP
的变量中:
export DO_TOKEN='digitalocean_api_token'
IP='reserved_ip_addr'
ID=$(curl -s http://169.254.169.254/metadata/v1/id)
HAS_RESERVED_IP=$(curl -s http://169.254.169.254/metadata/v1/reserved_ip/ipv4/active)
现在,我们可以使用上面的变量来调用 assign-ip
脚本。如果保留 IP 尚未与我们的 Droplet 关联,我们只会调用脚本。这将有助于最大程度地减少 API 调用,并有助于在主状态在服务器之间快速切换的情况下防止对 API 的请求发生冲突。
为处理保留 IP 已经有正在进行的事件的情况,我们将重试 assign-ip
脚本几次。下面,我们尝试运行脚本 10 次,每次调用之间间隔 3 秒。如果保留 IP 移动成功,循环将立即结束:
export DO_TOKEN='digitalocean_api_token'
IP='reserved_ip_addr'
ID=$(curl -s http://169.254.169.254/metadata/v1/id)
HAS_RESERVED_IP=$(curl -s http://169.254.169.254/metadata/v1/reserved_ip/ipv4/active)
if [ $HAS_RESERVED_IP = "false" ]; then
n=0
while [ $n -lt 10 ]
do
python /usr/local/bin/assign-ip $IP $ID && break
n=$((n+1))
sleep 3
done
fi
完成后保存并关闭文件。
现在,我们只需要使脚本可执行,以便 keepalived
可以调用它:
- sudo chmod +x /etc/keepalived/master.sh
启动Keepalived服务并测试故障转移
keepalived
守护程序及其所有伴随脚本现在应该已完全配置。我们可以通过键入以下命令在我们的两台机器上启动服务:
- sudo start keepalived
该服务应在每台服务器上启动并联系其对等方,使用我们配置的共享密钥进行身份验证。每个守护进程都会监视本地 Nginx 进程,并会监听来自远程 keepalived
进程的信号。
当两台服务器都健康时,如果您在 Web 浏览器中访问您的保留 IP,您应该被带到主服务器的 Nginx 页面:

现在,我们已准备好测试配置的故障转移功能。
当发生以下任一情况时,应发生故障转移:
- 当主服务器上的 Nginx 健康检查表明 Nginx 不再运行时。在这种情况下,主服务器的
keepalived
守护进程将进入“故障”状态。它会通知辅助服务器它应该转换到主状态并申请保留 IP。 - 当辅助服务器失去与主服务器的
keepalived
连接时。如果辅助服务器由于任何原因无法连接到主服务器,它将转换为“主”状态并尝试申请保留 IP。
如果主服务器稍后恢复,它将转换回主状态并回收保留 IP,因为它将发起新的选举(它仍将具有最高优先级编号)。
测试 Nginx 失败
我们可以通过停止主服务器上的 Nginx 服务来测试第一个条件:
- sudo service nginx stop
如果刷新 Web 浏览器,最初可能会收到指示该页面不可用的响应:

然而,几秒钟后,如果你刷新页面几次,你会看到辅助服务器已经声明了保留的 IP 地址:

我们可以通过在主服务器上重新启动 Nginx 守护进程来从故障中恢复:
- sudo service nginx start
几秒钟后,如果你刷新页面,你会发现主服务器已经重新收回了 Reserved IP 的所有权:

测试服务器故障
我们应该测试的另一种情况是,如果辅助服务器无法连接到主服务器,它是否能正确转换到主状态。我们可以重启主服务器来测试这个:
- sudo reboot
同样,我们首先应该在保留 IP 地址处看到服务中断:

几秒钟后,辅助服务器将接收请求:

片刻之后,当主服务器完成重启时,它将回收 IP 地址:

这验证了我们的第二个失败场景。
结论
在本指南中,我们使用 keepalived
、DigitalOcean API 和保留 IP 地址配置了一个高度可用的 Web 服务器环境。实际的基础设施相当简单,但这些概念可以应用于服务可用性和正常运行时间很重要的任何类型的基础设施。