MENU

离线安装 Kubernetes 高可用集群并设置证书期限

March 2, 2024 • 博文

在查阅 Kubernetes 官方文档时,发现官方文档关于部署高可用集群的内容较为离散,本文整合相关内容并按照离线环境下的高可用集群安装进行一个较为完善的说明。

一、架构说明

本文旨在完成一个堆叠 ETCD 集群的高可用 Kubernetes 集群,包含三个层次,分别是工作节点,负载均衡器和控制平面节点,详细架构如下图:

堆叠的 etcd 拓扑
堆叠的 etcd 拓扑

从架构看,服务器类型分为三大部分:控制平面节点(含 etcd)、负载均衡器、工作节点。负载均衡器在本文档采用软件方案(Nginx + Keepalived 实现),后续部署说明按如下的服务器规划执行:

服务器类型IP主机名部署内容
负载均衡器10.10.0.12k8s-lb1Nginx、Keepalived
负载均衡器10.10.0.13k8s-lb2Nginx、Keepalived
负载均衡器10.10.0.14k8s-lb3Nginx、Keepalived
控制平面节点(含 etcd)10.10.0.15k8s-master1docker,cri-dockerd,kubeadm,kubectl,kubelet,kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,etcd
控制平面节点(含 etcd)10.10.0.16k8s-master2docker,cri-dockerd,kubeadm,kubectl,kubelet,kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,etcd
控制平面节点(含 etcd)10.10.0.17k8s-master3docker,cri-dockerd,kubeadm,kubectl,kubelet,kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,etcd
工作节点10.10.0.19k8s-node1docker,cri-dockerd,kubeadm,kubectl,kubelet,kube-proxy

说明 :

  • LB 的 IP:Port 设置为 10.10.0.18:16443
  • kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,etcd 均使用 Kubernetes 管理的容器部署
  • 工作节点可扩展,部署内容一样
  • 服务器操作系统本文档选择 Ubuntu 20.04,内核版本 5.15.0-112-generic
  • 架构中未提及网络部分,在 Kubernetes 集群中,容器网络由 CNI 网络插件实现,本文的部署使用 Calico 网络

二、准备物料

本文档说明的安装在非公网环境,需要先按如下内容在可访问公网的机器进行部署物料包的准备,如果是公网环境,自行将相应包使用包管理器安装,或者也按离线方式安装。

1 - 维护工具包

在后续维护中,我们需要进行 ipvs 规则查看、时间同步等操作,因此需要安装相关软件:

ipvs 相关:

时间同步相关:

工具包打包至 tools.tar.gz

2 - 容器运行时(Docker CE)

自 1.24 版起,Dockershim 已从 Kubernetes 项目中移除, 需要使用 cri-dockerd 适配器来将 Docker Engine 与 Kubernetes 集成,因此除了安装 Docker CE 外,还需要安装 cri-dockerd

Docker CE :

cri-dockerd :

Docker CE 安装包打包至 DockerCE.tar.gz

3 - kubeadm、kubelet、kubectl

使用 kubeadm 安装 Kubernetes 时,kubelet、kubectl 是作为二进制服务运行的,kubeadm 不负责安装,需要手动安装配置。如下为安装包下载地址:

Dep :

Kubeadm、kubelet、kubectl :

Kubeadm 等命令安装包打包至 kubeadm-init.tar.gz

4 - 基础服务镜像

安装完 kubeadm 后,可以通过命令 kubeadm config images list 查看安装需要的拉取的镜像清单,v1.28.5 对应的镜像清单如下,使用 docker pull 命令获取,国内访问可能受限,可使用代理或者阿里云的镜像:

registry.k8s.io/kube-apiserver:v1.28.5
registry.k8s.io/kube-controller-manager:v1.28.5
registry.k8s.io/kube-scheduler:v1.28.5
registry.k8s.io/kube-proxy:v1.28.5
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.9-0
registry.k8s.io/coredns/coredns:v1.10.1

基础服务镜像使用 docker save 命令归档至 kubeadm-k8s-1.28.5.tar.gz

5 - 负载均衡软件包

多个节点的 kube-apiserver 负载均衡采用 Nginx + Keepalived 的方案实现,需要安装 Nginx 和 Keepalived 软件,如下为安装包下载地址:

Nginx :

Keepalived :

Nginx 和 Keepalived 软件及其依赖打包至 nginx-lb.tar.gz

6 - Calico 网络服务

Calico 网络服务采用 Calico 官方的 Kubernetes Operator 进行部署,该 Operator 使用了如下镜像:

calico/apiserver:v3.27.0
calico/cni:v3.27.0
calico/csi:v3.27.0
calico/kube-controllers:v3.27.0
calico/node-driver-registrar:v3.27.0
calico/node:v3.27.0
calico/pod2daemon-flexvol:v3.27.0
calico/typha:v3.27.0
quay.io/tigera/operator:v1.32.3

服务镜像使用 docker save 命令归档至 calico-cni-3.27.0.tar.gz

同时需要使用两份配置文件

将配置文件下载后归档至 <strong>calico-manifests-3.27.0.tar.gz</strong>

7 - 打包所有物料

按如下目录结构存放上述物料包,并打包成 K8S-INSTALL.tar.gz ,安装时上传到各服务器节点,其中二进制文件 kubeadm_100Y 的生成参考第五部分。

截图_17050393866801.png

三、准备环境

1 - 服务器基本要求

  • 具备 Linux 兼容性的服务器
  • 2 GB 或更多的 RAM(如果少于这个数字将会影响你应用的运行内存)
  • CPU 2 核心及以上
  • 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以)
  • 如果机器存在一个以上的网络适配器,同时 Kubernetes 组件通过默认路由不可达,需要预先添加 IP 路由规则, 这样 Kubernetes 集群就可以通过对应的适配器完成连接。
  • 节点之中不可以有重复的主机名、MAC 地址或 product_uuid

    • 你可以使用命令 ip link 或 ifconfig -a 来获取网络接口的 MAC 地址
    • 可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验
  • 开启机器上的需要的端口

  • 交换分区的配置。kubelet 的默认行为是在节点上检测到交换内存时无法启动。 kubelet 自 v1.22 起已开始支持交换分区。自 v1.28 起,仅针对 cgroup v2 支持交换分区; kubelet 的 NodeSwap 特性门控处于 Beta 阶段,但默认被禁用。

    • 如果 kubelet 未被正确配置使用交换分区,则你必须禁用交换分区

说明:

kubeadm 的安装是通过使用动态链接的二进制文件完成的,安装时假设你的目标系统提供 glibc。 这个假设在许多 Linux 发行版(包括 Debian、Ubuntu、Fedora、CentOS 等)上是合理的, 但对于不包含默认 glibc 的自定义和轻量级发行版(如 Alpine Linux),情况并非总是如此。 预期的情况是,发行版要么包含 glibc, 要么提供了一个兼容层以提供所需的符号。

2 - 服务器初始化

基于上述需求,需要对所有服务器(Ubuntu 20.04)进行初始化配置,端口放通的配置这里不一一操作,直接关闭服务器防火墙实现放行(不建议公网环境这样操作):

# 确保每个节点上 MAC 地址和 product_uuid 的唯一性
ip link # 查看mac地址
sudo cat /sys/class/dmi/id/product_uuid

# 放行端口(此处关闭防火墙)
systemctl stop ufw.service
systemctl disable ufw.service
# 存在selinux的情况下,需要关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0

# 关闭swap
sudo swapoff -a 
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 根据架构说明中的服务器规划设置主机名
hostnamectl set-hostname <主机名>
# 配置hosts, 格式为 IP 主机名,添加所有节点的信息,请按时间情况修改
cat >> /etc/hosts << EOF
10.10.0.12 k8s-lb1
10.10.0.13 k8s-lb2
10.10.0.14 k8s-lb3
10.10.0.15 k8s-master1
10.10.0.16 k8s-master2
10.10.0.17 k8s-master3
10.10.0.19 k8s-node1
EOF

# 上传离线物料至各节点/opt/目录,物料清单如下:
# K8S-INSTALL.tar.gz

# 安装工具软件包
cd /opt/ && tar xzvf K8S-INSTALL.tar.gz
cd /opt/K8S-INSTALL/ubuntu20.04/ && tar xzvf tools.tar.gz
# apt-get install ntpdate ipvsadm ipset -y
dpkg -i tools/ntpdate_4.2.8p12+dfsg-3ubuntu4.20.04.1_amd64.deb
dpkg -i tools/ipvsadm_1.31-1_amd64.deb
dpkg -i tools/libipset13_7.5-1ubuntu0.20.04.1_amd64.deb
dpkg -i tools/ipset_7.5-1ubuntu0.20.04.1_amd64.deb

# 时间同步
timedatectl set-timezone Asia/Shanghai
timedatectl set-ntp no

# 修改为内部能访问的ntp服务器
ntpdate -u 10.x.x.x

3 - 安装容器运行时

基于运维习惯的考虑,容器运行时沿用 Docker CE,在使用容器运行时时,需要进行一些先决条件配置:

3-1 转发 IPv4 并让 iptables/ipvs 看到桥接流量

执行下述指令:

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF

modprobe -- overlay
modprobe -- br_netfilter
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack

# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# 应用 sysctl 参数而不重新启动
sysctl --system

通过运行以下指令确认 br_netfilter 和 overlay 模块被加载:

lsmod | grep br_netfilter
lsmod | grep overlay
lsmod | grep ip_vs

通过运行以下指令确认 net.bridge.bridge-nf-call-iptables、net.bridge.bridge-nf-call-ip6tables 和 net.ipv4.ip_forward 系统变量在你的 sysctl 配置中被设置为 1:

sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

上述命令中添加了对 IPVS 的支持,方便后续 kube-proxy 使用 ipvs 模式,参考 :kubernetes/pkg/proxy/ipvs/README.md at master · kubernetes/kubernetes · GitHub

3-2 配置 cgroup 驱动程序

在 Linux 上,控制组(CGroup)用于限制分配给进程的资源。

kubelet 和底层容器运行时都需要对接控制组来强制执行 为 Pod 和容器管理资源 并为诸如 CPU、内存这类资源设置请求和限制。若要对接控制组,kubelet 和容器运行时需要使用一个 cgroup 驱动 。 关键的一点是 kubelet 和容器运行时需使用相同的 cgroup 驱动并且采用相同的配置。

可用的 cgroup 驱动有两个:

cgroupfs

cgroupfs 驱动是 kubelet 中默认的 cgroup 驱动。 当使用 cgroupfs 驱动时, kubelet 和容器运行时将直接对接 cgroup 文件系统来配置 cgroup。

当 systemd 是初始化系统时, 不 推荐使用 cgroupfs 驱动,因为 systemd 期望系统上只有一个 cgroup 管理器。 此外,如果你使用 cgroup v2, 则应用 systemd cgroup 驱动取代 cgroupfs。

systemd

当某个 Linux 系统发行版使用 systemd 作为其初始化系统时,初始化进程会生成并使用一个 root 控制组(cgroup),并充当 cgroup 管理器。

systemd 与 cgroup 集成紧密,并将为每个 systemd 单元分配一个 cgroup。 因此,如果你 systemd 用作初始化系统,同时使用 cgroupfs 驱动,则系统中会存在两个不同的 cgroup 管理器。

同时存在两个 cgroup 管理器将造成系统中针对可用的资源和使用中的资源出现两个视图。某些情况下, 将 kubelet 和容器运行时配置为使用 cgroupfs、但为剩余的进程使用 systemd 的那些节点将在资源压力增大时变得不稳定。

当 systemd 是选定的初始化系统时,缓解这个不稳定问题的方法是针对 kubelet 和容器运行时将 systemd 用作 cgroup 驱动。

要将 systemd 设置为 cgroup 驱动,需编辑 KubeletConfiguration 的 cgroupDriver 选项,并将其设置为 systemd。例如:

说明:

从 v1.22 开始,在使用 kubeadm 创建集群时,如果用户没有在 KubeletConfiguration 下设置 cgroupDriver 字段,kubeadm 默认使用 systemd。

我们的部署配置 cgroup 驱动程序为 <strong>systemd </strong>, kubeadm 使用默认配置即可,无需操作。

Docker 需要配置 cgroup driver 为 systemd, 配置方法为在运行配置添加 native.cgroupdriver=systemd

3-3 安装 Docker CE 和 cri-dockerd

执行如下指令完成安装:

# 安装包已上传至/opt目录
cd /opt/K8S-INSTALL/ubuntu20.04/ && tar xzvf DockerCE.tar.gz
dpkg -i DockerCE/containerd.io_1.6.21-1_amd64.deb
dpkg -i DockerCE/docker-ce-cli_24.0.2-1~ubuntu.20.04~focal_amd64.deb
dpkg -i DockerCE/docker-ce_24.0.2-1~ubuntu.20.04~focal_amd64.deb
dpkg -i DockerCE/cri-dockerd_0.3.9.3-0.ubuntu-focal_amd64.deb
# 配置docker, 限制日志大小,调整工作目录为 /home 或其他数据盘, 配置运行时的 cgroup driver 为 systemd
# log-opts 需要和 kubelet 的KubeletConfiguration配置中容器日志文件相关配置保持一致避免冲突,
# max-size <-> containerLogMaxSize 默认 10m
# max-file <-> containerLogMaxFiles 默认 5
# 参考:https://github.com/Mirantis/cri-dockerd/issues/35
cat > /etc/docker/daemon.json << EOF
{
  "log-driver": "json-file",
  "log-opts": {
                "max-size": "10m",
                "max-file": "5"
              },
  "data-root": "/home/docker",
  "exec-opts": ["native.cgroupdriver=systemd"],
  "insecure-registries": ["dockerhub.kubekey.local"]
}

EOF
systemctl restart docker

# 修改 cri-dockerd 默认的基础镜像,以适配当前版本的 Kubernetes 的 pause 镜像
cat > /usr/lib/systemd/system/cri-docker.service << EOF
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket

[Service]
Type=notify
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image=registry.k8s.io/pause:3.9
ExecReload=/bin/kill -s HUP \$MAINPID
TimeoutSec=0
RestartSec=2
Restart=always

# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3

# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl restart cri-docker

通过运行如下命令查看 cri-dockerd 的运行情况, cri-dockerd 依赖 conntrack 二进制,后续在安装 kubeadm 等软件时安装

systemctl status cri-docker

通过运行如下命令查看 docker ce 的运行情况

systemctl status docker

通过运行如下命令查看 docker ce 的 cgroupdriver 是否配置为 systemd

docker info | grep 'Cgroup Driver'

4 - 安装 kubeadm、kubelet 和 kubectl

本章节说明如何安装 kubeadm 工具箱。假设安装包已上传至节点的 /opt 目录,执行如下命令完成安装:

cd /opt/K8S-INSTALL/ubuntu20.04/ && tar xzvf kubeadm-init.tar.gz
dpkg -i kubeadm-init/conntrack_1.4.5-2_amd64.deb
dpkg -i kubeadm-init/ebtables_2.0.11-3build1_amd64.deb
dpkg -i kubeadm-init/socat_1.7.3.3-2_amd64.deb
dpkg -i kubeadm-init/cri-tools_1.28.0-1.1_amd64.deb
dpkg -i kubeadm-init/kubernetes-cni_1.2.0-2.1_amd64.deb
dpkg -i kubeadm-init/kubectl_1.28.5-1.1_amd64.deb
dpkg -i kubeadm-init/kubelet_1.28.5-1.1_amd64.deb
dpkg -i kubeadm-init/kubeadm_1.28.5-1.1_amd64.deb
# 锁定版本
apt-mark hold kubelet kubeadm kubectl
# 重启 cri-dockerd,解决其 conntrack 依赖问题
systemctl restart cri-docker
kubelet 现在每隔几秒就会重启,因为它陷入了一个等待 kubeadm 指令的死循环。

5 - 替换 kubeadm 为证书 100 年有效期修改版(对应 kubeadm v1.28.5)

默认 kubeadm 生成的证书是 1 年有效期,通过修改源码重新编译默认生成 100 年有效期证书的 kubeadm ,保证集群的稳定,执行以下命令完成命令的备份和替换:

mv /usr/bin/kubeadm /usr/bin/kubeadm_backup
cp /opt/K8S-INSTALL/kubeadm_100Y /usr/bin/kubeadm
chown root:root /usr/bin/kubeadm
chmod +x /usr/bin/kubeadm
# 验证版本
kubeadm version

三、部署 Nginx Keepalived 高可用负载均衡层

使用 https://10.10.0.18:16443 作为 Kubernetes 控制面的负载均衡地址,在选定的三台机器(10.10.0.13,10.10.0.12,10.10.0.14)上部署如下负载均衡组件:

# 三个负载均衡节点安装nginx和keepalived
cd /opt && tar xzvf nginx-lb.tar.gz
# apt-get install nginx -y
dpkg -i nginx-lb/fonts-dejavu-core_2.37-1_all.deb
dpkg -i nginx-lb/fontconfig-config_2.13.1-2ubuntu3_all.deb
dpkg -i nginx-lb/libfontconfig1_2.13.1-2ubuntu3_amd64.deb
dpkg -i nginx-lb/libjpeg-turbo8_2.0.3-0ubuntu1.20.04.3_amd64.deb
dpkg -i nginx-lb/libjpeg8_8c-2ubuntu8_amd64.deb
dpkg -i nginx-lb/libjbig0_2.1-3.1ubuntu0.20.04.1_amd64.deb
dpkg -i nginx-lb/libwebp6_0.6.1-2ubuntu0.20.04.3_amd64.deb
dpkg -i nginx-lb/libtiff5_4.1.0+git191117-2ubuntu0.20.04.11_amd64.deb
dpkg -i nginx-lb/libxpm4_3.5.12-1ubuntu0.20.04.2_amd64.deb
dpkg -i nginx-lb/libgd3_2.2.5-5.2ubuntu2.1_amd64.deb
dpkg -i nginx-lb/nginx-common_1.18.0-0ubuntu1.4_all.deb
dpkg -i nginx-lb/libnginx-mod-http-image-filter_1.18.0-0ubuntu1.4_amd64.deb
dpkg -i nginx-lb/libnginx-mod-http-xslt-filter_1.18.0-0ubuntu1.4_amd64.deb
dpkg -i nginx-lb/libnginx-mod-mail_1.18.0-0ubuntu1.4_amd64.deb
dpkg -i nginx-lb/libnginx-mod-stream_1.18.0-0ubuntu1.4_amd64.deb
dpkg -i nginx-lb/nginx-core_1.18.0-0ubuntu1.4_amd64.deb
dpkg -i nginx-lb/nginx_1.18.0-0ubuntu1.4_all.deb

# apt-get install keepalived -y
dpkg -i nginx-lb/mysql-common_5.8+1.0.5ubuntu2_all.deb
dpkg -i nginx-lb/libmysqlclient21_8.0.35-0ubuntu0.20.04.1_amd64.deb
dpkg -i nginx-lb/libsensors-config_3.6.0-2ubuntu1.1_all.deb
dpkg -i nginx-lb/libsensors5_3.6.0-2ubuntu1.1_amd64.deb
dpkg -i nginx-lb/libsnmp-base_5.8+dfsg-2ubuntu2.9_all.deb
dpkg -i nginx-lb/libsnmp35_5.8+dfsg-2ubuntu2.9_amd64.deb
dpkg -i nginx-lb/keepalived_2.0.19-2ubuntu0.2_amd64.deb

# 配置nginx负载均衡master节点
cat > /etc/nginx/nginx.conf << EOF
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024;
}

# 四层负载均衡,为多台Master apiserver组件提供负载均衡
stream {

    log_format  main  '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';

    access_log  /var/log/nginx/k8s-access.log  main;

    upstream k8s-apiserver {
       server 10.10.0.15:6443 weight=1 max_fails=2 fail_timeout=30s;   # Master1 APISERVER IP:PORT
       server 10.10.0.16:6443 weight=1 max_fails=2 fail_timeout=30s;   # Master2 APISERVER IP:PORT
       server 10.10.0.17:6443 weight=1 max_fails=2 fail_timeout=30s;  # Master3 APISERVER IP:PORT
    }
  
    server {
       listen 16443; # 如果nginx与master节点复用,这个监听端口不能是6443,否则会冲突
       proxy_pass k8s-apiserver;
    }
}

EOF

# 启动nginx
systemctl start nginx
systemctl enable nginx

# 所有节点配置检查nginx进程状态的脚本
cat > /etc/keepalived/check_nginx.sh  << "EOF"
#!/bin/bash
count=$(ss -antp |grep 16443 |egrep -cv "grep|$$")

if [ "$count" -eq 0 ];then
    exit 1
else
    exit 0
fi
EOF
chmod +x /etc/keepalived/check_nginx.sh

# 配置10.10.0.12的keepalived(非抢占式)
cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
    script_user root
    enable_script_security
    router_id LVS_DEVEL
}
vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    state BACKUP
    interface bond0 # 修改为实际网卡名
    virtual_router_id 55 # VRRP 路由 ID实例,每个实例是唯一的 
    priority 100
    nopreempt # 非抢占式
    advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒 
 
    unicast_peer{
      10.10.0.13
      10.10.0.14
    }

    authentication {
        auth_type PASS
        auth_pass kube@123
    }
 
    virtual_ipaddress {
        10.10.0.18
    }

    track_script {
        check_nginx
    } 
}

EOF

# 配置10.10.0.13的keepalived(非抢占式)

cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
    script_user root
    enable_script_security
    router_id LVS_DEVEL
}
vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    state BACKUP
    interface eno1np0 # 修改为实际网卡名
    virtual_router_id 55 # VRRP 路由 ID实例,每个实例是唯一的 
    priority 90
    nopreempt # 非抢占式
    advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒 
 
    unicast_peer{
      10.10.0.12
      10.10.0.14
    }

    authentication {
        auth_type PASS
        auth_pass kube@123
    }
 
    virtual_ipaddress {
        10.10.0.18
    }

    track_script {
        check_nginx
    } 
}

EOF

# 配置10.10.0.14的keepalived(非抢占式)
cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
    script_user root
    enable_script_security
    router_id LVS_DEVEL
}
vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    state BACKUP
    interface bond0 # 修改为实际网卡名
    virtual_router_id 55 # VRRP 路由 ID实例,每个实例是唯一的 
    priority 70
    nopreempt # 非抢占式
    advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒 
 
    unicast_peer{
      10.10.0.12
      10.10.0.13
    }

    authentication {
        auth_type PASS
        auth_pass kube@123
    }
 
    virtual_ipaddress {
        10.10.0.18
    }

    track_script {
        check_nginx
    } 
}

EOF

# 启动keepalived
systemctl restart keepalived
systemctl enable keepalived

四、部署 Kubernetes

使用 kubeadm 安装 Kubernetes 控制平面,本文档旨在安装一个三个控制面多个工作节点的 Kubernetes 集群,因此安装命令参数需要添加如下内容:

  • --control-plane-endpoint= 10.10.0.18:16443 :计划将单个控制平面 kubeadm 集群升级成高可用, 你应该指定 --control-plane-endpoint 为所有控制平面节点设置共享端点。 端点可以是负载均衡器的 DNS 名称或 IP 地址。
  • --pod-network-cidr=192.168.0.0/16 : Pod 网络插件使用 Calico,Calico 默认使用的 Pod 网络地址范围为 192.168.0.0/16
  • --cri-socket=unix:///var/run/cri-dockerd.sock : 使用了 cri-dockerd 适配器将 Docker CE 集成进 Kubernetes,需要指定使用的容器运行时连接 socket 为 cri-dockerd 的 unix:///var/run/cri-dockerd.sock
  • --kubernetes-version=v1.28.5 : 指定安装的 Kubernetes 版本
  • kube-proxy 使用 ipvs 模式
  • --upload-certs 标志用来将在所有控制平面实例之间的共享证书上传到集群。 如果正好相反,你更喜欢手动地通过控制平面节点或者使用自动化工具复制证书, 请删除此标志并参考如下部分证书分配手册。

命令参数说明:kubeadm init | Kubernetes

3-1 生成 kubeadm init 配置

注意:本节步骤只需要在主节点 1 执行,作为第一个安装的控制节点。

我们使用 kubeadm config print init-defaults > kubeadm_init_config.yaml 命令生成默认配置,在此基础上修改或添加我们自定义的参数配置,修改后的文件 kubeadm_init_config.yaml 内容如下:

cd /opt/K8S-INSTALL/
cat > /opt/K8S-INSTALL/kubeadm_init_config.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  bindPort: 6443
nodeRegistration:
  # 配置 docker ce 为容器运行时
  criSocket: unix:///var/run/cri-dockerd.sock
  imagePullPolicy: IfNotPresent
  taints: null
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
  local:
# 必要时修改etcd存储路径
    dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kind: ClusterConfiguration
# 配置集群控制面负载地址
controlPlaneEndpoint: 10.10.0.18:16443
# 安装 Kubernetes 1.28.5 版本
kubernetesVersion: 1.28.5
networking:
  dnsDomain: cluster.local
  # Calico 网络默认的Pod子网
  podSubnet: 192.168.0.0/16
  serviceSubnet: 192.169.0.0/12
scheduler: {}
---
# 配置kube-proxy为 ipvs 模式
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
EOF

3-2 导入基础镜像

假设已经镜像包上传至各节点的 /opt 目录,在所有 Kubernetes 节点执行如下命令完成镜像的导入:

docker load -i /opt/K8S-INSTALL/images/kubeadm-k8s-1.28.5.tar.gz

3-3 执行安装命令

在主节点 1 上执行如下命令开始安装 Kubernetes 控制节点:

kubeadm init --config /opt/K8S-INSTALL/kubeadm_init_config.yaml --upload-certs

完成后输出如下内容:

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join 10.10.0.18:16443 --token g8v4vv.jez3btz6kb6oy9rn \
        --discovery-token-ca-cert-hash sha256:d976b88a2fab6538f38b9f934b6f889b136605861e35d5d3295bae2c1173126b \
        --control-plane --certificate-key afafa37b37ef47d8f80bfe6e865c75dc80e84fdec30d068adbdef9ae7a56a2f3

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 --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 10.10.0.18:16443 --token g8v4vv.jez3btz6kb6oy9rn \
        --discovery-token-ca-cert-hash sha256:d976b88a2fab6538f38b9f934b6f889b136605861e35d5d3295bae2c1173126b

按照说明执行如下命令完成 kubectl 的连接配置:

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

3-4 添加其他控制面节点

根据 3-3 部署完成后输出的命令提示,在其他控制面节点使用如下命令完成控制面节点部署并加入集群,注意指定 --cri-socket unix:///var/run/cri-dockerd.sock ,certificate-key 的有效期为 2 小时,过期后使用命令 kubeadm init phase upload-certs --upload-certs 重新获取:

# 添加节点
kubeadm join 10.10.0.18:16443 --token f8yzvp.ng0pnlnvhbohvttv \
        --discovery-token-ca-cert-hash sha256:19d95c39b9630ffa896e5209e0e0d2682b5fffc449c20fd3b7b54bef7339972b \
        --control-plane --certificate-key cc89ea3987e5a078652ea24ef864d6084c862459555927ac42e672dc342efbef \
        --cri-socket unix:///var/run/cri-dockerd.sock

命令执行成功后输出如下内容:

This node has joined the cluster and a new control plane instance was created:

  • Certificate signing request was sent to apiserver and approval was received.
  • The Kubelet was informed of the new secure connection details.
  • Control plane label and taint were applied to the new node.
  • The Kubernetes control plane instances scaled up.
  • A new etcd member was added to the local/stacked etcd cluster.

To start administering your cluster from this node, you need to run the following as a regular user:

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

Run 'kubectl get nodes' to see this node join the cluster.

按照说明执行如下命令完成 kubectl 的连接配置:

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

此时可以执行 kubectl get nodes 命令获取已安装的控制名节点,节点在未安装完成网络插件前状态都将是 NotReady :

root@k8s-master3:~# kubectl get nodes

NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane 11m v1.28.5
k8s-master2 NotReady control-plane 4m58s v1.28.5
k8s-master3 NotReady control-plane 4m8s v1.28.5

3-5 添加工作节点

根据 3-3 部署完成后输出的命令提示,在工作节点使用如下命令完成工作节点部署并加入集群,注意指定 --cri-socket unix:///var/run/cri-dockerd.sock ,指定的 token 有效期为 24 小时:

kubeadm join 10.10.0.18:16443 --token f8yzvp.ng0pnlnvhbohvttv \
        --discovery-token-ca-cert-hash sha256:19d95c39b9630ffa896e5209e0e0d2682b5fffc449c20fd3b7b54bef7339972b \
        --cri-socket unix:///var/run/cri-dockerd.sock

命令执行成功后输出如下内容:

This node has joined the cluster:

  • Certificate signing request was sent to apiserver and a response was received.
  • The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

此时可以在控制节点执行 kubectl get nodes 命令获取已安装的控制名节点,节点在未安装完成网络插件前状态都将是 NotReady :

root@k8s-master3:~# kubectl get nodes NAME STATUS ROLES AGE VERSION

k8s-master1 NotReady control-plane 18m v1.28.5
k8s-master2 NotReady control-plane 12m v1.28.5
k8s-master3 NotReady control-plane 11m v1.28.5
k8s-node1 NotReady 106s v1.28.5

3-6 部署 Calico 网络插件

参考:Quickstart for Calico on Kubernetes | Calico Documentation (tigera.io)

Calico 是一种开源网络和网络安全解决方案,适用于容器,虚拟机和基于主机的本机工作负载。Calico 支持广泛的平台,包括 Kubernetes,docker,OpenStack 和裸机服务。Calico 后端支持多种网络模式。

  • BGP 模式:将节点做为虚拟路由器通过 BGP 路由协议来实现集群内容器之间的网络访问。
  • IPIP 模式:在原有 IP 报文中封装一个新的 IP 报文,新的 IP 报文中将源地址 IP 和目的地址 IP 都修改为对端宿主机 IP。
  • cross-subnet:Calico-ipip 模式和 calico-bgp 模式都有对应的局限性,对于一些主机跨子网而又无法使网络设备使用 BGP 的场景可以使用 cross-subnet 模式,实现同子网机器使用 calico-BGP 模式,跨子网机器使用 calico-ipip 模式。

部署完成后默认使用 calico-ipip 的模式

各节点加载镜像 :

以下命令在所有 Kubernetes 节点执行:

docker load -i /opt/K8S-INSTALL/images/calico-cni-3.27.0.tar.gz

安装 Calico :

如下指令在任意一个控制面节点执行:

cd /opt/K8S-INSTALL/ && tar xzvf calico-manifests-3.27.0.tar.gz
kubectl create -f calico-manifests-3.27.0/tigera-operator.yaml
# 如果 pod 网段不是 192.168.0.0/16 , 对应修改 custom-resources.yaml 文件内容
kubectl create -f calico-manifests-3.27.0/custom-resources.yaml

执行如下命令等待所有 Pod 的 STATUS 栏变成 Running 即完成 Calico 的安装 :

watch kubectl get pods -n calico-system

Every 2.0s: kubectl get pods -n calico-system k8s-master1: Thu Jan 11 15:46:28 2024

NAME READY STATUS RESTARTS AGE
calico-kube-controllers-78b56f45bc-b2skt 1/1 Running 0 3m34s
calico-node-cxh5z 1/1 Running 0 3m34s
calico-node-jgdjh 1/1 Running 0 3m34s
calico-node-qcjr5 1/1 Running 0 3m34s
calico-node-z6bxl 1/1 Running 0 3m34s
calico-typha-5df98d9d45-mfkpv 1/1 Running 0 3m25s
calico-typha-5df98d9d45-z2f7t 1/1 Running 0 3m34s
csi-node-driver-c5bjh 2/2 Running 0 3m34s
csi-node-driver-fvs5b 2/2 Running 0 3m34s
csi-node-driver-gktvt 2/2 Running 0 3m34s
csi-node-driver-ktg54 2/2 Running 0 3m34s

执行如下命令等待所有 Pod 的 STATUS 栏变成 Running 即完成 Calico api-server 的安装 :

watch kubectl get pods -n calico-apiserver

Every 2.0s: kubectl get pods -n calico-apiserver

k8s-master1: Thu Jan 11 16:09:22 2024
NAME READY STATUS RESTARTS AGE
calico-apiserver-747499f6b8-bz8f2 1/1 Running 0 76s
calico-apiserver-747499f6b8-g9l8n 1/1 Running 0 2m14s

所有 Pod 状态均为 Running 后,执行如下命令获取各节点状态将为 Ready :

kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane 106m v1.28.5
k8s-master2 Ready control-plane 100m v1.28.5
k8s-master3 Ready control-plane 99m v1.28.5
k8s-node1 Ready 89m v1.28.5

至此,Kubernetes 高可用集群就安装完成了 ,后续如果需要添加工作节点或者控制节点,按 3-4 、3-5 操作即可,注意修改 token 和 certificate-key 为新生成的。

# 重新创建 token 命令
kubeadm token create --print-join-command
# 重新创建 certificate-key 命令
kubeadm init phase upload-certs --upload-certs
# 获取 discovery-token-ca-cert-hash 的值
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
   openssl dgst -sha256 -hex | sed 's/^.* //'

五、自编译 Kubeadm 使证书默认 100 年有效期

Kubernetes v1.25 编译 kubeadm 修改证书有效期到 100 年 - sysin - 博客园 (cnblogs.com)

kubeadm 安装的 k8s 证书过期升级为 100 年证书_k8s 证书改 100 年-CSDN 博客

默认的 kubeadm 命令生成的证书有效期是 1 年,虽然谷歌推荐每年使用 kubeadm 续期,但实际环境对 Kubernetes 集群的改动较小,为了环境稳定,使用一个 10 年以上的证书可以减少麻烦。常用有效的办法就行修改 kubeadm 的源码,修改代码中默认的有效期为 100 年,然后编译成二进制文件替换默认版本。以下说明如何进行修改和编译。

5-1 下载对应版本源码

访问:https://github.com/kubernetes/kubernetes/releases,下载特定版本源码,这里获取 v1.28.5 版本的

wget https://github.com/kubernetes/kubernetes/archive/refs/tags/v1.28.5.tar.gz
tar -zxvf kubernetes-1.28.5.tar.gz
mv kubernetes-1.28.5 kubernetes
cd kubernetes

5-2 修改源码

主要有两个地方需要修改(v1.28.5 版本后是否会变动暂不可知)

5-2-1 修改 CA 有效期为 100 年(默认为 10 年)

vim ./staging/src/k8s.io/client-go/util/cert/cert.go
// 这个方法里面 NotAfter:              now.Add(duration365d * 10).UTC()
// 默认有效期就是 10 年,改成 100 年 (sysin)
// 输入 /NotAfter 查找,回车定位
func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, error) {
        now := time.Now()
        tmpl := x509.Certificate{
                SerialNumber: new(big.Int).SetInt64(0),
                Subject: pkix.Name{
                        CommonName:   cfg.CommonName,
                        Organization: cfg.Organization,
                },
                NotBefore:             now.UTC(),
                // NotAfter:              now.Add(duration365d * 10).UTC(),
                NotAfter:              now.Add(duration365d * 100).UTC(),
                KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
                BasicConstraintsValid: true,
                IsCA:                  true,
        }

        certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &tmpl, &tmpl, key.Public(), key)
        if err != nil {
                return nil, err
        }
        return x509.ParseCertificate(certDERBytes)
}

5-2-2 修改证书有效期为 100 年(默认为 1 年)

vim ./cmd/kubeadm/app/constants/constants.go
// 就是这个常量定义 CertificateValidity,改成 * 100 年 (sysin)
// 输入 /CertificateValidity 查找,回车定位
const (
        // KubernetesDir is the directory Kubernetes owns for storing various configuration files
        KubernetesDir = "/etc/kubernetes"
        // ManifestsSubDirName defines directory name to store manifests
        ManifestsSubDirName = "manifests"
        // TempDirForKubeadm defines temporary directory for kubeadm
        // should be joined with KubernetesDir.
        TempDirForKubeadm = "tmp"

        // CertificateValidity defines the validity for all the signed certificates generated by kubeadm
        // CertificateValidity = time.Hour * 24 * 365
        CertificateValidity = time.Hour * 24 * 365 * 100

        // CACertAndKeyBaseName defines certificate authority base name
        CACertAndKeyBaseName = "ca"
        // CACertName defines certificate name
        CACertName = "ca.crt"
        // CAKeyName defines certificate name
        CAKeyName = "ca.key"

验证一下已经正确修改:

cat ./staging/src/k8s.io/client-go/util/cert/cert.go | grep NotAfter
cat ./cmd/kubeadm/app/constants/constants.go | grep CertificateValidity

5-3 安装编译环境

官方编译说明 : kubernetes/build/README.md at 4b94168c0f724bbf1edfd846a8e788a32d9a5c49 · kubernetes/kubernetes · GitHub

apt-get install make

dkpg -i docker-buildx-plugin_0.11.2-1\~ubuntu.20.04~focal_amd64.deb

docker pull registry.k8s.io/build-image/kube-cross:v1.28.0-go1.20.12-bullseye.0 (编译镜像)

其他镜像,但只编译二进制文件不需要其他的

5-4 编译二进制

我们只需生成新的 kubeadm 二进制文件,不需要整个 Release 包,执行如下命令只编译二进制文件

# kubernetes 源码根目录执行
build/make-clean.sh
build/run.sh make
root@k8s-master1:/opt/kubernetes# build/run.sh make
+++ [0112 10:13:26] Verifying Prerequisites....
+++ [0112 10:13:26] Building Docker image kube-build:build-9146bf4b41-5-v1.28.0-go1.20.12-bullseye.0
+++ [0112 10:13:27] Syncing sources to container
+++ [0112 10:13:29] Output from this container will be rsynced out upon completion. Set KUBE_RUN_COPY_OUTPUT=n to disable.
+++ [0112 10:13:29] Running build command... Go version: go version go1.20.12 linux/amd64
+++ [0112 10:13:29] Building go targets for linux/amd64 k8s.io/kubernetes/cmd/kube-proxy (static) k8s.io/kubernetes/cmd/kube-apiserver (static) k8s.io/kubernetes/cmd/kube-controller-manager (static) k8s.io/kubernetes/cmd/kubelet (non-static) k8s.io/kubernetes/cmd/kubeadm (static) k8s.io/kubernetes/cmd/kube-scheduler (static) k8s.io/component-base/logs/kube-log-runner (static) k8s.io/kube-aggregator (static) k8s.io/apiextensions-apiserver (static) k8s.io/kubernetes/cluster/gce/gci/mounter (non-static) k8s.io/kubernetes/cmd/kubectl (static) k8s.io/kubernetes/cmd/kubectl-convert (static) github.com/onsi/ginkgo/v2/ginkgo (non-static) k8s.io/kubernetes/test/e2e/e2e.test (test) k8s.io/kubernetes/test/conformance/image/go-runner (non-static) k8s.io/kubernetes/cmd/kubemark (static) github.com/onsi/ginkgo/v2/ginkgo (non-static) k8s.io/kubernetes/test/e2e_node/e2e_node.test (test) Env for linux/amd64: GOOS=linux GOARCH=amd64 GOROOT=/usr/local/go CGO_ENABLED= CC= Coverage is disabled. Coverage is disabled.
+++ [0112 10:14:21] Placing binaries
+++ [0112 10:14:41] Syncing out of container root@k8s-master1:/opt/kubernetes# build/make-clean.sh
+++ [0112 10:18:58] Verifying Prerequisites....
+++ [0112 10:18:58] Deleting container kube-build-data-9146bf4b41-5-v1.28.0-go1.20.12-bullseye.0
+++ [0112 10:19:00] Deleting image kube-build:build-9146bf4b41-5-v1.28.0-go1.20.12-bullseye.0
+++ [0112 10:19:00] Cleaning all untagged docker images
+++ [0112 10:19:00] Removing _output directory root@k8s-master1:/opt/kubernetes# build/run.sh make
+++ [0112 10:19:05] Verifying Prerequisites....
+++ [0112 10:19:05] Building Docker image kube-build:build-9146bf4b41-5-v1.28.0-go1.20.12-bullseye.0
+++ [0112 10:19:06] Creating data container kube-build-data-9146bf4b41-5-v1.28.0-go1.20.12-bullseye.0
+++ [0112 10:19:10] Syncing sources to container
+++ [0112 10:19:20] Output from this container will be rsynced out upon completion. Set KUBE_RUN_COPY_OUTPUT=n to disable.
+++ [0112 10:19:20] Running build command... Go version: go version go1.20.12 linux/amd64
+++ [0112 10:19:21] Building go targets for linux/amd64 k8s.io/kubernetes/cmd/kube-proxy (static) k8s.io/kubernetes/cmd/kube-apiserver (static) k8s.io/kubernetes/cmd/kube-controller-manager (static) k8s.io/kubernetes/cmd/kubelet (non-static) k8s.io/kubernetes/cmd/kubeadm (static) k8s.io/kubernetes/cmd/kube-scheduler (static) k8s.io/component-base/logs/kube-log-runner (static) k8s.io/kube-aggregator (static) k8s.io/apiextensions-apiserver (static) k8s.io/kubernetes/cluster/gce/gci/mounter (non-static) k8s.io/kubernetes/cmd/kubectl (static) k8s.io/kubernetes/cmd/kubectl-convert (static) github.com/onsi/ginkgo/v2/ginkgo (non-static) k8s.io/kubernetes/test/e2e/e2e.test (test) k8s.io/kubernetes/test/conformance/image/go-runner (non-static) k8s.io/kubernetes/cmd/kubemark (static) github.com/onsi/ginkgo/v2/ginkgo (non-static) k8s.io/kubernetes/test/e2e_node/e2e_node.test (test) Env for linux/amd64: GOOS=linux GOARCH=amd64 GOROOT=/usr/local/go CGO_ENABLED= CC= Coverage is disabled. Coverage is disabled.
+++ [0112 10:27:10] Placing binaries
+++ [0112 10:27:27] Syncing out of container

编译完产物在 _output/dockerized/bin/linux/amd64/ 目录下

5-5 备份原版,安装新版

mv /usr/bin/kubeadm /usr/bin/kubeadm_backup
cp _output/local/bin/linux/amd64/kubeadm /usr/bin/kubeadm
#chmod +x /usr/bin/kubeadm

# 验证版本
kubeadm version

# 压缩保存到用户主目录下
tar zcvf ~/kubeadm-1.25.0.tgz -C /usr/bin/ kubeadm

# 在其他(含工作节点)节点上替换原有版本
mv /usr/bin/kubeadm /usr/bin/kubeadm_backup
tar zxvf ./kubeadm-1.25.0.tgz -C /usr/bin/

5-6 【原版 kubeadm 安装前】正常使用修改后的命令安装集群即可

5-6 【原版 kubeadm 安装后】执行命令更新证书

如果是使用原版 kubeadm 安装之后,可以手动执行命令更新证书有效期到 100 年。

可以先备份证书,证书在 /etc/kubernetes/pki

# 续订全部证书
kubeadm certs renew all
# 重启  kube-apiserver, kube-controller-manager, kube-scheduler , etcd
kubectl -n kube-system delete pod kube-scheduler-k8s-master1 kube-scheduler-k8s-master2 kube-scheduler-k8s-master3 kube-controller-manager-k8s-master1 kube-controller-manager-k8s-master2 kube-controller-manager-k8s-master3 kube-apiserver-k8s-master1 kube-apiserver-k8s-master2 kube-apiserver-k8s-master3 etcd-k8s-master1 etcd-k8s-master2 etcd-k8s-master3
# 查看当前有效期,ca证书是init的时候生成的,这个命令刷新不了
kubeadm certs check-expiration

root@k8s-master1:/opt# kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'

CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Dec 19, 2123 02:46 UTC 99y ca no
apiserver Dec 19, 2123 02:46 UTC 99y ca no
apiserver-etcd-client Dec 19, 2123 02:46 UTC 99y etcd-ca no
apiserver-kubelet-client Dec 19, 2123 02:46 UTC 99y ca no
controller-manager.conf Dec 19, 2123 02:46 UTC 99y ca no
etcd-healthcheck-client Dec 19, 2123 02:46 UTC 99y etcd-ca no
etcd-peer Dec 19, 2123 02:46 UTC 99y etcd-ca no
etcd-server Dec 19, 2123 02:46 UTC 99y etcd-ca no
front-proxy-client Dec 19, 2123 02:46 UTC 99y front-proxy-ca no
scheduler.conf Dec 19, 2123 02:46 UTC 99y ca no

CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Jan 08, 2034 06:21 UTC 9y no
etcd-ca Jan 08, 2034 06:21 UTC 9y no
front-proxy-ca Jan 08, 2034 06:21 UTC 9y no

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