
示例集群有三个主节点,以及一个虚拟 IP 地址。本示例中的虚拟 IP 地址也可称为“浮动 IP 地址”。这意味着在节点故障的情况下,该 IP 地址可在节点之间漂移,从而实现高可用。

Keepalived 提供 VRRP 实现,并允许您配置 Linux 机器使负载均衡,预防单点故障。HAProxy 提供可靠、高性能的负载均衡,能与 Keepalived 完美配合。
由于在所有集群上安装了 Keepalived 和 HAproxy,如果其中一个节点故障,虚拟 IP 地址(即浮动 IP 地址)将自动与另一个节点关联,使集群仍然可以正常运行,从而实现高可用。若扩展集群,可以继续 添加更多安装 Keepalived 和 HAproxy 的节点。
yum install -y haproxy keepalived
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
zhanglu90@126.com
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_1
vrrp_skip_check_adv_addr
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI-kube-master {
state MASTER #需要将状态设置为(MASTER)
interface eno1 #这个地方需要特别注意,一个服务器有很多虚拟网卡,而这个网卡是真实网卡,可以通过ifconfig 命令查看你服务器中的名字,我的服务器中ip地址对应的网卡名称就是eno1 ,这个不能写错
virtual_router_id 51 #这个id可以是其他数字,但是该数字必须在master和node中要保持一致,也可以照我这个写,不需要修改的
priority 100 #权重设置,数值大的选为master 节点
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.41.39.206 # vip #这个就是虚拟出来的ip了,简称VIP,需要确保集群环境中不能有ip与这个vip冲突,其次需要确定该vip能和集群中所有节点ping的通
}
}
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
zhanglu90@126.com
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_1
vrrp_skip_check_adv_addr
# vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI-kube-master {
state BACKUP #此处需要设置为备份状态(BACKUP)
interface eno1 #这个地方需要特别注意,一个服务器有很多虚拟网卡,而这个网卡是真实网卡,可以通过ifconfig 命令查看你服务器中的名字,我的服务器中ip地址对应的网卡名称就是eno1 ,这个不能写错
virtual_router_id 51 #这个id可以是其他数字,但是该数字必须在master和node中要保持一致,也可以照我这个写,不需要修改的
priority 80 #权重设置,数值大的选为master 节点
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.41.39.206 # vip #这个就是虚拟出来的ip了,简称VIP,需要确保集群环境中不能有ip与这个vip冲突,其次需要确定该vip能和集群中所有节点ping的通
}
}
更多关于企业集群运维管理系列的学习文章,请参阅:玩转企业集群运维管理专栏,本系列持续更新中。
#启动
systemctl start keepalived
#查看状态
systemctl status keepalived
#设置开机自启
systemctl enable keepalived
HAProxy 在 TCP Mode 下,从 Haproxy 向 Nginx 传递客户端真实网络地址

配置其实不用添加什么,只是在最后的listen <- sase-service-nginx 和 listen <-sase-customer-nginx 的server里的最后面添加上了send-proxy-v2-ssl-cn 参数,这样HA就把proxy protocol协议发送到后端Nginx上了。
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /var/run/haproxy-admin.sock mode 660 level admin
stats timeout 30s
user root #启动用户
group root #启动用户组
daemon
nbproc 1
defaults
log global
timeout connect 5000
timeout client 10m
timeout server 10m
listen admin_stats
bind 0.0.0.0:16688 #这里需要设置一个不和其他程序冲突的端口,查看端口是否占用:netstat -anp| grep 10080
mode http
log 127.0.0.1 local0 err
stats refresh 30s
stats uri /status
stats realm welcome login\ Haproxy
stats auth admin:123456
stats hide-version
stats admin if TRUE
# 业务下游 nginx 转发配置 ,nginx 部署在 k8s 中
listen sase-service-nginx
mode tcp
bind *:9443 #这里需要设置一个不和其他程序冲突的端口,查看端口是否占用:netstat -anp| grep 9443
balance roundrobin # 调度算法,使用轮询
# 下游nginx 地址并开启 proxy protocol 代理协议 send-proxy-v2-ssl-cn
server nginx-01 10.41.39.195:31498 send-proxy-v2-ssl-cn weight 1 maxconn 10000 check inter 10s
server nginx-01 10.41.39.196:31498 send-proxy-v2-ssl-cn weight 1 maxconn 10000 check inter 10s
server nginx-01 10.41.39.197:31498 send-proxy-v2-ssl-cn weight 1 maxconn 10000 check inter 10s
listen sase-customer-nginx
mode tcp
bind *:443 #这里需要设置一个不和其他程序冲突的端口,查看端口是否占用:netstat -anp| grep 7443
balance roundrobin
# 下游nginx 地址并开启 proxy protocol 代理协议 send-proxy-v2-ssl-cn
server nginx-01 10.41.39.195:31134 send-proxy-v2-ssl-cn weight 1 maxconn 10000 check inter 10s
server nginx-01 10.41.39.196:31134 send-proxy-v2-ssl-cn weight 1 maxconn 10000 check inter 10s
server nginx-01 10.41.39.197:31134 send-proxy-v2-ssl-cn weight 1 maxconn 10000 check inter 10s
注意,「PROXY协议」由两个版本,对应的HAProxy中的配置为send-proxy与send-proxy-v2指令,这是用于HTTP协议的。如果是HTTPS协议要使用send-proxy-v2-ssl或者send-proxy-v2-ssl-cn指令。我们用的https 协议,所以配置为send-proxy-v2-ssl-cn。
通过「PROXY协议」传递给Nginx的信息是客户端IP地址、代理服务器IP地址、两个端口号。接下来就是配置Nginx服务接受PROXY协议。
📢:haproxy 要监听1024 以下的端口需要用root 用户与root用户组启动,否则无法监听到端口。更多关于企业集群运维管理系列的学习文章,请参阅:玩转企业集群运维管理专栏,本系列持续更新中。
#启动
systemctl start haproxy
#查看状态
systemctl status haproxy
#设置开机自启
systemctl enable haproxy
通常web应用获取用户客户端的真实ip一个很常见的需求,例如将用户真实ip取到之后对用户做白名单访问限制、将用户ip记录到数据库日志中对用户的操作做审计等等。
k8s中运行的应用通过Service抽象来互相查找、通信和与外部世界沟通,在k8s中是kube-proxy组件实现了Service的通信与负载均衡,流量在传递的过程中经过了源地址转换SNAT,因此在默认的情况下,常常是拿不到用户真实的ip的。
获取不到客户端真实 IP 的原因是 SNAT 使得访问 SVC 的源 IP 发生了变化。将服务的 externalTrafficPolicy 改为 Local 模式可以解决这个问题。将服务的 externalTrafficPolicy 设置为 Local 模式:

Cluster 隐藏了客户端源 IP,可能导致第二跳到另一个节点,但具有良好的整体负载分布。Local 保留客户端源 IP 并避免 LoadBalancer 和 NodePort 类型服务的第二跳,但存在潜在的不均衡流量传播风险。

当请求落到没有服务 Pod 的节点时,将无法访问。用 curl 访问时,会一直停顿在 TCP_NODELAY , 然后提示超时:

在生产环境,通常会有多个节点同时接收客户端的流量,如果仅使用 Local 模式将会导致服务可访问性变低。引入 HAproxy 的目的是为了利用其探活的特点,仅将流量转发到存在服务 Pod 的节点上,提高集群的可用性,并且通过Proxy Protocol 代理协议来透传客户端IP。
Proxy Protocol是HAProxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取用户真实IP时非常有用:
其本质是在三次握手结束后由代理在连接中插入了一个携带了原始连接四元组信息的数据包。目前Proxy Protocol有两个版本,v1仅支持human-readable报头格式(ASCIII码),v2需同时支持human-readable和二进制格式,即需要兼容v1格式。
代理协议分为v1和v2两个版本,v1人类易读,v2是二进制格式,方便程序处理。Proxy protocol是比较新的协议,但目前已经有很多软件支持,如haproxy、nginx、apache、squid、mysql等等,要使用proxy protocol需要两个角色sender和receiver,sender在与receiver之间建立连接后,会先发送一个带有客户信息的tcp header,因为更改了tcp协议,需receiver也支持proxy protocol,否则不能识别tcp包头,导致无法成功建立连接。
目前,HAProxy已经将客户端的IP地址通过PROXY协议发送给Nginx服务了。接下来就是在Nginx中获取客户端的IP地址,有两种办法:
proxy_protocol_addr和proxy_protocol_port变量捕获原始客户端IP地址和端口。remote_addr和remote_port变量捕获HAProxy的IP地址和端口。remote_addr和remote_port变量的值,用客户端IP地址和端口替换负载均衡的IP地址和端口;而 realip_remote_addr和realip_remote_port变量保留负载均衡的IP地址和端口;proxy_protocol_addr和proxy_protocol_port变量保留原始客户端IP地址和端口。这对Nginx也有所要求:
server {
charset utf-8;
listen [::]:443 default_server ssl ipv6only=on proxy_protocol; # proxy_protocol
listen 0.0.0.0:443 default_server ssl proxy_protocol;
location ^~ /v1/ {
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
proxy_set_header Host $http_host;
proxy_pass http://backend/v1/;
}
}
有一点需要说明,指令set_real_ip_from的参数为负载均衡的IP地址或网段。该参数标记出负载均衡的网段,然后Nginx会进行递归排除,递归排除之后剩下的IP地址就是客户端的IP地址。这个地方不要配置错了。更多关于企业集群运维管理系列的学习文章,请参阅:玩转企业集群运维管理专栏,本系列持续更新中。
本文介绍了如何在k8s 集群中 haproxy+keepalived 为集群总代理,以及使用俩种获取真实 IP 的部署方式。
受制于 Local 模式,可能会导致服务不可访问。需要保证对外提供入口的节点上,必须具有服务的负载。
利用 haproxy 的探活能力,能够提高服务的可访问性。
以上就是今天给大家分享的 k8s 集群使用 haproxy+keepalived+nginx 实现k8s集群负载均衡。
参考来源:https://blog.csdn.net/zhanglu0302/article /details/128066710