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分 --
参考文档
- https://github.com/kube-vip/kube-vip/blob/092eb5423a3d630a3aca20d5582fe4ad551a9bb9/kubernetes-control-plane.md
- https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
- https://www.cnblogs.com/hehe520/p/6147741.html
- http://www.skycloudsoftware.com/index.php/2016/08/18/kubernetes007.html
- https://inductor.medium.com/say-good-bye-to-haproxy-and-keepalived-with-kube-vip-on-your-ha-k8s-control-plane-bb7237eca9fc
- https://zhangguanzhang.github.io/2019/11/24/kubeadm-base-use/
- https://github.com/kubernetes/kubeadm/blob/main/docs/ha-considerations.md#options-for-software-load-balancing