利用 kubeadm 创建高可用集群

高可用拓扑

可以设置 HA 集群:

  • 使用堆叠(stacked)控制平面节点,其中 etcd 节点与控制平面节点共存;
  • 使用外部 etcd 节点,其中 etcd 在与控制平面不同的节点上运行;

在设置 HA 集群之前,应该仔细考虑每种拓扑的优缺点。

1、堆叠(Stacked) etcd 拓扑

image.png
主要特点:

  • etcd 分布式数据存储集群堆叠在 kubeadm 管理的控制平面节点上,作为控制平面的一个组件运行。
  • 每个控制平面节点运行 kube-apiserver,kube-scheduler 和 kube-controller-manager 实例。
  • kube-apiserver 使用 LB 暴露给工作节点。
  • 每个控制平面节点创建一个本地 etcd 成员(member),这个 etcd 成员只与该节点的 kube-apiserver 通信。这同样适用于本地 kube-controller-manager 和 kube-scheduler 实例。
  • 简单概况:每个 master 节点上运行一个 apiserver 和 etcd, etcd 只与本节点 apiserver 通信。
  • 这种拓扑将控制平面和 etcd 成员耦合在同一节点上。相对使用外部 etcd 集群,设置起来更简单,而且更易于副本管理。
  • 然而堆叠集群存在耦合失败的风险。如果一个节点发生故障,则 etcd 成员和控制平面实例都将丢失,并且冗余会受到影响。可以通过添加更多控制平面节点来降低此风险。应该为 HA 集群运行至少三个堆叠的控制平面节点(防止脑裂)。
  • 这是 kubeadm 中的默认拓扑。当使用 kubeadm init 和 kubeadm join —control-plane 时,在控制平面节点上会自动创建本地 etcd 成员。

    2、外部 etcd 拓扑

    image.png
    主要特点:

  • 具有外部 etcd 的 HA 集群是一种这样的拓扑,其中 etcd 分布式数据存储集群在独立于控制平面节点的其他节点上运行。

  • 就像堆叠的 etcd 拓扑一样,外部 etcd 拓扑中的每个控制平面节点都运行 kube-apiserver,kube-scheduler 和 kube-controller-manager 实例。
  • 同样 kube-apiserver 使用负载均衡器暴露给工作节点。但是,etcd 成员在不同的主机上运行,每个 etcd 主机与每个控制平面节点的 kube-apiserver 通信。
  • 简单概况: etcd 集群运行在单独的主机上,每个 etcd 都与 apiserver 节点通信。
  • 这种拓扑结构解耦了控制平面和 etcd 成员。因此,它提供了一种 HA 设置,其中失去控制平面实例或者 etcd 成员的影响较小,并且不会像堆叠的 HA 拓扑那样影响集群冗余。
  • 但是,此拓扑需要两倍于堆叠 HA 拓扑的主机数量。具有此拓扑的 HA 集群至少需要三个用于控制平面节点的主机和三个用于 etcd 节点的主机。
  • 需要单独设置外部 etcd 集群。

    3、小结

    官方这里主要是解决了高可用场景下 apiserver 与 etcd 集群的关系,以及控制平面节点防止单点故障。但是集群对外访问接口不可能将三个 apiserver 都暴露出去,一个节点挂掉时还是不能自动切换到其他节点。官方只提到了一句“使用负载均衡器将 apiserver 暴露给工作节点”,而这恰恰是部署过程中需要解决的重点问题。
    Notes: 此处的负载均衡器并不是 kube-proxy,此处的 Load Balancer 是针对 apiserver 的。
    最后,我们总结一下两种拓扑:

  • 堆叠(Stacked) etcd 拓扑:设置简单,易于副本管理 ,不过存在耦合失败风险。如果节点发生故障,则 etcd 成员和控制平面实例有丢失的可能,推荐测试开发环境;

  • 外部 etcd 拓扑:解耦了控制平面和 etcd 成员,不会像堆叠的 HA 拓扑那样有影响集群冗余的风险,不过需要两倍于堆叠 HA 拓扑的主机数量,设置相对复杂,推荐生产环境。

    部署架构

    以下是我们在测试环境所用的部署架构:
    image.png

这里采用 kubeadm 方式搭建高可用 k8s 集群,k8s 集群的高可用实际是 k8s 各核心组件的高可用,这里使用主备模式:
image.png

  • apiserver 通过 keepalived+haproxy 实现高可用,当某个节点故障时触发 keepalived vip 转移,haproxy 负责将流量负载到 apiserver 节点;
  • controller-manager k8s 内部通过选举方式产生领导者(由 —leader-elect 选型控制,默认为 true),同一时刻集群内只有一个 controller-manager 组件运行,其余处于 backup 状态;
  • scheduler k8s 内部通过选举方式产生领导者(由 —leader-elect 选型控制,默认为 true),同一时刻集群内只有一个scheduler组件运行,其余处于 backup 状态;
  • etcd 通过运行 kubeadm 方式自动创建集群来实现高可用,部署的节点数为奇数,3节点方式最多容忍一台机器宕机。

一、安装kubeadm

1.1、准备工作

  • 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令
  • 每台机器 2 GB 或更多的 RAM (如果少于这个数字将会影响你应用的运行内存)
  • 2 CPU 核或更多
  • 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以)
  • 节点之中不可以有重复的主机名、MAC 地址或 product_uuid。请参见这里了解更多详细信息。
  • 开启机器上的某些端口。请参见这里 了解更多详细信息。
  • 禁用交换分区。为了保证 kubelet 正常工作,你 必须 禁用交换分区。

1.1.1、硬件信息

主机hostname IP地址 安装组件 主机配置 explain
master-01 10.113.66.167 docker-ce v20.10.9
yum-utils v1.1.31
device-mapper-persistent-data v0.8.5
lvm2 v2.02.187
kubeadm v1.22.7
kubelet v1.22.7
kubectl v1.22.7
4C-8G

control plane
master-02 10.113.66.153 4C-8G
master-03 10.113.66.157 4C-8G
work-01 10.113.65.74 docker-ce v20.10.9
yum-utils v1.1.31
device-mapper-persistent-data v0.8.5
lvm2 v2.02.187
kubeadm v1.22.7
kubelet v1.22.7
kubectl v1.22.7
4C-8G

worker nodes
work-02 4C-8G
VIP 172.16.106.187 在control plane浮动

1.1.2、保证环境正确性

purpose commands
保证集群各节点互通 ping -c 3
保证MAC地址唯一 ip link 或 ifconfig -a
保证集群内主机名唯一 查询 hostnamectl status,修改 hostnamectl set-hostname
保证系统产品uuid唯一 sudo cat /sys/class/dmi/id/product_uuid

修改MAC地址参考命令:

  1. ifconfig eth0 down
  2. ifconfig eth0 hw ether 00:0C:18:EF:FF:ED
  3. ifconfig eth0 up

如product_uuid不唯一,请考虑重装CentOS系统.

1.1.3、检查所需端口

启用这些必要的端口后才能使 Kubernetes 的各组件相互通信。可以使用 telnet 来检查端口是否启用,例如:

  1. telnet 127.0.0.1 6443

控制面

协议 方向 端口范围 目的 使用者
TCP 入站 6443 Kubernetes API server 所有
TCP 入站 2379-2380 etcd server client API kube-apiserver, etcd
TCP 入站 10250 Kubelet API 自身, 控制面
TCP 入站 10259 kube-scheduler 自身
TCP 入站 10257 kube-controller-manager 自身

尽管 etcd 的端口也列举在控制面的部分,但你也可以在外部自己托管 etcd 集群或者自定义端口。

工作节点

协议 方向 端口范围 目的 使用者
TCP 入站 10250 Kubelet API 自身, 控制面
TCP 入站 30000-32767 NodePort Services 所有

1.1.4、禁用swap

swap仅当内存不够时会使用硬盘块充当额外内存,硬盘的io较内存差距极大,禁用swap以提高性能
各节点均需执行:

  1. swapoff -a
  2. sed -i 's/.*swap.*/#&/' /etc/fstab

1.1.5、安装 runtime

官网:安装runtime
这里以为docker为例,所有节点均需安装部署docker。

安装docker
  1. 删掉旧的docker

    1. sudo yum remove docker docker-common docker-selinux docker-engine
  2. 安装一些依赖

    1. sudo yum install -y yum-utils device-mapper-persistent-data lvm2
  3. 根据你的发行版下载repo文件:

    1. wget -O /etc/yum.repos.d/docker-ce.repo http://mirrors.sangfor.org/assistants/docker/centos/docker-ce.repo
  4. 安装指定版本docker ```

    查看可用docker版本

    yum list docker-ce.x86_64 —showduplicates | sort -r

安装指定版本docker

yum install -y docker-ce-19.03.12-3.el7

  1. > 这里以安装19.03.12版本举例,注意版本号不包含:与之前的数字
  2. 5. **添加用户到docker组**
  3. root用户,无需sudo即可使用docker命令

添加用户到docker组

usermod -aG docker

当前会话立即更新docker组

newgrp docker

  1. 6. **配置docker**

$ mkdir /etc/docker

修改cgroup驱动为systemd[k8s官方推荐]、限制容器日志量、修改存储类型,最后的docker家目录可修改

cat > /etc/docker/daemon.json <<EOF { “exec-opts”: [“native.cgroupdriver=systemd”], “log-driver”: “json-file”, “log-opts”: { “max-size”: “100m” }, “storage-driver”: “overlay2”, “storage-opts”: [ “overlay2.override_kernel_check=true” ], “registry-mirrors”: [“https://7uuu3esz.mirror.aliyuncs.com“], “data-root”: “/data/docker” } EOF

添加开机自启,立即启动

$ systemctl enable —now docker

  1. <a name="J86ck"></a>
  2. #### 1.1.6、确保网络模块开机自动加载

lsmod | grep overlay lsmod | grep br_netfilter

若上面命令无返回值输出或提示文件不存在,需执行以下命令:

cat > /etc/modules-load.d/docker.conf <<EOF overlay br_netfilter EOF

modprobe overlay modprobe br_netfilter

<a name="vGbFy"></a>
#### 1.1.7、允许桥接流量对iptables可见
各节点均需执行:

cat > /etc/sysctl.d/k8s.conf <<EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl —system

验证是否生效,均返回 1 即正确

sysctl -n net.bridge.bridge-nf-call-iptables sysctl -n net.bridge.bridge-nf-call-ip6tables

<a name="Rxwau"></a>
## 二、安装 kubeadm、kubelet 和 kubectl
你需要在每台机器上安装以下的软件包:

- kubeadm:用来初始化集群的指令。
- kubelet:在集群中的每个节点上用来启动 Pod 和容器等。
- kubectl:用来与集群通信的命令行工具。
<a name="qbFGw"></a>
### 2.1、配置kubernetes源
首先配置内部kubernetes源: 配置文件 /etc/yum.repos.d/kubernetes.repo

[kubernetes] name=Kubernetes baseurl=http://mirrors.sangfor.org/nexus/repository/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=http://mirrors.sangfor.org/nexus/repository/kubernetes/yum/doc/yum-key.gpg http://mirrors.sangfor.org/nexus/repository/kubernetes/yum/doc/rpm-package-key.gpg

执行

sudo yum makecache

<a name="uDseE"></a>
### 2.2、各节点均需安装kubeadm、kubelet,kubectl

yum install -y kubelet-1.22.7 kubeadm-1.22.7 kubectl-1.22.7 —disableexcludes=kubernetes

—disableexcludes=kubernetes 禁掉除了这个之外的别的仓库

systemctl enable —now kubelet

<a name="v6RpJ"></a>
#### 2.2.1、禁用selinux
关闭 SELinux,否则 kubelet 挂载目录时可能报错 `Permission denied`,可以设置为`permissive`或`disabled`,`permissive` 会提示warn信息

将 SELinux 设置为 permissive 模式(相当于将其禁用)

sudo setenforce 0 sudo sed -i ‘s/^SELINUX=enforcing$/SELINUX=permissive/‘ /etc/selinux/config

**注意:**

- 通过运行命令 setenforce 0 和 sed ... 将 SELinux 设置为 permissive 模式 可以有效地将其禁用。 这是允许容器访问主机文件系统所必需的,而这些操作时为了例如 Pod 网络工作正常。你必须这么做,直到 kubelet 做出对 SELinux 的支持进行升级为止。
- 如果你知道如何配置 SELinux 则可以将其保持启用状态,但可能需要设定 kubeadm 不支持的部分配置。

kubelet 现在每隔几秒就会重启,因为它陷入了一个等待 kubeadm 指令的死循环。

<a name="JnNRt"></a>
## 三、配置 cgroup 驱动程序 
容器运行时和 kubelet 都具有名字为 ["cgroup driver"](https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/) 的属性,该属性对于在 Linux 机器上管理 CGroups 而言非常重要。
> **警告:**
> 你需要确保容器运行时和 kubelet 所使用的是相同的 cgroup 驱动,否则 kubelet 进程会失败。


kubeadm 支持在执行 kubeadm init 时,传递一个 KubeletConfiguration 结构体。 KubeletConfiguration 包含 cgroupDriver 字段,可用于控制 kubelet 的 cgroup 驱动。

> **说明:** 在版本 1.22 中,如果用户没有在 KubeletConfiguration 中设置 cgroupDriver 字段, kubeadm init 会将它设置为默认值 systemd。

这是一个最小化的示例,其中显式的配置了此字段:

kubeadm-config.yaml

kind: ClusterConfiguration apiVersion: kubeadm.k8s.io/v1beta3

kubernetesVersion: v1.21.0

kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 cgroupDriver: systemd

这样一个配置文件就可以传递给 kubeadm 命令了:

kubeadm init —config kubeadm-config.yaml

> **说明:**
> Kubeadm 对集群所有的节点,使用相同的 KubeletConfiguration。 KubeletConfiguration 存放于 kube-system 命名空间下的某个 [ConfigMap](https://kubernetes.io/zh/docs/concepts/configuration/configmap) 对象中。
> 执行 init、join 和 upgrade 等子命令会促使 kubeadm 将 KubeletConfiguration 写入到文件 /var/lib/kubelet/config.yaml 中, 继而把它传递给本地节点的 kubelet。

**相关细节可参见**[配置 cgroup 驱动](https://kubernetes.io/zh/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/)**。**

<a name="m5cWH"></a>
## 四、利用 kubeadm 创建高可用集群
<a name="I52dO"></a>
### 4.1、拉取k8s镜像
查看指定k8s版本需要哪些镜像

$ kubeadm config images list —kubernetes-version v1.22.7

k8s.gcr.io/kube-apiserver:v1.22.7 k8s.gcr.io/kube-controller-manager:v1.22.7 k8s.gcr.io/kube-scheduler:v1.22.7 k8s.gcr.io/kube-proxy:v1.22.7 k8s.gcr.io/pause:3.5 k8s.gcr.io/etcd:3.5.0-0 k8s.gcr.io/coredns/coredns:v1.8.4

在 /root/k8s 目录下,新建脚本get-k8s-images.sh,内容如下:

!/bin/bash

Script For Quick Pull K8S Docker Images

KUBE_VERSION=v1.18.5 PAUSE_VERSION=3.2 CORE_DNS_VERSION=1.6.7 ETCD_VERSION=3.4.3-0

pull kubernetes images from hub.docker.com

docker pull kubeimage/kube-proxy-amd64:$KUBE_VERSION docker pull kubeimage/kube-controller-manager-amd64:$KUBE_VERSION docker pull kubeimage/kube-apiserver-amd64:$KUBE_VERSION docker pull kubeimage/kube-scheduler-amd64:$KUBE_VERSION

pull aliyuncs mirror docker images

docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:$PAUSE_VERSION docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$CORE_DNS_VERSION docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:$ETCD_VERSION

retag to k8s.gcr.io prefix

docker tag kubeimage/kube-proxy-amd64:$KUBE_VERSION k8s.gcr.io/kube-proxy:$KUBE_VERSION docker tag kubeimage/kube-controller-manager-amd64:$KUBE_VERSION k8s.gcr.io/kube-controller-manager:$KUBE_VERSION docker tag kubeimage/kube-apiserver-amd64:$KUBE_VERSION k8s.gcr.io/kube-apiserver:$KUBE_VERSION docker tag kubeimage/kube-scheduler-amd64:$KUBE_VERSION k8s.gcr.io/kube-scheduler:$KUBE_VERSION docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:$PAUSE_VERSION k8s.gcr.io/pause:$PAUSE_VERSION docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$CORE_DNS_VERSION k8s.gcr.io/coredns:$CORE_DNS_VERSION docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:$ETCD_VERSION k8s.gcr.io/etcd:$ETCD_VERSION

untag origin tag, the images won’t be delete.

docker rmi kubeimage/kube-proxy-amd64:$KUBE_VERSION docker rmi kubeimage/kube-controller-manager-amd64:$KUBE_VERSION docker rmi kubeimage/kube-apiserver-amd64:$KUBE_VERSION docker rmi kubeimage/kube-scheduler-amd64:$KUBE_VERSION docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/pause:$PAUSE_VERSION docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$CORE_DNS_VERSION docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:$ETCD_VERSION

脚本添加可执行权限,执行脚本拉取镜像:

chmod +x get-k8s-images.sh ./get-k8s-images.sh

拉取完成,执行 docker images 查看镜像<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2809907/1646202895457-56a1ac57-c326-4645-9ec5-b2763444d670.png#clientId=ufcfe6580-7577-4&from=paste&id=u37083204&margin=%5Bobject%20Object%5D&name=image.png&originHeight=158&originWidth=860&originalType=url&ratio=1&size=23486&status=done&style=none&taskId=uae55eadd-e9ba-4255-9b14-3a527697c03)

<a name="h6y9n"></a>
### 4.2、配置负载均衡
官网:[配置负载均衡](https://github.com/kubernetes/kubeadm/blob/main/docs/ha-considerations.md#bootstrap-the-cluster)<br />在三个master节点上安装了 Keepalived 和 HAproxy,如果其中一个节点故障,虚拟 IP 地址(即浮动 IP 地址)将自动与另一个节点关联,使集群仍然可以正常运行,从而实现高可用。若有需要,也可以此为目的,添加更多安装 Keepalived 和 HAproxy 的节点。

先运行以下命令安装 Keepalived 和 HAproxy。

yum install keepalived haproxy psmisc -y

<a name="Yfjoa"></a>
#### 4.2.1、配置HAproxy
1、在三台用于负载均衡的机器上运行以下命令以配置 Proxy(三台机器的 Proxy 配置相同):

vi /etc/haproxy/haproxy.cfg

2、以下是示例配置,供您参考:

——————————————————————————————————-

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

    # [...]
各个参数解析:

- ${APISERVER_DEST_PORT} :kubernetes与kube-apiserver交互的端口,也就是loadBanlander服务的端口。
- ${APISERVER_SRC_PORT} :kube-apiserver实例使用的端口,一般默认为6443。
- ${HOST1_ID} :kube-apiserver实例1的主机ID。
- ${HOST1_ADDRESS}:可以解析的地址 (DNS name, IP address) 作为loadBalander第一个主机。

```go
#---------------------------------------------------------------------
# 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 *: 8443
    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  kube-apiserver-1 192.168.0.31:6443 check
    server  kube-apiserver-2 192.168.0.32:6443 check
    server  kube-apiserver-3 192.168.0.33:6443 check

4.2.2、配置keepalived

1、运行以下命令以配置 Keepalived。

vi /etc/keepalived/keepalived.conf

以下是示例配置 (master-01),供您参考:

! /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
    }
}
  • ${STATE} :一个主机为MASTER,其他主机为BACKUP,因此虚拟IP最初将分配给MASTER。
  • ${INTERFACE} :参与虚拟IP协商的网络接口,例如eth0。
  • ${ROUTER_ID} :所有保持活的集群主机应该是相同的,而在同一子网中的所有集群中是唯一的。许多发行版将其值预先配置为51。
  • ${PRIORITY}: 在控制平面节点上的值应该高于备份节点上的值。因此分别是101和100就足够了。
  • ${AUTH_PASS} :对于所有的keepalive集群主机应该是相同的
  • ${APISERVER_VIP} :是keepalive集群主机之间协商的虚拟IP地址。 ```go ! 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 MASTER interface eth0 virtual_router_id 50 priority 100 authentication { auth_type PASS auth_pass 111 } virtual_ipaddress { 192.168.0.200 } track_script { check_apiserver } }


上面使用的kube-apiserver健康检测脚本<br />/etc/keepalived/check_apiserver.sh

!/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

变量参数解析:

- ${APISERVER_VIP} :是keepalive集群主机之间协商的虚拟IP地址。
- ${APISERVER_DEST_PORT} :Kubernetes与API Server通信的端口。

运行方式一:以服务的方式<br />先运行以下命令安装 Keepalived 和 HAproxy。
```go
yum install keepalived haproxy psmisc -y
# systemctl enable haproxy --now
# systemctl enable keepalived --now

运行方式二:静态pod运行
/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: {}

/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: {}

4.3、初始化控制平面:

4.3.1、修改kubelet配置默认cgroup driver

cat > /var/lib/kubelet/config.yaml <<EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOF

systemctl restart kubelet

4.3.2、生成kubeadm初始化配置文件

[可选] 仅当需自定义初始化配置时用

kubeadm config print init-defaults > init.default.yaml

4.3.3、测试环境是否正常

(WARNING是正常的)

kubeadm init phase preflight [--config kubeadm-init.yaml]

4.3.4、初始化

sudo kubeadm init --kubernetes-version=v1.22.7 \
--control-plane-endpoint "192.168.0.200:8443" \
--pod-network-cidr=10.244.0.0/16 \
--config=init.default.yaml \
--upload-certs

4.3.5、其他控制节点

执行先前由第一个节点上的 kubeadm init 输出提供给你的 join 命令。 它看起来应该像这样:

sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07

4.4、安装工作节点

sudo kubeadm join 192.168.0.200:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

五、配置自动补全命令

#安装bash自动补全插件
yum install bash-completion -y

#设置kubectl与kubeadm命令补全,下次login生效
kubectl completion bash >/etc/bash_completion.d/kubectl
kubeadm completion bash > /etc/bash_completion.d/kubeadm