K8S 高可用相关

etcd 就不说了,奇数个副本,可以坏 (n-1)/2 个,有条件的可以单独 SSD 机器部署 etcd 。K8S 所有组件和客户端,都会使用 kubeconfig 或者集群内 rbac 的 serviceaccount 后通过 kubernetes 这个 service 最终连到实体的 kube-apiserver 进程。

etcd 集群下,一般都是 kube-apiserver/kube-controller-manager/kube-scheduler 部署多份,但是所有的都是连接 kube-apiserver,所以需要一个负载均衡负载到 kube-apiserver 副本上。

K8S 集群内部相关

集群内部自带了第一个 Service CIDR 第一个 IP 的 kubernetes service:

$ kubectl -n default describe svc kubernetes 
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.0.1
IPs:               10.96.0.1
Port:              https  443/TCP
TargetPort:        6443/TCP
Endpoints:         192.168.2.111:6443,192.168.2.112:6443,192.168.2.113:6443
Session Affinity:  None
Events:            <none>

集群内部访问 https://kubernetes.default 最终解析成 10.96.0.1,然后 DNAT 到 endpoint 里任意一个 kube-apiserver。可能有些聪明的人会问,这看起来是 kube-apiserver 上报的自己网卡 IP,如果是 nat 后的怎么处理,kube-apiserver 提供了 --advertise-address 选项,用于告诉访问自己使用哪个 IP。

使用负载均衡

kube-apiserver 本质上是个 web 七层服务,所以我们要整高可用不要把 k8s 想的太复杂了,保证了 apiserver 的高可用就行了。tcp 和 web 层面,是否软硬件,还是组合使用都行,例如:

  • 硬件 F5 配置转发
  • nginx、caddy、envoy、haproxy
  • 云上 SLB 代理
  • keepalived VRRP
  • keepalived VRRP + haproxy
  • 网络设备 ospf + lvs
    ...

如果是 7层负载均衡,健康检查可以用应用层面 url /healthz:

$ kubectl get --raw / | grep /healthz
    "/healthz",
    "/healthz/autoregister-completion",
    "/healthz/etcd",
    "/healthz/log",
    "/healthz/ping",
    "/healthz/post
    ...

可以 kube-apiserver 不配置 --anonymous-auth=false 后 /healthz 路由就返回 200 状态码了,或者把证书上传到 SLB 上之类的配置里,7层检查,例如下面是 haproxy 的 7 层检查 tcp 代理:


frontend k8s-api
  bind 0.0.0.0:8443
  bind 127.0.0.1:8443
  mode tcp
  option tcplog
  tcp-request inspect-delay 5s
  default_backend k8s-api

backend k8s-api
  mode tcp
  option tcplog
  option httpchk GET /healthz
  http-check expect string ok
  balance roundrobin
  default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
  server  api1  192.168.2.111:6443  check check-ssl verify none
  server  api2  192.168.2.112:6443  check check-ssl verify none
  server  api3  192.168.2.113:6443  check check-ssl verify none

kubeconfig 文件里包含有 kubernetes 的 URL 地址,想在使用 kubectl 的时候绕过负载均衡,可以使用 -s, --server= 来指定 kube-apiserver url ,另外可能你会遇到 kubectl 报错无法连接:

The connection to the server localhost:8080 was refused - did you specify the right host or port?

这是因为没有 ~/.kube/config 文件和 KUBECONFIG 变量文件不存在或者权限问题下,kubectl 默认认为连接 kube-apiserver 地址是 http://localhost:8080 的不需要授权的匿名地址,而现在 kube-apiserver 都会把 insecure-port 关闭了造成的报错。

local proxy

在一些私有化环境内,客户会无法提供 SLB 和硬件负载均衡,环境也可能是 openstack 环境上的虚拟机而无法使用 VRRP VIP(会因为 IP 和 MAC 不匹配被 drop),所以可以使用 local proxy 方式代理,也就是每个节点上部署一个软件做负载均衡,例如每个节点部署一个 nginx,监听 0.0.0.0:8443 反向代理 

 upstream kube_apiserver {
    least_conn;
    server 192.168.2.111:6443 max_fails=3 fail_timeout=10s;
    server 192.168.2.112:6443 max_fails=3 fail_timeout=10s;
    server 192.168.2.113:6443 max_fails=3 fail_timeout=10s;
    }

  server {
    listen        0.0.0.0:8443;
    proxy_pass    kube_apiserver;
    proxy_connect_timeout 1s;
  } 

例如下面是市面上的 sealos 就是使用 kubeadm 部署,staticPod 的目录加了个 yaml,使用的内核 lvs 能力做四层负载。每个 node 跑一个 lvs 的 watch 进程的 pod 去维护 lvs 的规则保持高可用:

再次重申下,不要局限在自己会的软件和实现手段的顽固思想上,而是看场景和后续升级维护和规模多方面考虑,例如如果客户经常注重漏洞扫描 CVE,那选择 caddy 这种单二进制 web server 做代理更新方便。

  • 无标签

0 评论

你还没有登录。你所做的任何更改会将作者标记为匿名用户。 如果你已经拥有帐户,请登录