You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

682 lines
28 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 41 | 软件部署实战IAM 系统生产环境部署实战
你好,我是孔令飞。
上一讲我介绍了IAM部署用到的两个核心组件Nginx和Keepalived。那么这一讲我们就来看下如何使用Nginx和Keepalived来部署一个高可用的IAM应用。下一讲我再介绍下IAM应用安全和弹性伸缩能力的构建方式。
这一讲我们会通过下面四个步骤来部署IAM应用
1. 在服务器上部署IAM应用中的服务。
2. 配置Nginx实现反向代理功能。通过反向代理我们可以通过Nginx来访问部署在内网的IAM服务。
3. 配置Nginx实现负载均衡功能。通过负载均衡我们可以实现服务的水平扩缩容使IAM应用具备高可用能力。
4. 配置Keepalived实现Nginx的高可用。通过Nginx + Keepalived的组合可以实现整个应用架构的高可用。
## 部署IAM应用
部署一个高可用的IAM应用需要至少两个节点。所以我们按照先后顺序分别在`10.0.4.20`和`10.0.4.21`服务器上部署IAM应用。
### 在`10.0.4.20`服务器上部署IAM应用
首先,我来介绍下如何在`10.0.4.20`服务器上部署IAM应用。
我们要在这个服务器上部署如下组件:
* iam-apiserver
* iam-authz-server
* iam-pump
* MariaDB
* Redis
* MongoDB
这些组件的部署方式,[03讲](https://time.geekbang.org/column/article/378082) 有介绍,这里就不再说明。
此外我们还需要设置MariaDB给来自于`10.0.4.21`服务器的数据库连接授权,授权命令如下:
```bash
$ mysql -hlocalhost -P3306 -uroot -proot # 先以root用户登陆数据库
MariaDB [(none)]> grant all on iam.* TO iam@10.0.4.21 identified by 'iam1234';
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.000 sec)
```
### 在`10.0.4.21`服务器上部署IAM应用
然后,在`10.0.4.21`服务器上安装好iam-apiserver、iam-authz-server 和 iam-pump。这些组件通过`10.0.4.20` IP地址连接`10.0.4.20`服务器上的MariaDB、Redis和MongoDB。
## 配置Nginx作为反向代理
假定要访问的API Server和IAM Authorization Server的域名分别为`iam.api.marmotedu.com`和`iam.authz.marmotedu.com`我们需要分别为iam-apiserver和iam-authz-server配置Nginx反向代理。整个配置过程可以分为5步在`10.0.4.20`服务器上操作)。
**第一步配置iam-apiserver。**
新建Nginx配置文件`/etc/nginx/conf.d/iam-apiserver.conf`,内容如下:
```plain
server {
    listen       80;
    server_name  iam.api.marmotedu.com;
    root         /usr/share/nginx/html;
    location / {
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass  http://127.0.0.1:8080/;
    client_max_body_size 5m;
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}
```
有几点你在配置时需要注意,这里说明下。
* `server_name`需要为`iam.api.marmotedu.com`,我们通过`iam.api.marmotedu.com`访问iam-apiserver。
* iam-apiserver默认启动的端口为`8080`。
* 由于Nginx默认允许客户端请求的最大单文件字节数为`1MB`实际生产环境中可能太小所以这里将此限制改为5MB`client_max_body_size 5m`)。如果需要上传图片之类的,可能需要设置成更大的值,比如`50m`。
* server\_name用来说明访问Nginx服务器的域名例如`curl -H 'Host: iam.api.marmotedu.com' http://x.x.x.x:80/healthz``x.x.x.x`为Nginx服务器的IP地址。
* proxy\_pass表示反向代理的路径。因为这里是本机的iam-apiserver服务所以IP为`127.0.0.1`。端口要和API服务端口一致为`8080`。
最后还要提醒下,因为 Nginx 配置选项比较多,跟实际需求和环境有关,所以这里的配置是基础的、未经优化的配置,在实际生产环境中需要你再做调节。
**第二步配置iam-authz-server。**
新建Nginx配置文件`/etc/nginx/conf.d/iam-authz-server.conf`,内容如下:
```plain
server {
    listen       80;
    server_name  iam.authz.marmotedu.com;
    root         /usr/share/nginx/html;
    location / {
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass  http://127.0.0.1:9090/;
    client_max_body_size 5m;
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}
```
下面是一些配置说明。
* server\_name需要为`iam.authz.marmotedu.com`,我们通过`iam.authz.marmotedu.com`访问iam-authz-server。
* iam-authz-server默认启动的端口为`9090`。
* 其他配置跟`/etc/nginx/conf.d/iam-apiserver.conf`一致。
**第三步配置完Nginx后重启Nginx**
```bash
$ sudo systemctl restart nginx
```
**第四步,在/etc/hosts中追加下面两行**
```bash
127.0.0.1 iam.api.marmotedu.com
127.0.0.1 iam.authz.marmotedu.com
```
**第五步发送HTTP请求**
```bash
$ curl http://iam.api.marmotedu.com/healthz
{"status":"ok"}
$ curl http://iam.authz.marmotedu.com/healthz
{"status":"ok"}
```
我们分别请求iam-apiserver和iam-authz-server的健康检查接口输出了`{"status":"ok"}`说明我们可以成功通过代理访问后端的API服务。
在用curl请求`http://iam.api.marmotedu.com/healthz`后,后端的请求流程实际上是这样的:
1. 因为在`/etc/hosts`中配置了`127.0.0.1 iam.api.marmotedu.com`,所以请求`http://iam.api.marmotedu.com/healthz`实际上是请求本机的Nginx端口`127.0.0.1:80`)。
2. Nginx在收到请求后会解析请求得到请求域名为`iam.api.marmotedu.com`。根据请求域名去匹配 Nginx的server配置匹配到`server_name iam.api.marmotedu.com;`配置。
3. 匹配到server后把请求转发到该server的`proxy_pass`路径。
4. 等待API服务器返回结果并返回客户端。
## 配置Nginx作为负载均衡
这门课采用Nginx轮询的负载均衡策略转发请求。负载均衡需要至少两台服务器所以会分别在`10.0.4.20`和`10.0.4.21`服务器上执行相同的操作。下面我分别来介绍下如何配置这两台服务器,并验证配置是否成功。
### `10.0.4.20`服务器配置
登陆`10.0.4.20`服务器,在`/etc/nginx/nginx.conf`中添加upstream配置配置过程可以分为3步。
**第一步,在**`/etc/nginx/nginx.conf`**中添加upstream**
```plain
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
    upstream iam.api.marmotedu.com {
        server 127.0.0.1:8080
        server 10.0.4.21:8080
    }
    upstream iam.authz.marmotedu.com {
        server 127.0.0.1:9090
        server 10.0.4.21:9090
    }
}
```
配置说明:
* upstream是配置在`/etc/nginx/nginx.conf`文件中的`http{ … }`部分的。
* 因为我们要分别为iam-apiserver和iam-authz-server配置负载均衡所以我们创建了两个upstream分别是`iam.api.marmotedu.com`和`iam.authz.marmotedu.com`。为了便于识别upstream名称和域名最好保持一致。
* 在upstream中我们需要分别添加所有的iam-apiserver和iam-authz-server的后端`ip:port`),本机的后端为了访问更快,可以使用`127.0.0.1:<port>`,其他机器的后端,需要使用`<内网>:port`,例如`10.0.4.21:8080`、`10.0.4.21:9090`。
**第二步修改proxy\_pass。**
修改`/etc/nginx/conf.d/iam-apiserver.conf`文件,将`proxy_pass`修改为:
```plain
proxy_pass http://iam.api.marmotedu.com/;
```
修改`/etc/nginx/conf.d/iam-authz-server.conf`文件,将`proxy_pass`修改为:
```plain
proxy_pass http://iam.authz.marmotedu.com/;
```
当Nginx转发到`http://iam.api.marmotedu.com/`域名时,会从`iam.api.marmotedu.com` upstream配置的后端列表中根据负载均衡策略选取一个后端并将请求转发过去。转发`http://iam.authz.marmotedu.com/`域名的逻辑也一样。
**第三步配置完Nginx后重启Nginx**
```bash
$ sudo systemctl restart nginx
```
最终配置好的配置文件,你可以参考下面这些(保存在[configs/ha/10.0.4.20](https://github.com/marmotedu/iam/tree/v1.0.8/configs/ha/10.0.4.20)目录下):
* nginx.conf[configs/ha/10.0.4.20/nginx.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.20/nginx.conf)。
* iam-apiserver.conf[configs/ha/10.0.4.20/iam-apiserver.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.20/iam-apiserver.conf)。
* iam-authz-server.conf[configs/ha/10.0.4.20/iam-authz-server.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.20/iam-authz-server.conf)。
### `10.0.4.21`服务器配置
登陆`10.0.4.21`服务器,在`/etc/nginx/nginx.conf`中添加upstream配置。配置过程可以分为下面4步。
**第一步,在**`/etc/nginx/nginx.conf`**中添加upstream**
```plain
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
    upstream iam.api.marmotedu.com {
        server 127.0.0.1:8080
        server 10.0.4.20:8080
    }
    upstream iam.authz.marmotedu.com {
        server 127.0.0.1:9090
        server 10.0.4.20:9090
    }
}
```
upstream中需要配置`10.0.4.20`服务器上的iam-apiserver和iam-authz-server的后端例如`10.0.4.20:8080`、`10.0.4.20:9090`。
**第二步,创建**`/etc/nginx/conf.d/iam-apiserver.conf`**文件**iam-apiserver的反向代理+负载均衡配置),内容如下:
```plain
server {
    listen       80;
    server_name  iam.api.marmotedu.com;
    root         /usr/share/nginx/html;
    location / {
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass  http://iam.api.marmotedu.com/;
    client_max_body_size 5m;
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}
```
**第三步,创建**`/etc/nginx/conf.d/iam-authz-server`**文件**iam-authz-server的反向代理+负载均衡配置),内容如下:
```plain
server {
    listen       80;
    server_name  iam.authz.marmotedu.com;
    root         /usr/share/nginx/html;
    location / {
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass  http://iam.authz.marmotedu.com/;
    client_max_body_size 5m;
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}
```
**第四步配置完Nginx后重启Nginx**
```bash
$ sudo systemctl restart nginx
```
最终配置好的配置文件,你可以参考下面这些(保存在[configs/ha/10.0.4.21](https://github.com/marmotedu/iam/tree/v1.0.8/configs/ha/10.0.4.21)目录下):
* nginx.conf[configs/ha/10.0.4.21/nginx.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.21/nginx.conf)。
* iam-apiserver.conf[configs/ha/10.0.4.21/iam-apiserver.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.21/iam-apiserver.conf)。
* iam-authz-server.conf[configs/ha/10.0.4.21/iam-authz-server.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.21/iam-authz-server.conf)。
### 测试负载均衡
上面我们配置了Nginx负载均衡器这里我们还需要测试下是否配置成功。
**第一步,执行测试脚本(**[test/nginx/loadbalance.sh](https://github.com/marmotedu/iam/blob/v1.0.8/test/nginx/loadbalance.sh)****
```bash
#!/usr/bin/env bash
for domain in iam.api.marmotedu.com iam.authz.marmotedu.com
do
for n in $(seq 1 1 10)
do
echo $domain
nohup curl http://${domain}/healthz &>/dev/null &
done
done
```
**第二步分别查看iam-apiserver和iam-authz-server的日志。**
这里我展示下iam-apiserver的日志iam-authz-server的日志你可自行查看
`10.0.4.20`服务器的iam-apiserver日志如下图所示
![图片](https://static001.geekbang.org/resource/image/58/26/58d072c92552fa3068e3ef3acd0ed726.png?wh=1920x498)
`10.0.4.21`服务器的iam-apiserver日志如下图所示
![图片](https://static001.geekbang.org/resource/image/19/85/199066c65ff60007f80f3c2dyy11c785.png?wh=1920x482)
通过上面两张图,你可以看到`10.0.4.20`和`10.0.4.21`各收到`5`个`/healthz`请求,说明负载均衡配置成功。
## 配置Keepalived
在 [40讲](https://time.geekbang.org/column/article/411663),我们分别在`10.0.4.20`和`10.0.4.21`服务器上安装了Keepalived。这里我来介绍下如何配置Keepalived实现Nginx的高可用。为了避免故障恢复时VIP切换造成的服务延时这一讲采用Keepalived的非抢占模式。
配置Keepalived的流程比较复杂分为创建腾讯云HAVIP、主服务器配置、备服务器配置、测试Keepalived、VIP绑定公网IP和测试公网访问六大步每一步中都有很多小步骤下面我们来一步步地看下。
### **第一步创建腾讯云HAVIP**
公有云厂商的普通内网IP出于安全考虑如避免ARP欺骗等不支持主机通过ARP宣告IP 。如果用户直接在`keepalived.conf`文件中指定一个普通内网IP为virtual IP当Keepalived将virtual IP从MASTER机器切换到BACKUP机器时将无法更新IP和MAC地址的映射而需要调API来进行IP切换。所以这里的VIP需要申请腾讯云的HAVIP。
申请的流程可以分为下面4步
1. 登录私有网络控制台**。**
2. 在左侧导航栏中选择【IP与网卡】>【高可用虚拟IP】。
3. 在HAVIP管理页面选择所在地域单击【申请】。
4. 在弹出的【申请高可用虚拟IP】对话框中输入名称选择HAVIP所在的私有网络和子网等信息单击【确定】即可。
这里选择的私有网络和子网,需要和`10.0.4.20`、`10.0.4.21`相同。HAVIP 的 IP 地址可以自动分配也可以手动填写这里我们手动填写为10.0.4.99。申请页面如下图所示:
![图片](https://static001.geekbang.org/resource/image/a4/11/a49d6e7e080d658392dbb144a1560811.png?wh=827x1016)
### 第二步:主服务器配置
进行主服务器配置,可以分为两步。
**首先修改Keepalived配置文件。**
登陆服务器`10.0.4.20`,编辑`/etc/keepalived/keepalived.conf`,修改配置,修改后配置内容如下(参考:[configs/ha/10.0.4.20/keepalived.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.20/keepalived.conf)
```bash
# 全局定义,定义全局的配置选项
global_defs {
# 指定keepalived在发生切换操作时发送email发送给哪些email
# 建议在keepalived_notify.sh中发送邮件
notification_email {
acassen@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc # 发送email时邮件源地址
smtp_server 192.168.200.1 # 发送email时smtp服务器地址
smtp_connect_timeout 30 # 连接smtp的超时时间
router_id VM-4-20-centos # 机器标识通常可以设置为hostname
vrrp_skip_check_adv_addr # 如果接收到的报文和上一个报文来自同一个路由器,则不执行检查。默认是跳过检查
vrrp_garp_interval 0 # 单位秒在一个网卡上每组gratuitous arp消息之间的延迟时间默认为0
vrrp_gna_interval 0 # 单位秒在一个网卡上每组na消息之间的延迟时间默认为0
}
# 检测脚本配置
vrrp_script checkhaproxy
{
script "/etc/keepalived/check_nginx.sh" # 检测脚本路径
interval 5 # 检测时间间隔(秒)
weight 0 # 根据该权重改变priority当值为0时不改变实例的优先级
}
# VRRP实例配置
vrrp_instance VI_1 {
state BACKUP # 设置初始状态为'备份'
interface eth0 # 设置绑定VIP的网卡例如eth0
virtual_router_id 51 # 配置集群VRID互为主备的VRID需要是相同的值
nopreempt # 设置非抢占模式只能设置在state为backup的节点上
priority 100 # 设置优先级值范围0254值越大优先级越高最高的为master
advert_int 1 # 组播信息发送时间间隔两个节点必须设置一样默认为1秒
# 验证信息,两个节点必须一致
authentication {
auth_type PASS # 认证方式可以是PASS或AH两种认证方式
auth_pass 1111 # 认证密码
}
unicast_src_ip 10.0.4.20 # 设置本机内网IP地址
unicast_peer {
10.0.4.21 # 对端设备的IP地址
}
# VIP当state为master时添加当state为backup时删除
virtual_ipaddress {
10.0.4.99 # 设置高可用虚拟VIP如果是腾讯云的CVM需要填写控制台申请到的HAVIP地址。
}
notify_master "/etc/keepalived/keepalived_notify.sh MASTER" # 当切换到master状态时执行脚本
notify_backup "/etc/keepalived/keepalived_notify.sh BACKUP" # 当切换到backup状态时执行脚本
notify_fault "/etc/keepalived/keepalived_notify.sh FAULT" # 当切换到fault状态时执行脚本
notify_stop "/etc/keepalived/keepalived_notify.sh STOP" # 当切换到stop状态时执行脚本
garp_master_delay 1 # 设置当切为主状态后多久更新ARP缓存
garp_master_refresh 5 # 设置主节点发送ARP报文的时间间隔
# 跟踪接口,里面任意一块网卡出现问题,都会进入故障(FAULT)状态
track_interface {
eth0
}
# 要执行的检查脚本
track_script {
checkhaproxy
}
}
```
这里有几个注意事项:
* 确保已经配置了garp相关参数。因为Keepalived依赖ARP报文更新IP信息如果缺少这些参数会导致某些场景下主设备不发送ARP进而导致通信异常。garp相关参数配置如下
```plain
garp_master_delay 1
garp_master_refresh 5
```
* 确定没有采用 strict 模式即需要删除vrrp\_strict配置。
* 配置中的`/etc/keepalived/check_nginx.sh`和`/etc/keepalived/keepalived_notify.sh`脚本文件,可分别拷贝自[scripts/check\_nginx.sh](https://github.com/marmotedu/iam/blob/v1.0.8/scripts/check_nginx.sh)和[scripts/keepalived\_notify.sh](https://github.com/marmotedu/iam/blob/v1.0.8/scripts/keepalived_notify.sh)。
**然后重启Keepalived**
```bash
$ sudo systemctl restart keepalived
```
### 第三步:备服务器配置
进行备服务器配置也分为两步。
**首先修改Keepalived配置文件。**
登陆服务器`10.0.4.21`,编辑`/etc/keepalived/keepalived.conf`,修改配置,修改后配置内容如下(参考:[configs/ha/10.0.4.21/keepalived.conf](https://github.com/marmotedu/iam/blob/v1.0.8/configs/ha/10.0.4.21/keepalived.conf)
```plain
# 全局定义,定义全局的配置选项
global_defs {
# 指定keepalived在发生切换操作时发送email发送给哪些email
# 建议在keepalived_notify.sh中发送邮件
  notification_email {
    acassen@firewall.loc
  }
  notification_email_from Alexandre.Cassen@firewall.loc # 发送email时邮件源地址
    smtp_server 192.168.200.1 # 发送email时smtp服务器地址
    smtp_connect_timeout 30 # 连接smtp的超时时间
    router_id VM-4-21-centos # 机器标识通常可以设置为hostname
    vrrp_skip_check_adv_addr # 如果接收到的报文和上一个报文来自同一个路由器,则不执行检查。默认是跳过检查
    vrrp_garp_interval 0 # 单位秒在一个网卡上每组gratuitous arp消息之间的延迟时间默认为0
    vrrp_gna_interval 0 # 单位秒在一个网卡上每组na消息之间的延迟时间默认为0
}
# 检测脚本配置
vrrp_script checkhaproxy
{
  script "/etc/keepalived/check_nginx.sh" # 检测脚本路径
    interval 5 # 检测时间间隔(秒)
    weight 0 # 根据该权重改变priority当值为0时不改变实例的优先级
}
# VRRP实例配置
vrrp_instance VI_1 {
  state BACKUP  # 设置初始状态为'备份'
    interface eth0 # 设置绑定VIP的网卡例如eth0
    virtual_router_id 51  # 配置集群VRID互为主备的VRID需要是相同的值
    nopreempt               # 设置非抢占模式只能设置在state为backup的节点上
    priority 50 # 设置优先级值范围0254值越大优先级越高最高的为master
    advert_int 1 # 组播信息发送时间间隔两个节点必须设置一样默认为1秒
# 验证信息,两个节点必须一致
    authentication {
      auth_type PASS # 认证方式可以是PASS或AH两种认证方式
        auth_pass 1111 # 认证密码
    }
  unicast_src_ip 10.0.4.21  # 设置本机内网IP地址
    unicast_peer {
      10.0.4.20             # 对端设备的IP地址
    }
# VIP当state为master时添加当state为backup时删除
  virtual_ipaddress {
    10.0.4.99 # 设置高可用虚拟VIP如果是腾讯云的CVM需要填写控制台申请到的HAVIP地址。
  }
  notify_master "/etc/keepalived/keepalived_notify.sh MASTER" # 当切换到master状态时执行脚本
    notify_backup "/etc/keepalived/keepalived_notify.sh BACKUP" # 当切换到backup状态时执行脚本
    notify_fault "/etc/keepalived/keepalived_notify.sh FAULT" # 当切换到fault状态时执行脚本
    notify_stop "/etc/keepalived/keepalived_notify.sh STOP" # 当切换到stop状态时执行脚本
    garp_master_delay 1    # 设置当切为主状态后多久更新ARP缓存
    garp_master_refresh 5   # 设置主节点发送ARP报文的时间间隔
    # 跟踪接口,里面任意一块网卡出现问题,都会进入故障(FAULT)状态
    track_interface {
      eth0
    }
  # 要执行的检查脚本
  track_script {
    checkhaproxy
  }
}
```
**然后重启Keepalived**
```bash
$ sudo systemctl restart keepalived
```
### 第四步测试Keepalived
上面的配置中,`10.0.4.20`的优先级更高,所以正常情况下`10.0.4.20`将被选择为主节点,如下图所示:
![图片](https://static001.geekbang.org/resource/image/54/79/54968f40707b779e2ab70d3ab5a53479.png?wh=1920x500)
接下来,我们分别模拟一些故障场景,来看下配置是否生效。
**场景1Keepalived故障**
在`10.0.4.20`服务器上执行`sudo systemctl stop keepalived`模拟Keepalived故障查看VIP如下图所示
![图片](https://static001.geekbang.org/resource/image/2a/ee/2a57e958bd9fce3b9c842c1cf09c48ee.png?wh=1920x544)
可以看到VIP从`10.0.4.20`服务器上,漂移到了`10.0.4.21`服务器上。查看`/var/log/keepalived.log`,可以看到`10.0.4.20`服务器新增如下一行日志:
```plain
[2020-10-14 14:01:51] notify_stop
```
`10.0.4.21`服务器新增如下日志:
```plain
[2020-10-14 14:01:52] notify_master
```
**场景2Nginx故障**
在`10.0.4.20`和`10.0.4.21`服务器上分别执行`sudo systemctl restart keepalived`让VIP漂移到`10.0.4.20`服务器上。
在`10.0.4.20`服务器上,执行 `sudo systemctl stop nginx` 模拟Nginx故障查看VIP如下图所示
![图片](https://static001.geekbang.org/resource/image/2a/ee/2a57e958bd9fce3b9c842c1cf09c48ee.png?wh=1920x544)
可以看到VIP从`10.0.4.20`服务器上,漂移到了`10.0.4.21`服务器上。查看`/var/log/keepalived.log`,可以看到`10.0.4.20`服务器新增如下一行日志:
```plain
[2020-10-14 14:02:34] notify_fault
```
`10.0.4.21` 服务器新增如下日志:
```plain
[2020-10-14 14:02:35] notify_master
```
**场景3Nginx恢复**
基于**场景2**,在`10.0.4.20`服务器上执行`sudo systemctl start nginx`恢复Nginx查看VIP如下图所示
![图片](https://static001.geekbang.org/resource/image/2a/ee/2a57e958bd9fce3b9c842c1cf09c48ee.png?wh=1920x544)
可以看到VIP仍然在`10.0.4.21`服务器上,没有被`10.0.4.20`抢占。查看`/var/log/keepalived.log`,可以看到`10.0.4.20`服务器新增如下一行日志:
```plain
[2020-10-14 14:03:44] notify_backup
```
`10.0.4.21`服务器没有新增日志。
### 第五步VIP绑定公网IP
到这里我们已经成功配置了Keepalived + Nginx的高可用方案。但是我们的VIP是内网还不能通过外网访问。这时候我们需要将VIP绑定一个外网IP供外网访问。在腾讯云上可通过绑定弹性公网IP来实现外网访问需要先申请公网IP然后将VIP绑定弹性公网IP。下面我来讲讲具体步骤。
申请公网IP
1. 登录**私有网络控制台。**
2. 在左侧导航栏中选择【IP与网卡】>【弹性公网IP】。
3. 在弹性公网IP管理页面选择所在地域单击【申请】。
将VIP绑定弹性公网IP
1. 登录**私有网络控制台**。
2. 在左侧导航栏中选择【IP与网卡】>【高可用虚拟】。
3. 单击需要绑定的HAVIP所在行的【绑定】。
4. 在弹出界面中选择需要绑定的公网IP即可如下图所示
![图片](https://static001.geekbang.org/resource/image/83/62/83bc9f4595325e9d339e7c3269aa3462.png?wh=1388x666)
绑定的弹性公网IP是`106.52.252.139`。
这里提示下腾讯云平台中如果HAVIP没有绑定实例绑定HAVIP的EIP会处于闲置状态按`¥0.2/小时` 收取闲置费用。所以,你需要正确配置高可用应用,确保绑定成功。
### 第六步:测试公网访问
最后,你可以通过执行如下命令来测试:
```bash
$ curl -H"Host: iam.api.marmotedu.com" http://106.52.252.139/healthz -H"iam.api.marmotedu.com"
{"status":"ok"}
```
可以看到我们可以成功通过公网访问后端的高可用服务。到这里我们成功部署了一个可用性很高的IAM应用。
## 总结
今天我主要讲了如何使用Nginx和Keepalived来部署一个高可用的IAM应用。
为了部署一个高可用的IAM应用我们至少需要两台服务器并且部署相同的服务iam-apiserver、iam-authz-server、iam-pump。而且选择其中一台服务器部署数据库服务MariaDB、Redis、MongoDB。
为了安全和性能iam-apiserver、iam-authz-server、iam-pump服务都是通过内网来访问数据库服务的。这一讲我还介绍了如何配置Nginx来实现负载均衡如何配置Keepalived来实现Nginx的高可用。
## 课后练习
1. 思考下当前部署架构下如果iam-apiserver需要扩容可以怎么扩容
2. 思考下当VIP切换时如何实现告警功能给系统运维人员告警
欢迎你在留言区与我交流讨论,我们下一讲见。