这是一篇关于如何使用kubeadm工具搭建Kubernetes集群的文章。
kubeadm是由kubernetes官方社区维护的一款kubernetes集群部署工具,kubeadm会帮我们部署kubernetes里的一些关键服务,以及一些必要的证书,Kubeadm还会通过运行一系列预检查来确保服务器具有运行Kubernetes所需的所有必要组件和配置,从而使整个部署过程变得简单。
集群整体架构
这里采用kubernetes官网的图片进行说明:
如图,每个控制面节点都运行一份API服务器(kube-apiserver)、调度器(kube-scheduler)和控制器管理器(kube-controller-manager)实例。API服务器通过负载均衡器暴露给工作节点。etcd分布式数据库分别运行一个实例在控制面节点上,而且每个控制面节点的API服务器只会与本机的etcd实例进行通信。
集群整体硬件配置
这次的部署是在虚拟机上进行的,总共使用了7台虚拟机,都是Ubuntu 22.04.2 LTS系统,详细如下:
主机名 | IP | CPU | Mem | 作用 |
---|---|---|---|---|
haproxy1 | 192.168.1.9 | 2核 | 2G | 负载均衡器 |
haproxy2 | 192.168.1.10 | 2核 | 2G | 负载均衡器 |
control1 | 192.168.1.4 | 2核 | 2G | 控制面节点 |
control2 | 192.168.1.5 | 2核 | 2G | 控制面节点 |
contorl3 | 192.168.1.6 | 2核 | 2G | 控制面节点 |
work1 | 192.168.1.7 | 2核 | 2G | 工作节点 |
work2 | 192.168.1.8 | 2核 | 2G | 工作节点 |
控制面节点就是我们所说的主节点,只不过kubernetes官网称为控制面节点。
如上表所示,由于是在我的个人电脑上部署,所以每个虚拟机分配的资源并不多,不过已经足够跑起来了。
我们还要确保每个节点上主机名、MAC地址和product_uuid的唯一性。主机名可以通过hostname
命令查看,然后通过hostnamectl set-hostname 新主机名
设置;MAC地址可以通过ip link
查看;product_uuid可以通过cat /sys/class/dmi/id/product_uuid
查看。
控制面节点和工作节点还需禁用交换分区:
swapoff -a
(crontab -l 2>/dev/null; echo "@reboot /sbin/swapoff -a") | crontab - || true
必要端口开放设置
请确保在防火墙配置中允许这些端口:
控制面节点:
工作节点:
工作节点里的端口范围30000-32767主要用于NodePort型的网络服务。
ubuntu系统中防火墙相关命令有:ufw allow 端口号
,ufw enable
,ufw status
。
配置Kubernetes运行所需的内核模块和网络参数
在每个节点进行如下配置。
加载并启用Linux文件系统层叠功能模块和桥接设备的网络过滤模块:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
配置Linux网络内核参数:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1 #这个参数设置 Linux 桥接设备在进行网络地址转换 (NAT) 时调用 iptables 进行数据包处理。
net.bridge.bridge-nf-call-ip6tables = 1 #类似于上一个参数,但针对 IPv6 数据包。
net.ipv4.ip_forward = 1 #这个参数启用 Linux 内核的 IP 转发功能,允许系统将接收到的数据包从一个网络接口路由到另一个网络接口.
EOF
#重新加载sysctl配置,以应用新的参数设置。--system 选项表示从/etc/sysctl.conf和/etc/sysctl.d/目录中的配置文件加载参数,并将这些参数应用到系统。
sysctl --system
安装负载均衡器
负载均衡器是实现集群高可用的关键,用于代理三台控制面节点的6443端口,也就是API服务器(kube-apiserver)。这里我们将使用两个节点(haproxy1和haproxy2)来部署负载均衡器,其中一个作为主负载均衡器,另一个作为备用。采用的技术架构是keepalived 和 HAProxy。
Keepalived简单来讲就是一个主备切换工具,备用节点会不断的对主节点进行探活,当主节点故障时,备用节点会替代主节点进行工作,下文会大概介绍下它的工作原理。
HAProxy则是一款负载均衡器和代理服务器软件,这里不做过多介绍。
下面开始负载均衡器的具体搭建:
在节点haproxy1编写配置文件/etc/keepalived/keepalived.conf
! /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 MASTER
interface ens33
virtual_router_id 51
priority 101
authentication {
auth_type PASS
auth_pass 42
}
virtual_ipaddress {
192.168.1.120
}
track_script {
check_apiserver
}
}
上述文件里的一些关键配置:
vrrp_script
: 配置的是Keepalived的探活脚本,后面将会提到;state
:只有MASTER
和BACKUP
两种值,用于区分主备,节点haproxy1是主,所以这里写MASTER;interface
:网卡名;virtaul_router_id
:用于区分所属子网,在同一个kubernetes集群中所有Keepalived节点都配置相同的即可;priority
:优先级,主节点要高于备用节点才行;auth_pass
:用于Keepalived节点之间的认证,要配置成一样的;virtual_ipaddress
:这是一个关键配置,当所有Keepalived节点运行时,它们都会拥有一个相同的虚拟IP,而只有主Keepalived节点会通过ARP协议对外宣称拥有这个虚拟IP,而其它备用节点则会保持缄默。当备用节点发现主节点挂掉时,则会替代主节点对外宣称拥有这个虚拟IP,这就是Keepalived主备切换的大概原理;
在节点haproxy2编写配置文件/etc/keepalived/keepalived.conf
! /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 BACKUP
interface ens33
virtual_router_id 51
priority 100
authentication {
auth_type PASS
auth_pass 42
}
virtual_ipaddress {
192.168.1.120
}
track_script {
check_apiserver
}
}
配置和节点haproxy1的基本一样,主要是state
和priority
这两个配置不同。
在节点haproxy1和haproxy2编写探活脚本/etc/keepalived/check_apiserver.sh
#!/bin/sh
# /etc/keepalived/check_apiserver.sh
APISERVER_DEST_PORT=6443
APISERVER_VIP="192.168.1.120"
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
在节点haproxy1和haproxy2安装并运行Keepalived
运行以下命令进行安装:
apt-get update
apt-get install keepalived
systemctl enable keepalived --now
安装完成后,我们发现节点haproxy1和haproxy2都有了虚拟IP192.168.1.120
:
在节点haproxy1和haproxy2安装并运行HAProxy
运行以下命令进行安装:
apt-get update
apt-get install haproxy
systemctl enable haproxy --now
在节点haproxy1和haproxy2替换配置文件/etc/haproxy/haproxy.cfg
,并重启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 0.0.0.0:6443
mode tcp
option tcplog
default_backend apiserver
#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
backend apiserver
mode tcp
option tcp-check
balance roundrobin
server control1 192.168.1.4:6443 check
server control2 192.168.1.5:6443 check
server contorl3 192.168.1.6:6443 check
重启HAProxy:systemctl restart haproxy.service
。
通过配置文件我们可以看到HAProxy绑定了本地的6443端口,并且将请求转发到后面的三个控制面节点。
到这里我们两个节点的负载均衡器就搭建完成了,不过这时候你会看到HAProxy不停报后端不可达的错误,这是正常的,因为我们的控制面节点还没有搭建。
在控制面节点和工作节点安装容器运行时
我们采用containerd作为容器运行时。
执行以下命令来安装containerd:
apt update
apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install containerd.io
然后我们初始下containerd的默认配置:
containerd config default | tee /etc/containerd/config.toml
我们还需要把containerd的cgroup驱动设置为systemd,在配置文件/etc/containerd/config.toml
里设置:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
我们还要给containerd配置一个国内的sanbox镜像文件,不然可能会出现拉取不了镜像的问题,在配置文件/etc/containerd/config.toml
里设置:
[plugins."io.containerd.grpc.v1.cri"]
...
sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9"
重启containerd:systemctl restart containerd.service
。
在控制面节点和工作节点安装kubeadm、kubectl、kubelet工具
apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
工作节点可以不安装kubectl。
在节点control1执行kubeadm init
kubeadm init --pod-network-cidr="10.51.32.0/24" --node-name "control1" --control-plane-endpoint "192.168.1.120:6443" --upload-certs --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers
其中,
--pod-network-cidr
配置的是我们kubernetes内部的网络段;
--control-plane-endpoint
配置的是我们虚拟IP;
--upload-certs
表示要将kubeadm自动生成的证书上传至etcd,因为我们是多控制面节点,其它节点加入时可以从etcd获取相关证书信息;
--image-repository
是用来配置国内镜像源,因为kubeadm初始化时,会自动安装API服务器(kube-apiserver)、调度器(kube-scheduler)、控制器管理器(kube-controller-manager)和etcd等这些必要组件,
而且这些组件都是以pod的形式运行,所以配置个国内镜像源,这些pod的yaml文件都会被kubeadm在初始化时放在/etc/kubernetes/manifests
。
kubeadm init
命令运行成功后,我们将会看到这样的一个输出:
...
You can now join any number of control-plane node by running the following command on each as a root:
kubeadm join 192.168.1.120:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 --control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.1.120:6443 --token 9vr73a.a8uxyaju799qwdjv --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
这里有两种kubeadm join
命令,一种用于控制面节点的加入,另一种用于工作节点的加入。
在其余控制面节点和工作节点分别执行对应的kubeadm join命令
都加入完成后,我们可以执行kubectl get nodes -o wide
命令查看节点状态。
安装calico网络组件
安装calico组件前,还需让各节点开放179端口。
执行以下命令进行安装:
curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml -o calico.yaml
kubectl apply -f calico.yaml
执行apply后,你可能发现你的calico组件pod一直在重启,那可能是因为它不知道关联主机上的哪个网络接口,所以用这一步指定calico使用哪个网络接口,我的虚拟机网络接口都是ens33,所以我就写成ens*,各位可根据自身情况配置,比如eth* 等等:
kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=interface=ens*
安装Metrics Server
安装Metrics Server组件前,还需让各节点开放4443端口。
# 记得修改yaml文件里使用的镜像为国内源,不然你可能拉取不到镜像,比如配置成:registry.aliyuncs.com/google_containers/metrics-server:v0.6.2
curl https://raw.githubusercontent.com/techiescamp/kubeadm-scripts/main/manifests/metrics-server.yaml -o metrics.yaml
kubectl apply -f metrics.yaml
完成
这些步骤都正常执行完成后,通过kubectl get pods -n kube-system
你应该就能够看到集群里的pod状态了: