### 使用 Heartbeat 构建高可用服务
> Even in the future, nothing works!
>
> — Spaceballs
一切迟早都会发生故障。高可用服务就是指当一个主机或网络线路失效时仍旧能够提供服务。 高可用性的主要技术就是冗余,另外,这个问题的解决就是以投放更多硬件设备而著称的。
虽然最终肯定会有单独的一台服务器失效,但是两台服务器同时失效的概率是不太高的, 这对大多数的应用程序提供了一个良好的冗余水平。
最简单的方法之一是建立一对冗余服务器,它们共享一个 IP 地址,并使用心跳检测。 **心跳**(**Heartbeat**)是一个守护进程,它同时运行在两台机器上并且定期彼此交换信息(heartbeats)。 其中的一台是主服务器,通常它拥有资源:在本例中是一个 IP 地址。 如果辅助服务器无法从主服务器检测到心跳信号,它就接管地址以确保服务的连续性。
在下面的处方中,我们将使用 Puppet 的配置设置两台机器,并解释如何使用它提供一个高可用服务。
#### 操作步骤
1. 创建如下的 heartbeat 模块:
```
# mkdir /etc/puppet/modules/heartbeat
# mkdir /etc/puppet/modules/heartbeat/manifests
# mkdir /etc/puppet/modules/heartbeat/files
```
2. 使用如下内容创建 /etc/puppet/modules/heartbeat/manifests/init.pp 文件:
```
class heartbeat {
package { "heartbeat":
ensure => installed,
}
service { "heartbeat":
ensure => running,
require => Package["heartbeat"],
}
exec { "reload-heartbeat":
command => "/usr/sbin/service heartbeat reload",
refreshonly => true,
}
file { "/etc/ha.d/authkeys":
source => "puppet:///modules/heartbeat/authkeys",
mode => "600",
require => Package["heartbeat"],
notify => Exec["reload-heartbeat"],
}
file { "/etc/ha.d/haresources":
source => "puppet:///modules/heartbeat/haresources",
notify => Exec["reload-heartbeat"],
require => Package["heartbeat"],
}
file { "/etc/ha.d/ha.cf":
source => "puppet:///modules/heartbeat/ha.cf",
notify => Exec["reload-heartbeat"],
require => Package["heartbeat"],
}
}
```
3. 使用如下内容创建 /etc/puppet/modules/heartbeat/files/haresources 文件。 将 cookbook 替换成你的主服务器的主机名。这可以通过在主服务器上运行 uname -n 命令获得。 将 10.0.2.100 替换成你要在两台主机上共享的 IP 地址(这应该是当前网络上还未使用的地址)。 最后列出的接口是分配给心跳检测的(本例中是 eth0:1)。
```
cookbook IPaddr::10.0.2.100/24/eth0:1
```
4. 使用如下内容创建 /etc/puppet/modules/heartbeat/files/authkeys 文件 (使用你自己选择的口令替换 topsecretpassword):
```
auth 1
1 sha1 topsecretpassword
```
5. 使用如下内容创建 /etc/puppet/modules/heartbeat/files/ha.cf 文件。 替换下面的两个 IP 地址为你自己的两台机器上 eth0 接口对应的 IP 地址。 同样需替换 cookbook 和 cookbook2 为你自己的两台机器的主机名(可以通过运行 uname -n 命令获得)。
```
autojoin none
ucast eth0 10.0.2.15
ucast eth0 10.0.2.16
keepalive 1
deadtime 10
warntime 5
udpport 694
auto_failback on
node cookbook
node cookbook2
use_logd yes
```
6. 在两台冗余服务器上都运行 Puppet:
```
# puppet agent --test
info: Retrieving plugin
info: Caching catalog for cookbook.bitfieldconsulting.com
info: Applying configuration version '1311440876'
notice: /Stage[main]/Heartbeat/Package[heartbeat]/ensure: created
notice: /Stage[main]/Heartbeat/File[/etc/ha.d/authkeys]/ensure:
defined content as '{md5}e908c869aabe519aa69acc9e51da3399'
info: /Stage[main]/Heartbeat/File[/etc/ha.d/authkeys]: Scheduling
refresh of Exec[reload-heartbeat]
notice: /Stage[main]/Heartbeat/File[/etc/ha.d/ha.cf]/ensure:
defined content as '{md5}a8d3fdd62a1172cdff150fc1d86d8a6b'
info: /Stage[main]/Heartbeat/File[/etc/ha.d/ha.cf]: Scheduling
refresh of Exec[reload-heartbeat]
notice: /Stage[main]/Heartbeat/File[/etc/ha.d/haresources]/ensure:
defined content as '{md5}0f25aefe7f6c4c8e81b3bb6c86a42d60'
info: /Stage[main]/Heartbeat/File[/etc/ha.d/haresources]:
Scheduling refresh of Exec[reload-heartbeat]
notice: /Stage[main]/Heartbeat/Exec[reload-heartbeat]: Triggered
'refresh' from 3 events
notice: Finished catalog run in 27.01 seconds
```
7. 在主服务器节点上,检查它的资源:
```
# cl_status rscstatus -m
This node is holding all resources.
```
8. 在辅助服务器节点上,你应该可以看到如下信息:
```
# cl_status rscstatus -m
This node is holding none resources.
```
9. 在主节点上禁用 Heartbeat 服务:
```
# service heartbeat stop
```
10. 辅助节点现在应该接管了资源:
```
# cl_status rscstatus -m
This node is holding all resources.
```
#### 工作原理
两台服务器上都运行了心跳守护进程,彼此监听心跳信号。 如果主服务器检测到辅助服务器已宕机,什么也不会发生。 而相反地,如果辅助服务器检测到主服务器已宕机,它就接管 IP 地址。 当主服务器恢复运行后,辅助服务器将再次放弃此地址,重新由主服务器接管 IP 地址 (如果 auto_failback 设置成了 on)。 在某些情况下,例如:如果你在主数据库服务器和从数据库服务器之间共享 IP 地址, 你可能不希望这种行为发生,在这种情况下应该将 auto_failback 设置成了 off。
#### 更多用法
现在你有一个共享的 IP 地址(真是名不副实,因为这个地址不是“共享”的,而是在两个服务器之间切换), 你可以用这个地址来提供高可用性的服务。例如,如果服务器是被托管的 web 站点, 你应该为 web 站点设置 DNS 记录指向这个共享的 IP 地址。 当主服务器宕机时,辅助服务器将接管 IP 地址并继续响应基于此地址的 HTTP 请求。
> ![提示](https://box.kancloud.cn/2016-05-12_5733eec6d55e1.png)
> 如果你正在使用 SSL 站点,你需要配置基于共享 IP 地址的 SSL 虚拟主机, 否则将不能响应基于这个 IP 的 HTTPs 请求。
另外,如果这个 web 站点使用了 sessions,主服务器上的任何 sessions 在故障转移后将会丢失, 除非 sessions 存储在一个分离的共享数据库中。
共享 IP 地址也是实现双路冗余负载均衡器的一种好方式 (参考 [使用 HAProxy 为多个 web 服务器实现负载均衡](#ch08sec04) 一节)。 你也可以使用这种方式为 Puppetmaster 主机提供冗余服务。 在 Puppet Labs 站点给出了一个合适的模式: [http://projects.puppetlabs.com/projects/1/wiki/High_Availability_Patterns](http://projects.puppetlabs.com/projects/1/wiki/High_Availability_Patterns) 。
- Puppet 2.7 Cookbook 中文版
- 中文翻译版
- 译者序
- 项目缘起
- 翻译方法
- 社区链接
- 社区建议
- 贡献者
- 原书版权页
- 关于作者
- 前言
- 本书内容
- 阅读前提
- 适用读者
- 格式约定
- 读者反馈
- 客户支持
- 下载案例代码
- 勘误表
- Puppet 基础设施
- 使用版本控制
- 使用提交钩子
- 使用 Rake 部署变更
- 配置 Puppet 的文件服务器
- 从 cron 运行 Puppet
- 使用自动签名
- 预签名证书
- 从 Puppet 的 filebucket 检索文件
- 使用 Passenger 扩展 Puppet 的部署规模
- 创建去中心化的分布式 Puppet 架构
- 监控、报告和排错
- 生成报告
- 通过 Email 发送包含特定标签的日志信息
- 创建图形化报告
- 自动生成 HTML 文档
- 绘制依赖关系图
- 测试你的 Puppet 配置清单
- 执行模拟运行
- 检测编译错误
- 理解 Puppet 的错误信息
- 显示命令的输出结果
- 输出调试信息
- 检查配置设置
- 使用标签
- 使用运行阶段
- 使用不同的环境
- Puppet 语言及其写作风格
- 使用 Puppet 社区规范
- 使用模块
- 使用标准的命名规范
- 使用嵌入式 Ruby 代码
- 使用纯 Ruby 代码书写配置清单
- 遍历多个项目
- 书写强大的条件语句
- 在 if 语句中使用正则表达式
- 使用选择器和 case 语句
- 检测字符串中是否包含指定的值
- 使用正则表达式替换
- 书写更优质的配置清单
- 使用资源的数组
- 使用 define 资源
- 指定资源的依赖关系
- 使用节点继承
- 使用类的继承和重载
- 给类传递参数
- 书写可重用的跨平台配置清单
- 获得系统的环境信息
- 导入动态信息
- 从 CSV 文件导入数据
- 给 Shell 命令传递参数
- 使用文件和软件包
- 为配置文件添加配置行
- 使用 Augeas 自动修改配置文件
- 使用配置片段构建配置文件
- 使用 ERB 模板
- 在模板中遍历数组
- 从第三方仓库安装软件包
- 配置 APT 软件仓库
- 配置 GEM 仓库
- 从源码包自动构建软件
- 比较软件包的版本
- 用户和虚拟资源
- 使用虚拟资源
- 使用虚拟资源管理用户
- 管理用户基于密钥的 SSH 访问
- 管理用户的自定义文件
- 有效地分发 cron 任务
- 当文件更新时运行命令
- 使用主机资源
- 为文件资源指定多个源
- 使用文件资源递归地分发整个目录树
- 清理过期的旧文件
- 使用日程表资源
- 资源的审计
- 临时禁用资源
- 管理时区
- 应用程序
- 管理 Apache 服务
- 创建 Apache 虚拟主机
- 创建 Nginx 虚拟主机
- 创建 MySQL 数据库及用户
- 管理 Drupal 站点
- 管理 Rails 应用程序
- 服务器和云基础设施
- 部署 Nagios 监控服务器
- 使用 Heartbeat 构建高可用服务
- 管理 NFS 服务和文件共享
- 使用 HAProxy 为多个 web 服务器实现负载均衡
- 使用 iptables 管理防火墙
- 管理 Amazon 的 EC2 实例
- 使用 Vagrant 管理虚拟机
- 外部工具和 Puppet 生态环境
- 创建 Facter 的自定义 fact
- 在运行 Puppet 之前和之后执行命令
- 从 Shell 会话生成 Puppet 配置清单
- 从运行的系统上生成 Puppet 配置清单
- 使用 Puppet Dashboard
- 使用 Foreman
- 使用 MCollective
- 使用公共模块
- 使用外部节点分类器
- 创建自定义的资源类型
- 创建自定义的提供者