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


    目录、参考文献


    高可用注意事项

    本文包含社区提供的关于设置高可用 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
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    其中存在一些 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中存在一些 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
            # [...]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    其中存在一些 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
    
    • 1
    • 2

    服务运行起来后就可以用 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: {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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: {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    其中的 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>
    
    • 1
    • 2

    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")
    
    • 1
    • 或手动设置版本:
    export KVVERSION=vx.x.x
    
    • 1

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

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

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

    4.3. 为不同场景创建清单

    4.3.1. ARP

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

    export INTERFACE=eth0
    
    • 1
    kube-vip manifest pod \
        --interface $INTERFACE \
        --vip $VIP \
        --controlplane \
        --arp \
        --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    清单的例子:

    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: {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    4.3.2 BGP

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

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

    export INTERFACE=lo
    
    • 1
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    清单的例子:

    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: {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    服务运行起来后就可以用 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 ...]
    
    • 1

    目录、参考文献

  • 相关阅读:
    【云原生】Docker报错:curl: (56) Recv failure: Connection reset by peer解决
    七月集训(5)双指针
    C语言文件操作
    Java浮点运算为什么不精确
    CLion 2023:专注于C和C++编程的智能IDE mac/win版
    viewBinding与反射结合的实用实践
    Spring Boot配置文件
    【快速阅读二】从OpenCv的代码中扣取泊松融合算子(Poisson Image Editing)并稍作优化
    mybatis的一对一和一对多实现
    Cilium系列-15-7层网络CiliumNetworkPolicy简介
  • 原文地址:https://blog.csdn.net/wdhlzd/article/details/126442882