边侧高可用解决方案
边侧服务高可用其实就是当年服务还没上云的时候,使用的那套技术栈。不过稍微有些不同的是,边缘计算需要考虑完全封闭的局域网,有点像组态软件的场景。
基于域名
本地域名一般使用.local
/.lan
之类的后缀,避免和.com
等云上域名冲突。
基于域名的高可用显然需要依赖DNS来解决,简单的思路就是:
- 为私有域名配置多个后端host ip;
- 私有域名自动探测后端的存活性(即健康检查);
- 当DNS解析的请求过来时,如果是配置的私有域名(或其子域名),则随机(或者其他负载均衡策略)返回一个健康的ip地址;
这个需求最简单的解决方案是使用CoreDNS的插件机制自己写一个插件,存活探测使用ping即可。
基于虚拟IP
这个其实也是成熟技术栈,就是基于LVS的Keepalived. 不过要注意的是这玩意仅支持Linux,Windows平台可以考虑使用WSFC(Windows Server Failover Clustering)来实现类似的功能。不过该组件也是仅支持windows server,普通的家用操作系统是不行的。
Keepalived原理概述
Keepalived底层基于linux内核中的IPVS,即LVS模块,后者提供了负载均衡的功能。Keepalived则主要基于VRRP协议(即虚拟路由冗余协议)解决了高可用(单点故障)问题。
在多个节点上安装Keepalived,通过配置使其中一个成为master,其他结点都是backup. 外部服务通过master节点的**虚拟IP(vip)**地址访问结点上的服务。如果边侧是k3s环境,由于自带了LoadBalancer,所以只要指向任意一个k3s结点都可以访问暴露出来的服务。所以可以在k3s的server节点上都装上keepalived, 第一台初始化成功的作为master,其他的作为backup即可。
当master节点宕机时,backup节点会根据配置选举出新的master,这个新的master接管了vip,所以客户端访问该vip的流量就会自动切换过来。
vrrp设计是给路由器使用的,是将多个路由器视为一个路由器,所以它的算法其实比较简单,见下图:
默认情况下,所有节点之间通过UDP组播通信,如果在云上也可以改为单播。选举主要需要配置的参数是抢占策略和优先级数值。
需要注意的是,存在多个master的可能性,不过对于k3s而言这个问题不大。k3s的server节点本来就是等价的,对于LoadBalancer服务而言更是如此。
配置示例
一个比较简单的配置如下:
global_defs {
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state BACKUP # 建议都设成BACKUP,不要直接指定MASTER
nopreempt # 不抢占,避免来回切换master
interface enp3s0 # 真实网卡的名称
virtual_router_id 51 # VRID标记,多个集群不能重复
priority 80 # 优先级,建议配置的不同
advert_int 1 # 检测的默认时间,默认1s
authentication { # 认证
auth_type PASS
auth_pass 1111 # 同一个集群内的认证密码应该一样
}
virtual_ipaddress { # 设置VIP,一般一个就行了
172.16.11.111
}
}
virtual_server 172.16.11.111 { # VIP与真实IP的映射配置,可以具体到端口
protocol * # 支持所有协议,可选TCP/UDP/SCTP
real_server 172.16.11.66 { # 真实网卡的ip地址
weight 1
}
}
如果仅仅是为了将虚拟ip的流量转发到真实ip,上面的配置就够用了。主要需要修改的就是主机的网卡名称和真实ip,以及虚拟的ip地址。
启动命令:keepalived -f /etc/keepalived/keepalived.conf
,建议设置systemd启动:
[Unit]
Description=LVS and VRRP High Availability Monitor
After=syslog.target network.target
[Service]
Type=forking
PIDFile=/var/run/keepalived.pid
KillMode=control-group
ExecStart=/usr/sbin/keepalived -D -f /etc/keepalived/keepalived.conf
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
[Install]
WantedBy=multi-user.target
静态编译方法
官方只提供了源码,可以使用docker buildx来完成静态编译,Dockerfile
如下:
FROM alpine as build
RUN if [ -f /etc/apk/repositories ];then sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories; fi && \
if [ -f /etc/apt/sources.list ];then sed -ri 's/(deb|security).debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list; fi && \
if [ ! -e /etc/nsswitch.conf ];then echo 'hosts: files dns myhostname' > /etc/nsswitch.conf; fi && \
apk --no-cache add \
binutils \
file \
file-dev \
gcc \
glib \
glib-dev \
ipset \
ipset-dev \
iptables \
iptables-dev \
libmnl-dev \
libnftnl-dev \
libnl3 \
libnl3-dev \
make \
musl-dev \
net-snmp-dev \
openssl \
openssl-dev \
openssl-libs-static \
pcre2 \
pcre2-dev \
autoconf \
automake zlib-static alpine-sdk linux-headers libmnl-static
WORKDIR /opt
RUN wget http://ghproxy.com/https://github.com/acassen/keepalived/archive/refs/tags/v2.2.8.tar.gz && tar xzvf v2.2.8.tar.gz && mv ./keepalived-2.2.8 /opt/keepalived
RUN set -ex && \
cd /opt/keepalived && \
./autogen.sh && \
CFLAGS='-static -s' LDFLAGS=-static ./configure --disable-dynamic-linking \
--prefix=/usr \
--exec-prefix=/usr \
--bindir=/usr/bin \
--sbindir=/usr/sbin \
--sysconfdir=/etc \
--datadir=/usr/share \
--localstatedir=/var \
--mandir=/usr/share/man \
--enable-bfd \
--enable-snmp \
--enable-snmp-rfc \
--enable-nftables \
--enable-regex \
--enable-json --with-init=systemd --enable-vrrp --enable-libnl-dynamic
RUN set -ex && \
cd /opt/keepalived && \
make && \
make DESTDIR=/install_root install && \
find /install_root && \
rm -rf /install_root/usr/share
FROM scratch AS bin
COPY --from=build /install_root /
运行
docker buildx build . --platform linux/amd64 --target bin --output .
之后在usr/sbin/
下就可以看到静态编译好的二进制文件了。注意libnl仍然是动态链接的,需要安装依赖:
yum install -y libnl3 libnl3-devel
或
apt install -y libnl-3-dev
其他方案
Keepalived是比较古老的方案,现代集群一般使用raft来进行选举,也可以考虑其他方案.
不过在边侧用keepalived其实够了,因为该软件最开始就是为了解决局域网问题的写的。