Kubernetes 笔记 / kubeadm / 高可用注意事项

本文详细介绍了如何使用kubeadm创建高可用Kubernetes集群,包括选择软件负载均衡器、配置keepalived与haproxy或kube-vip实现API服务器的高可用,以及集群启动步骤。重点讨论了keepalived与haproxy的配置文件示例,以及kube-vip的使用方法,提供了在不同场景下的配置示例。

目录、参考文献


高可用注意事项

本文包含社区提供的关于设置高可用 Kubernetes 集群的注意事项

1. 概览

在设置生产集群时
通常需要高可用性(即使某些控制平面或工作节点发生故障,集群仍能运行的能力)
对于工作节点,假设有足够多的节点,这是集群功能的一部分
但是,在规划和设置集群时,需要考虑控制平面节点与 etcd 实例的冗余

kubeadm 支持设置多控制平面与多 etcd 集群(见:用 kubeadm 创建高可用集群
还有一些需要关注的点不属于 Kubernetes,因而没有包含在 Kubernetes 的项目文档中
本文提供了一些用 kubeadm 启动高可用集群的额外信息与例子

2. 软件负载均衡器的选择

在设置拥有两个及以上的控制平面的集群时
可以通过将 API 服务器实例放在一个负载均衡器后边来实现高可用
在为新集群运行 kubeadm init 命令时,使用 --control-plane-endpoint 选项来指向该负载均衡器

负载均衡器自己也应该是高可用的,通常通过添加冗余的负载均衡器来实现
为此,设置了管理虚拟 IP 的主机集群,每个主机运行一个负载均衡器的实例
以便始终使用当前持有 vIP 的主机上的负载均衡器,而其它主机处于待机状态

在某些环境中,如在具有专用负载均衡器组件(如某些云供应商提供的)的数据中心中
可能有现成的负载均衡功能
如果没有,则可以使用用户管理的负载平衡,在这种情况下,启动集群之前需要做一些准备

下边的内容给出了一些有用的例子,当然还有许多其它配置负载均衡器的方法

3. keepalived 与 haproxy

keepalivedhaproxy 结合,可以通过虚拟 IP 来实现负载均衡
这个方法已经使用了很长时间,经过了充分地测试

  • keepalived 服务提供了一个由可配置的健康检查管理的虚拟 IP
    由于虚拟 IP 的实现方式,所有协商虚拟 IP 的主机都需要在同一个 IP 子网中
  • 可以将 haproxy 服务配置为简单的基于流的负载均衡
    从而允许 TLS 终端由其后面的 API 服务器实例处理

keepalivedhaproxy 既可以以操作系统服务的形式运行
也可以以控制平面主机上的静态 pod 运行
两种情况下的服务配置是完全相同的

3.1. keepalived 配置

keepalived 的配置由两个文件组成

  1. 服务配置文件
  2. 健康检查脚本
    会被定期调用,用于确认持有虚拟 IP 的节点是否在正常运转

服务配置文件一般位于 /etc/keepalived 目录,但有些 Linux 发行版会将其放在别的地方

下边的配置能够成功用于 2.0.17 版本的 keepalived

! /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
    router_id LVS_DEVEL
}
vrrp_script check_apiserver {
  script "/etc/keepalived/check_apiserver.sh"
  interval 3
  weight -2
  fall 10
  rise 2
}

vrrp_instance VI_1 {
    state ${STATE}
    interface ${INTERFACE}
    virtual_router_id ${ROUTER_ID}
    priority ${PRIORITY}
    authentication {
        auth_type PASS
        auth_pass ${AUTH_PASS}
    }
    virtual_ipaddress {
        ${APISERVER_VIP}
    }
    track_script {
        check_apiserver
    }
}

其中存在一些 bash 变量风格的占位符,需要根据实际需求替换:

  • ${STATE}
    一个节点配置为 MASTER,其它所有节点配置为 BACKUP
    虚拟 IP 初次会被分配给配置了 MASTER 的节点
  • ${INTERFACE}
    参与虚拟 IP 协商的网络接口(网卡)如:eth0
  • ${ROUTER_ID}
    在同一个 keepalived 集群中的主机上相同
    在同一个子网下的不同集群之间唯一
  • ${PRIORITY}
    获得虚拟 IP 的优先级
    控制平面节点上的值应该高于备份节点上的值,如:101100
  • ${AUTH_PASS}
    keepalived 集群中的所有主机都有相同的值,如:42
  • ${APISERVER_VIP}
    keepalived 集群主机间进行协商的虚拟 IP

上边的 keepalived 配置使用了一个健康检查脚本 /etc/keepalived/check_apiserver.sh
该脚本负责确保在持有虚拟 IP 的节点上,API 服务器处于可用状态
脚本类似:

#!/bin/sh

errorExit() {
    echo "*** $*" 1>&2
    exit 1
}

curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
    curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi

其中存在一些 bash 变量风格的占位符,需要根据实际需求替换:

  • ${APISERVER_VIP}
    keepalived 集群主机间进行协商的虚拟 IP
  • ${APISERVER_DEST_PORT}
    Kubernetes 通过该端口与 API 服务器通信

3.2. haproxy 配置

haproxy 配置由 1 个文件组成
服务配置文件一般位于 /etc/haproxy 目录,但有些 Linux 发行版会将其放在别的地方

下边的配置能够成功用于 2.1.4 版本的 haproxy

# /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    log /dev/log local0
    log /dev/log local1 notice
    daemon

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 1
    timeout http-request    10s
    timeout queue           20s
    timeout connect         5s
    timeout client          20s
    timeout server          20s
    timeout http-keep-alive 10s
    timeout check           10s

#---------------------------------------------------------------------
# apiserver frontend which proxys to the control plane nodes
#---------------------------------------------------------------------
frontend apiserver
    bind *:${APISERVER_DEST_PORT}
    mode tcp
    option tcplog
    default_backend apiserver

#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
backend apiserver
    option httpchk GET /healthz
    http-check expect status 200
    mode tcp
    option ssl-hello-chk
    balance     roundrobin
        server ${HOST1_ID} ${HOST1_ADDRESS}:${APISERVER_SRC_PORT} check
        # [...]

其中存在一些 bash 变量风格的占位符,需要根据实际需求替换:

  • ${APISERVER_DEST_PORT}
    Kubernetes 通过该端口与 API 服务器通信
  • ${APISERVER_SRC_PORT}
    API 服务器实例使用的端口
  • ${HOST1_ID}
    第一个被负载均衡的 API 服务器主机的符号名称
  • ${HOST1_ADDRESS}
    第一个被负载均衡的 API 服务器主机的可解析的地址(DNS 名称、IP 地址)
  • 额外的 server 行,被负载均衡的 API 服务器主机各对应一行

3.3. 方式 1:作为操作系统服务运行

可以使用不同发行版的包管理器来安装 keepalivedhaproxy

之前的配置都已经设置好之后就可以开启服务了
在基于 RedHat 的系统上,可以使用 systemd 来启动

# systemctl enable haproxy --now
# systemctl enable keepalived --now

服务运行起来后就可以用 kubeadm init 启动 Kubernetes 集群了

3.4. 方式 2:作为静态 pod 运行

如果 keepalivedhaproxy 运行在控制平面节点上,可以将它们配置为以静态 pod 的形式运行
这需要在 /etc/kubernetes/manifests 目录创建对应的清单文件
在启动过程中,kubelet 会启动进程,这样集群就可以在开始时使用它们了

这样做可以让 keepalivedhaproxy 也享受容器技术的好处
如可以避免受到特定环境的影响、能被 k8s 管理等

keepalived 的清单文件 /etc/kubernetes/manifests/keepalived.yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: keepalived
  namespace: kube-system
spec:
  containers:
  - image: osixia/keepalived:2.0.17
    name: keepalived
    resources: {}
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        - NET_BROADCAST
        - NET_RAW
    volumeMounts:
    - mountPath: /usr/local/etc/keepalived/keepalived.conf
      name: config
    - mountPath: /etc/keepalived/check_apiserver.sh
      name: check
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/keepalived/keepalived.conf
    name: config
  - hostPath:
      path: /etc/keepalived/check_apiserver.sh
    name: check
status: {}

haproxy 的清单文件 /etc/kubernetes/manifests/haproxy.yaml

apiVersion: v1
kind: Pod
metadata:
  name: haproxy
  namespace: kube-system
spec:
  containers:
  - image: haproxy:2.1.4
    name: haproxy
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: localhost
        path: /healthz
        port: ${APISERVER_DEST_PORT}
        scheme: HTTPS
    volumeMounts:
    - mountPath: /usr/local/etc/haproxy/haproxy.cfg
      name: haproxyconf
      readOnly: true
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/haproxy/haproxy.cfg
      type: FileOrCreate
    name: haproxyconf
status: {}

其中的 bash 变量风格的占位符 ${APISERVER_DEST_PORT}
需要与前边 /etc/haproxy/haproxy.cfg 中的配置一致

服务运行起来后就可以用 kubeadm init 启动 Kubernetes 集群了

4. kube-vip

作为传统的 keepalivedhaproxy 的一个替代方案
kube-vip 用一个服务同时实现了虚拟 IP 管理与负载均衡功能

kube-vip 可以在 2 层(用 ARP 与 leaderElection)或 3 层用 BGP 对等互连来实现

与 3.4 中的方式 2 类似,kube-vip 会作为控制平面节点上的静态 pod 运行

类似 keepalived,协商虚拟 IP 的主机需要在同一个 IP 子网
类似 haproxy,基于流的(stream-based)负载均衡允许 TLS 终端由其后面的 API 服务器实例处理

注意:
kube-vip 需要具备访问 API 服务器的权限
特别是在集群初始化期间(即在 kubeadm init 阶段)
此时,admin.conf 是唯一可用于 kube-vip 进行身份验证并与 API 服务器通信的 kubeconfig
集群启动后,建议用户签署自定义客户端 kubeconfig 并在到期时手动轮换

4.1. 设置配置细节

export VIP=192.168.0.40`
export INTERFACE=<interface>

4.2. 配置容器运行时

4.2.1. 设置 kube-vip 的版本

  • 通过解析 GitHub API 设置最新版本:
KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")
  • 或手动设置版本:
export KVVERSION=vx.x.x

4.2.2. 为不同的容器运行时创建别名

创建清单的最简单的方法是利用容器自己来创建

  • containerd:
alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"
  • Docker:
alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"

4.3. 为不同场景创建清单

4.3.1. ARP

此配置将使用 leaderElection 创建一个清单
该清单用于启动 kube-vip 来提供控制平面与服务管理
当这个实例被选为 leader 时,会将 vip 绑定到指定的接口上
对于 type:LoadBalancer 的服务也是如此

export INTERFACE=eth0
kube-vip manifest pod \
    --interface $INTERFACE \
    --vip $VIP \
    --controlplane \
    --arp \
    --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml

清单的例子:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: kube-vip
  namespace: kube-system
spec:
  containers:
  - args:
    - manager
    env:
    - name: vip_arp
      value: "true"
    - name: port
      value: "6443"
    - name: vip_interface
      value: ens192
    - name: vip_cidr
      value: "32"
    - name: cp_enable
      value: "true"
    - name: cp_namespace
      value: kube-system
    - name: vip_ddns
      value: "false"
    - name: vip_leaderelection
      value: "true"
    - name: vip_leaseduration
      value: "5"
    - name: vip_renewdeadline
      value: "3"
    - name: vip_retryperiod
      value: "1"
    - name: vip_address
      value: 192.168.0.40
    image: ghcr.io/kube-vip/kube-vip:v0.4.0
    imagePullPolicy: Always
    name: kube-vip
    resources: {}
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
        - SYS_TIME
    volumeMounts:
    - mountPath: /etc/kubernetes/admin.conf
      name: kubeconfig
  hostAliases:
  - hostnames:
    - kubernetes
    ip: 127.0.0.1
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/admin.conf
    name: kubeconfig
status: {}

4.3.2 BGP

此配置将创建一个清单
该清单用于启动 kube-vip 来提供控制平面与服务管理
与 ARP 不同,BGP 配置中的所有节点都会发布虚拟 IP 地址

注意:
将地址绑定到 lo 上,是为了避免多个设备在公共接口上具有相同的地址
可以在一个逗号分隔的列表中指定所有对等点,格式为 address:AS:password:multihop

export INTERFACE=lo
kube-vip manifest pod \
    --interface $INTERFACE \
    --vip $VIP \
    --controlplane \
    --bgp \
    --localAS 65000 \
    --bgpRouterID 192.168.0.2 \
    --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml

清单的例子:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: kube-vip
  namespace: kube-system
spec:
  containers:
  - args:
    - manager
    env:
    - name: vip_arp
      value: "false"
    - name: port
      value: "6443"
    - name: vip_interface
      value: ens192
    - name: vip_cidr
      value: "32"
    - name: cp_enable
      value: "true"
    - name: cp_namespace
      value: kube-system
    - name: vip_ddns
      value: "false"
    - name: bgp_enable
      value: "true"
    - name: bgp_routerid
      value: 192.168.0.2
    - name: bgp_as
      value: "65000"
    - name: bgp_peeraddress
    - name: bgp_peerpass
    - name: bgp_peeras
      value: "65000"
    - name: bgp_peers
      value: 192.168.0.10:65000::false,192.168.0.11:65000::false
    - name: vip_address
      value: 192.168.0.40
    image: ghcr.io/kube-vip/kube-vip:v0.4.0
    imagePullPolicy: Always
    name: kube-vip
    resources: {}
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
        - SYS_TIME
    volumeMounts:
    - mountPath: /etc/kubernetes/admin.conf
      name: kubeconfig
  hostAliases:
  - hostnames:
    - kubernetes
    ip: 127.0.0.1
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/admin.conf
    name: kubeconfig
status: {}

服务运行起来后就可以用 kubeadm init 启动 Kubernetes 集群了

5. 启动集群

以上步骤完成后就可以启动集群了,详见:用 kubeadm 创建高可用集群

在上述配置中,如果 ${APISERVER_DEST_PORT} 的值不是 6443
则需要告知 kubeadm initAPI 服务器端口设置为对应的值

假设集群的被负载均衡的 API 服务器的端口为 8443
虚拟 IP 的 DNS 名称为 vip.mycluster.local
则需要设置 kubeadm 参数 --control-plane-endpoint

# kubeadm init --control-plane-endpoint vip.mycluster.local:8443 [additional arguments ...]

目录、参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值