Back
Featured image of post Kubeadm部署kubernetes高可用集群

Kubeadm部署kubernetes高可用集群

Kubeadm部署kubernetes高可用集群

前言

技术发展实在是快,之前还比较流行的keep-alived+HAProxy HA负载方案,如今(2021-11-2)已经大有被kube-vip取代的趋势。回过头来看当时写的部署文档,已然过时了。 趁着服务器空闲,修补下方案。

HA方案

对于kubernetes集群来说,高可用性指的是控制平面(包括etcd集群)的高可用。控制平面的组件中,kube-scheduler和kube-controller-manager通过etcd实现高可用选主,我们不需要额外操心。所以,实际的高可用方案,只要满足控制节点数量奇数且大于等于三,然后实现apiserver的高可用即可。

基于etcd集群的耦合性,高可用集群一般包括以下两种拓扑架构。

Stacked ectd topology

etcd分布式存储集群堆叠在每一个控制面板节点上,作为控制平面的一个组件运行。
每个控制平面节点创建一个本地etcd成员,这个etcd成员只与本地的kube-apiserver通信。

External etcd topology

外部etcd分布式数据存储集群在独立于控制平面节点的其他节点上运行。这样的话解耦了控制平面和etcd成员。 缺点是需要更多的服务器节点(至少三个)用于etcd集群部署。

apiserver高可用实现

实现apiserver的高可用,主要是通过负载均衡技术,把请求转发到健康的节点上。

  • 硬件LB
    比如F5,Radware这类硬件负载技术。不过成本较高,好处是一般都自带维保合同。适合财大气粗的大厂。
  • 软件LB
    比如nginx代理,keep-alived + HAProxy,kube-vip

说到这里我其实觉得蛮遗憾的,为什么k8s不自己实现高可用呢,比如借助ipvs…非要借助外部依赖增大架构复杂度。

本文主要介绍最新的kube-vip实现的高可用方案。

kube-vip

传统意义上的HA方案主要是通过keep-alived + HAProxy实现的,HAProxy是一个软件负载,但是存在单点问题,而keep-alived通过VRRP协议实现vip漂移从而达到热备的效果。

kube-vip是直接通过k8s构建的static pod,也可以配置为DaemonSet实现,通过ARP或者BGP协议实现冗余。

ARP协议下会选举出一个领导者,而BGP协议下所有节点都会广播VIP地址。优点也是显而易见的,架构简单,成本低,维护方便。


前期准备

节点规划

主机名 角色 ip 配置 系统版本
master-1 master 172.21.0.3 4C8G Ubuntu 16.04.1 LTS
master-2 master 172.21.0.4 4C8G Ubuntu 16.04.1 LTS
master-3 master 172.21.0.5 4C8G Ubuntu 16.04.1 LTS
worker-1 node 172.21.0.6 4C8G Ubuntu 16.04.1 LTS
worker-2 node 172.21.0.7 4C8G Ubuntu 16.04.1 LTS
k8s-apiserver LB 172.17.0.11 kube-vip

硬件需求

  • 系统版本支持
  • 2GB及以上的内存,2C及以上的CPU核心
  • 节点直接网络互通
  • 主机名、UUID、MAC地址等唯一不重复

环境配置

除了一些基本的环境配置,比如主机名,本地DNS配置,时间同步等以外,所有服务器都需要进行基础设置,比如关闭防火墙,关闭swap等。

关闭防火墙

鉴于防火墙的配置复杂,k8s需要保持一些端口畅通,一般会建议关闭防火墙。

ufw disable

如果有生产环境安全需求不关闭防火墙的话,需要保持端口畅通,详情请参考 https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#check-required-ports

关闭swap

swapoff -a && sysctl -w vm.swappiness=0
sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab

允许iptables检查桥接流量

此处用于提供一些桥接技术的CNI网络插件支持iptables代理。

# 加载br_netfilter模块
sudo modprobe br_netfilter
# 查看加载结果
lsmod | grep br_netfilter
# 允许iptables监控桥接流量
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

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

安装容器运行时

鉴于kubernets即将放弃支持docker-shim,现在首推的容器运行时为contained

cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# Setup required sysctl params, these persist across reboots.
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.ipv4.ip_forward                 = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key --keyring /etc/apt/trusted.gpg.d/docker.gpg add -
sudo add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"
sudo apt-get update && sudo apt-get install -y containerd.io

# Configure containerd
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
# 使用 systemd 作为 cgroup 驱动
sudo vim /etc/containerd/config.toml
  [plugins."io.containerd.runtime.v1.linux"]
     systemd_cgroup = true
# 修改配置镜像源为阿里云
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
          endpoint = ["https://vcw3fe1o.mirror.aliyuncs.com"]
   [plugins."io.containerd.grpc.v1.cri"]
      sandbox_image = "https://vcw3fe1o.mirror.aliyuncs.com/pause:3.2"
# Restart containerd
sudo systemctl restart containerd

可选方案:安装docker

sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

配置docker镜像加速,systemd管理

cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": [
      "https://fz5yth0r.mirror.aliyuncs.com",
      "http://hub-mirror.c.163.com/",
      "https://docker.mirrors.ustc.edu.cn/",
      "https://registry.docker-cn.com"
  ],
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
EOF

sudo systemctl restart docker.service 

开启内核ipvs模块 (可选)

kube-proxy使用ipvs会有更好的性能,可伸缩性等优点
https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
确保内核模块开启

  • ip_vs
  • ip_vs_rr
  • ip_vs_wrr
  • ip_vs_sh
  • nf_conntrack_ipv4
# 安装ipvsadm ipset
sudo apt-get install ipvsadm ipset
# load module <module_name>
sudo modprobe -- ip_vs
sudo modprobe -- ip_vs_rr
sudo modprobe -- ip_vs_wrr
sudo modprobe -- ip_vs_sh
sudo modprobe -- nf_conntrack

# to check loaded modules, use
lsmod | grep -e ip_vs -e nf_conntrack

# 永久生效
cat << EOF | sudo tee /etc/modules-load.d/ipvs.conf
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack 
EOF
# Apply sysctl params without reboot
sudo sysctl --system

安装kubeadm相关程序

# 国内使用阿里云镜像源进行安装
sudo apt-get update && sudo apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
cat <<EOF  | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-$(lsb_release -cs) main
EOF
sudo apt-get update
# 非master节点不需安装kubectl
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

---

# 国外安装
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-$(lsb_release -cs) main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl


# 可选bash补全
sudo apt-get install bash-completion
#  生成自动补全脚本
sudo -s 
cd /etc/bash_completion.d && kubectl completion bash >kubectl

目前kubernetes新版下,kubectl默认systemd托管,不需要额外配置了。

kubeadm部署

kube-vip初始化

由于BGP模式更为复杂,需要BGP服务支持,本部署方案选择更为简单的ARP模式。

生成kube-vip默认配置文件

# master-1
sudo mkdir -p /etc/kube-vip/
sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample config | sudo tee /etc/kube-vip/config.yaml

生成的配置文件config.yaml修改后如下

localPeer:
  # master-1主机名
  id: master-1
  # master-1ip地址
  address: 172.17.0.3
  port: 10000
remotePeers:
# 其他master节点的主机名和ip地址
- id: master-2
  address: 172.17.0.4
  port: 10000
- id: master-3
  address: 172.17.0.5
  port: 10000
# apiserver的vip地址
vip: 172.17.0.11
gratuitousARP: true
singleNode: false
# master-1配置为leader,其他节点为false
startAsLeader: true
# 网卡
interface: eth0
loadBalancers:
- name: API Server Load Balancer
  type: tcp
  port: 8443
  bindToVip: false
  backends:
  # 所有master节点信息
  - port: 6443
    address: 172.17.0.3
  - port: 6443
    address: 172.17.0.4
  - port: 6443
    address: 172.17.0.5

生成static pod配置

# master-1
sudo mkdir -p /etc/kubernetes/manifests/
sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml

github的package可能下载失败,请参考https://github.com/kube-vip/kube-vip/pkgs/container/kube-vip/4621490?tag=v0.3.7

生成的默认配置文件kube-vip.yaml如下

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: kube-vip
  namespace: kube-system
spec:
  containers:
  - args:
    - start
    - -c
    - /etc/kube-vip/config.yaml
    image: docker.io/plndr/kube-vip:v0.3.7
    name: kube-vip
    resources: {}
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        - SYS_TIME
    volumeMounts:
    - mountPath: /etc/kube-vip/
      name: config
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/kube-vip/
    name: config
status: {}

kubeadm初始化

master-1 配置阿里云镜像,apiserver的负载VIP,pod子网掩码(网络插件需要)等

# 配置文件
sudo kubeadm config print init-defaults > initconfig.yaml
# 修改配置文件后,执行检查 (详细修改请见下面的initconfig.yaml)
sudo kubeadm init --config initconfig.yaml --dry-run
sudo kubeadm config images list --config initconfig.yaml
# 预先拉取镜像
sudo kubeadm config images pull --config initconfig.yaml
sudo kubeadm init --config initconfig.yaml --upload-certs --v=5

# 非配置文件,不支持ipvs直接配置,需要后面patch

sudo kubeadm init \
# 国内阿里云镜像源
--image-repository registry.aliyuncs.com/google_containers \
# apiserver的VIP
--control-plane-endpoint 172.17.0.11 \
# 本地ip
--apiserver-advertise-address 172.21.0.3 \
# 根据网络CNI插件选择配置
--pod-network-cidr 10.244.0.0/16 \
# 容器运行时的CRI套接字
--cri-socket /run/containerd/containerd.sock

配置文件initconfig.yaml,改动点请看注释

apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  #### 指明用Master的哪个interface与Cluster 的其他节点通信。 如果Master有多个网卡, 建议明确指定,如果不指定,kubeadm会自动选择有默认网关的interface
  advertiseAddress: 172.17.0.10
  bindPort: 6443
nodeRegistration:
  #### 容器运行时,可选docker
  criSocket: /run/containerd/containerd.sock
  #criSocket: /var/run/dockershim.sock
  imagePullPolicy: IfNotPresent
  #### 本地主机名
  name: master-1
  taints: null
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
#### 配置apiserver的VIP
controlPlaneEndpoint: 172.17.0.11:8443
dns: {}
etcd:
  local:
    dataDir: /var/lib/etcd
#### 更新为国内阿里云镜像源
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.22.0
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
  #### 根据网络插件按需配置,此处为flannel默认配置
  podSubnet: 10.244.0.0/16

scheduler: {}
---

apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration # https://godoc.org/k8s.io/kube-proxy/config/v1alpha1#KubeProxyConfiguration
# 按需配置ipvs
mode: ipvs 

初始化后保存相关打印token,证书信息等。失败后重新init如果报错可以重置

sudo kubeadm reset

配置k8s运行的普通用户

# master1
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

安装网络插件

# flannel
# master1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 查看pods运行状况
kubectl get pods -n kube-system

---

# calico
kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml

其他master加入k8s集群

初始化kube-vip配置

同master-1,创建/etc/kube-vip/config.yaml,以下是master-2示例

localPeer:
  id: master-2
  address: 172.17.0.4
  port: 10000
remotePeers:
- id: master-1
  address: 172.17.0.3
  port: 10000
- id: master-3
  address: 172.17.0.5
  port: 10000
vip: 172.17.0.11
gratuitousARP: true
singleNode: false
## 确保不是leader,false
startAsLeader: false
interface: eth0
loadBalancers:
- name: API Server Load Balancer
  type: tcp
  port: 8443
  bindToVip: false
  backends:
  - port: 6443
    address: 172.17.0.10
  - port: 6443
    address: 172.17.0.4
  - port: 6443
    address: 172.17.0.17

加入集群的控制平面

# master2-3 
kubeadm join 172.17.0.10:8443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:53f09c157254a40b71043c71ad5094a335b0beb5ac083742d517ffc6792565bc \
    --control-plane --certificate-key e77731a34529ea1604a0f1344813c3ea4f83be7930471c917c5bb84a6776f421

为了便于在任意master节点操作,同样进行用户初始化

# master2-3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

生成static pod配置

由于kubeadm init的一些古怪行为,比如不允许/etc/kubernetes/manifests下有文件存在,所以必须在join后进行该步骤。

也可以直接复制master-1的配置文件(内容相同)。

sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml

其他node加入k8s集群

# worker-1-2
# 使用 kubeadm init的初始化输出命令加入
kubeadm join 172.17.0.10:8443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:53f09c157254a40b71043c71ad5094a335b0beb5ac083742d517ffc6792565bc \

查看集群nodes状态

# master
kubectl get nodes -o wide

输出结果

NAME       STATUS   ROLES                  AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
master-1   Ready    control-plane,master   3m15s   v1.20.2   172.21.0.3    <none>        Ubuntu 16.04.1 LTS   4.4.0-157-generic   docker://19.3.14
master-2   Ready    control-plane,master   2m37s   v1.20.2   172.21.0.4    <none>        Ubuntu 16.04.1 LTS   4.4.0-157-generic   docker://19.3.14
master-3   Ready    control-plane,master   2m32s   v1.20.2   172.21.0.5    <none>        Ubuntu 16.04.1 LTS   4.4.0-157-generic   docker://19.3.14
worker-1   Ready    <none>                 104s    v1.20.2   172.21.0.6    <none>        Ubuntu 16.04.1 LTS   4.4.0-157-generic   docker://19.3.14
worker-2   Ready    <none>                 110s    v1.20.2   172.21.0.7    <none>        Ubuntu 16.04.1 LTS   4.4.0-157-generic   docker://19.3.14
                                                      -- 更新于2021年11月3日16:48分 --

参考文档

  1. https://github.com/kube-vip/kube-vip/blob/092eb5423a3d630a3aca20d5582fe4ad551a9bb9/kubernetes-control-plane.md
  2. https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
  3. https://www.cnblogs.com/hehe520/p/6147741.html
  4. http://www.skycloudsoftware.com/index.php/2016/08/18/kubernetes007.html
  5. https://inductor.medium.com/say-good-bye-to-haproxy-and-keepalived-with-kube-vip-on-your-ha-k8s-control-plane-bb7237eca9fc
  6. https://zhangguanzhang.github.io/2019/11/24/kubeadm-base-use/
  7. https://github.com/kubernetes/kubeadm/blob/main/docs/ha-considerations.md#options-for-software-load-balancing
Built with Hugo
Theme Stack designed by Jimmy