Kubernetes安装部署

文章目录

开篇导读

Docker是一个非常流行的容器化平台,它可以让我们方便构建、打包、发布和运行容器化应用程序。但是,在生产环境中,我们可能需要处理成百上千个容器,需要更好的管理这些容器,这就是Kubernetes的用武之地。Kubernetes是一个开源容器编排系统,它可以管理和部署容器化应用程序,自动化容器部署、扩展和故障恢复。Kubernetes可以让我们更好管理容器与容器相关的资源和服务,同时提供了许多强大的功能,如:负载均衡、自动扩展、滚动更新、健康检查等。Kubernetes的安装方法有很多,但官方推荐的只包括Kubeadm二进制安装。因为Kubeadm和二进制安装可以提供更加稳定、更适合生产环境的Kubernetes。本文将演示如何使用二进制和kubeadm快速部署一个 Kubernetes v1.30 集群。

先了解下,Kubeadm和二进制两种安装方式的适用场景。Kubeadm是官方提供的开源工具,用于快速搭建K8S集群,也是比较方便和推荐的方式。其中的kubeadm initkubeadm join这两个命令可以快速创建K8S集群。Kubeadm可以初始化K8S,且所有的组件都以Pod形式运行,具有故障自恢复能力。Kubeadm相当于使用程序脚本帮助我们自动完成集群安装,简化部署操作,证书、组件资源清单文件都是自动创建的。自动部署屏蔽了很多细节,使用者对各个模块的了解较少,遇到问题比较难排错。因此,Kubeadm适合需要经常部署K8S或对自动化要求比较高的场景使用。二进制安装就是手动安装,步骤繁琐,对K8S理解的更加全面。

Kubernetes 部署方式有很多,建议使用CNCF认证的安装方法进行安装,更多安装方法:https://www.cncf.io/training/certification/software-conformance

环境准备

主机环境预设

本示例中的Kubernetes集群部署将基于以下环境进行

OS: CentOS 7.9.2009

内核版本:5.4.225

Kubernetes:v1.30.0

Container Runtime: Docker CE 23.0.5

CRI:cri-dockerd v0.3.1

测试使用的Kubernetes集群可由一个master主机及一个以上(建议至少两个)node主机组成,这些主机可以是物理服务器,也可以运行于vmware、virtualbox或kvm等虚拟化平台上的虚拟机,甚至是公有云上的VPS主机。本案例使用的是虚拟机来进行部署,服务器清单如下:

节点 ip 用途
master(3台) 192.168.209.101/102/103 Kubernetes控制端,通过一个vip做主备高可用
etcd(3台) 192.168.209.101/102/103 保存Kubernetes集群数据
harbor(2台) 192.168.209.101/102 镜像仓库
nginx (2台) 192.168.209.101/102 高可用etcd代理服务器
node(2-N台) 192.168.177.201/202 运行容器的服务器,高可用环境至少2台

配置静态ip

服务器或虚拟机的IP地址默认都是DHCP动态分配的,这样重启机器IP地址就会变化,为让IP固定不变,需设置静态IP。每台机器的ip都需要修改,我这里以master1为例

bash 复制代码
[root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
......
ONBOOT="yes"                   #开机启动网络,必须yes
BOOTPROTO="static"             #使用静态地址
IPADDR="192.168.209.101"       #IP地址,需要和自己计算机所在的网段一致
NETMASK="255.255.255.0"        #子网掩码,需要和自己计算机所在的网段一致
GATEWAY="192.168.209.2"        #网关,可以使用route -n查看自己电脑网关地址
DNS1="8.8.8.8"

配置文件修改完后,需要重启网络才能使配置生效

bash 复制代码
service network restart

升级内核

由于centos7.9的系统默认内核版本是3.10,3.10的内核有很多BUG,最常见的一个就是group memory leak。我们这里内核升级为5.4.225,查看我们本机的内核版本

bash 复制代码
wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-devel-5.4.225-1.el7.elrepo.x86_64.rpm
wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-5.4.225-1.el7.elrepo.x86_64.rpm

安装内核

bash 复制代码
rpm -ivh kernel-lt-5.4.225-1.el7.elrepo.x86_64.rpm
rpm -ivh kernel-lt-devel-5.4.225-1.el7.elrepo.x86_64.rpm

检查已安装内核版本

bash 复制代码
rpm -qa | grep kernel

查看系统上的所有可用内核

bash 复制代码
awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg

设置启动

bash 复制代码
grub2-set-default 0

生成 grub 配置文件,GRUB2 的配置文件通常为 /boot/grub2/grub.cfg,虽然此文件很灵活,但是我们并不需要手写所有内容。可以通过程序自动生成,或是直接修改生成之后的文件。通常情况下简单配置文件 /etc/default/grub ,然后用程序 grub-mkconfig 来产生文件 grub.cfg

bash 复制代码
grub2-mkconfig -o /boot/grub2/grub.cfg

重启机器

bash 复制代码
reboot

修改主机名

在K8s集群中,每个节点都需要一个唯一的名称标识自己,这个名称需要在加入集群时使用。若设置主机名,管理员可以更轻松管理容器,方便通过主机名识别和访问每个节点。在每个节点执行如下命令,修改主机名

bash 复制代码
#hostnamectl set-hostname <主机名>
hostnamectl set-hostname k8s-master1 
hostnamectl set-hostname k8s-master2 
hostnamectl set-hostname k8s-master3
hostnamectl set-hostname k8s-node1
hostnamectl set-hostname k8s-node2

配置hosts文件,把主机名称和IP对应关系添加到/etc/hosts。让每个k8s节点通过主机名互相通信,不需要记ip地址了,修改每台机器的/etc/hosts文件

bash 复制代码
cat >> /etc/hosts << EOF
192.168.209.101 k8s-master1
192.168.209.102 k8s-master2
192.168.209.103 k8s-master3
192.168.209.201 k8s-node1
192.168.209.202 k8s-node2
EOF

配置免密登录

配置控制节点到工作节点免密登录。在k8s集群中,控制节点需要能通过SSH链接到工作节点中,以执行各种命令和任务。每次都输入密码登录,非常麻烦,建议配置ssh免密登录,提高工作效率。在控制节点生成ssh密钥

bash 复制代码
ssh-keygen

选项直接回车,默认即可。 可以看到密钥文件生成在root目录下的.ssh目录中。默认情况下,生成一个id_rsa私钥文件和id_rsa.pub公钥文件,私钥应该保持安全,只有持有私钥的用户才能对它进行身份验证。公钥文件交给其他计算机上的授权用户,以便将它添加到本地计算机的授权列表,进而允许该用户在本地计算机上进行ssh连接。

安装 sshpass

bash 复制代码
yum install sshpass

接下来执行命令,将公钥文件发送给各个k8s节点服务器

bash 复制代码
for i in {1..5};do sshpass -p '123456' ssh-copy-id root@192.168.209.20$i ;done

以上命令分别将当前用户的公钥文件(默认~/.ssh/id_rsa.pub)复制到三个节点中,便于用户ssh免密登录。 ssh-copy-id工具会自动使用SSH协议进行连接,在目标计算机建立.ssh目录(若不存在),并将当前用户的公钥追加到目标计算机的~/.ssh/authorized_keys文件中。

关闭swap交换区

Linux中交换分区(Swap)类似于Windows的虚拟内存,就是当内存不足时,把一部分硬盘空间虚拟成内存使用,解决内存容量不足的问题。在k8s集群中,关闭交换分区可以确保内存不被交换出去,避免内存不足导致应用程序崩溃和节点异常。因为k8s在每个节点部署多个容器,若节点上的应用程序的内存超过了可用内存,操作系统就会将部分的内存换出到硬盘,降低了容器的性能和稳定性。所以在部署k8s集群时,需要关闭交换分区。kubelet 在 1.8 版本以后强制要求 swap 必须关闭,否则会报如下错误:

bash 复制代码
Running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false

或者kubeadm init时会报错:

bash 复制代码
[ERROR Swap]: running with swap on is not supported. Please disable swap

两种关闭方式,一种临时,一种永久

1、临时关闭

bash 复制代码
swapoff -a

2、永久关闭

使用vim命令打开/etc/fstab文件,直接注释掉挂载交换分区即可,每台机器都需要关闭

bash 复制代码
#/dev/mapper/centos-swap swap                    swap    defaults        0 0

fstab全称(File System Table),系统启动时,会读取这个文件的数据,并根据其中的信息自动挂载文件系统。所以最好重启下机器,重新读取一下fstab文件,或者再执行下临时方案就行了。

关闭防火墙

在安装k8s集群时,关闭Firewalld防火墙可以避免由于防火墙造成的k8s集群组件无法正常通信的问题。k8s需要使用大量的网络端口进行通信,包括etcd、kubelet、kube-proxy等组件都需要开放对应的端口才能工作。在关闭防火墙前,确保已经采取了安全措施,如安全组来保护节点安全问性。每台机器都执行

bash 复制代码
systemctl stop firewalld; systemctl disable firewalld

关闭SELinux

安装k8s集群,通常关闭SELinux,默认情况下,SELinux可能会阻止k8s某些操作,如挂载卷和访问容器日志等。可能使k8s无法正常工作。关闭SELinux,每台机器都执行

bash 复制代码
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

验证是否已经关闭,如果显示Disabled,那么说明已经关闭了

bash 复制代码
getenforce

配置时间同步

在k8s集群中,时间同步很重要,因为k8s各个组件之间需要通过时间戳确定事件的先后顺序,若各个节点的时间不同步,会导致k8s出现各种问题。每台机器都执行

bash 复制代码
yum -y install ntpdate		# 安装软件
ntpdate cn.pool.ntp.org 	# 同步网络时间

定时任务同步时间,每三十分钟执行一次

bash 复制代码
[root@k8s-master1 ~]# crontab -e
*/30 * * * * /usr/sbin/ntpdate cn.pool.ntp.org

如果第一次没有实现时间同步,可以使用相关命令来完成相关的同步操作,输入 ntpdate time1.aliyun.com ,然后回车

修改内核参数

安装IPVS

bash 复制代码
yum -y install conntrack-tools ipvsadm ipset conntrack libseccomp

加载 IPVS 模块、加载br_netfilter模块,kube-prox开启ipvs的前置条件。br_netfilter叫透明防火墙,又称桥接模式防火墙。就是在网桥设备中增加防火墙功能,开启ip6tables和iptables需要加载透明防火墙

bash 复制代码
cat > /etc/sysconfig/modules/ipvs.modules <<"EOF"
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"

for kernel_module in ${ipvs_modules}; do
    /sbin/modinfo -F filename ${kernel_module} > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        /sbin/modprobe ${kernel_module}
    fi
done
EOF

执行脚本

bash 复制代码
sh /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs

增加kubernetes转发配置

bash 复制代码
cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp.keepaliv.probes = 3
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp.max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp.max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 65536
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.top_timestamps = 0
net.core.somaxconn = 16384
EOF

立即生效

bash 复制代码
sysctl --system

接下来我们修改limits.conf文件

bash 复制代码
cat >> /etc/security/limits.conf << EOF
* soft nofile 655360
* hard nofile 131072
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF

部署 Keepalived + Nginx

在高可用 Kubernetes 集群中,可以通过 Keepalived + Nginx 实现 API Server 的高可用。这里为了节约服务器,将 Keepalived + Nginx 部署在 Master 节点上。Keepalived 提供固定入口(VIP),Nginx 提供负载均衡(16443 → 三台 Master 的 6443),最终实现 Kubernetes 控制平面的高可用。

Keepalived 提供虚拟IP:192.168.209.100,VIP 始终会漂移到某一台 Master 节点上,确保对外始终有一个固定的访问入口。Nginx 作为反向代理,在每台 Master 节点上部署 Nginx。Nginx 监听 16443 端口,对外提供统一的访问入口。Nginx 会将来自 VIP:16443 的请求,反向代理到本机或其他 Master 节点的 6443(Kubernetes API Server 的默认端口),这样就实现了多个 Master 节点的负载均衡。对 kubectl 客户端而言,只需要访问 192.168.209.100:16443。请求会先进入 Nginx,再由 Nginx 负载均衡转发到三台 Master 的 6443 端口,从而实现 API Server 的高可用。

haproxy+keepalived高可用如图所示

部署 Nginx

安装Nginx,我这里部署在了 k8s-master1 和 k8s-master2 节点。添加 CentOS 7 Nginx yum 资源库

bash 复制代码
sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

安装Nginx

bash 复制代码
yum -y install nginx

修改nginx配置文件,修改upstream处各个端口,改为三个master节点的IP

bash 复制代码
cat > /etc/nginx/nginx.conf << "EOF"
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

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 192.168.209.101:6443;          
       server 192.168.209.102:6443;          
       server 192.168.209.103:6443;              
    }
    server {
       listen 16443;                                    
       proxy_pass k8s-apiserver;     
    }
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    #gzip  on;
    include /etc/nginx/conf.d/*.conf;
}
EOF

启动nginx并设置开机自启

bash 复制代码
systemctl enable --now nginx.service && systemctl status nginx

安装 Keepalived

安装keepalived,我这里部署在了 k8s-master1 和 k8s-master2 节点

bash 复制代码
yum -y install keepalived

k8s-master1节点配置keepalived

bash 复制代码
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf_bak
NODE_IP=`hostname -i`
cat > /etc/keepalived/keepalived.conf <<EOF
  ! Configuration File for keepalived
  global_defs {
      router_id LVS_DEVEL
  }
  vrrp_script chk_kubernetes {
      script "/etc/keepalived/check_kubernetes.sh"    #检测脚本文件
      interval 5     #检测时间间隔
      weight -5      #权重
      fall 3
      rise 2
  }
  vrrp_instance VI_1 {
      state MASTER      # 主机状态master,从节点为BACKUP
      interface ens33   #设置实例绑定的网卡
      mcast_src_ip ${NODE_IP}  # 广播的原地址
      virtual_router_id 51   #同一实例下virtual_router_id必须相同
      priority 100           #设置优先级,优先级高的会被竞选为Master
      advert_int 2
      authentication {
          auth_type PASS
          auth_pass K8SHA_KA_AUTH
      }
      virtual_ipaddress {
          192.168.209.100     #设置VIP,可以设置多个
      }
  }
EOF

k8s-master2节点配置keepalived

bash 复制代码
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf_bak
NODE_IP=`hostname -i`
cat > /etc/keepalived/keepalived.conf <<EOF
  ! Configuration File for keepalived
  global_defs {
      router_id LVS_DEVEL
  }
  vrrp_script chk_kubernetes {
      script "/etc/keepalived/check_kubernetes.sh"    #检测脚本文件
      interval 5     #检测时间间隔
      weight -5      #权重
      fall 3
      rise 2
  }
  vrrp_instance VI_1 {
      state BACKUP      # 主机状态master,从节点为BACKUP
      interface ens33   #设置实例绑定的网卡
      mcast_src_ip ${NODE_IP}  # 广播的原地址
      virtual_router_id 51   #同一实例下virtual_router_id必须相同
      priority 100           #设置优先级,优先级高的会被竞选为Master
      advert_int 2
      authentication {
          auth_type PASS
          auth_pass K8SHA_KA_AUTH
      }
      virtual_ipaddress {
          192.168.209.100     #设置VIP,可以设置多个
      }
  }
EOF

启动keepalived,并设置开机自启

bash 复制代码
systemctl enable --now keepalived && systemctl status keepalived

在 k8s-master1 节点执行 ip a show 会发现多了一个VIP

在 k8s-master1 节点停止keepalived,模拟事故

bash 复制代码
systemctl stop keepalived

此时,在 k8s-master2 节点执行 ip a show 会发现多了一个VIP,说明keepalived生效了

安装Docker-CE

K8s是一个容器编排和管理系统,它的任务是在集群中部署、运行和管理容器化应用程序。因此,Kubernetes需要一个容器运行时来管理容器,以便能够将容器化的应用程序部署和运行在集群中。Docker和Containerd都是常用的容器运行时,因此在安装Kubernetes前需要安装其一。从k8s1.20版本开始,k8s官方将默认的容器运行时从Docker改为了Containerd。在1.24版本后,Docker作为容器运行时已经被弃用,Containerd成为唯一推荐的容器运行时,所有节点均安装,安装步骤如下:

yum在线安装

安装 yum-utils 软件包

bash 复制代码
yum -y install yum-utils

添加阿里源docker-ce镜像仓库

bash 复制代码
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

查看可用docker版本,注意:docker和k8s版本有指定要求 可前往github查看对应版本https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG

bash 复制代码
yum list docker-ce --showduplicates | sort -r

安装指定版本,如:docker-ce-20.10.24-3.el7

bash 复制代码
yum -y install docker-ce-25.0.5-1.el7 docker-ce-cli-25.0.5

启动docker服务并设置开机自启

bash 复制代码
systemctl start docker && systemctl enable docker

配置阿里镜像加速

bash 复制代码
cat > /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://d6mtathr.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF

重启docker服务

bash 复制代码
systemctl restart docker

Docker离线部署流程

之前做了一个xx项目,使用的服务器都是内网环境,所以自己整合了一下Docker离线部署的方法分享给大家

1、下载docker离线安装包,大家根据自己的需求下载自己对应的版本。此处我下载的是25.0.5版本

2、将离线包上传到服务器,可以使用xftp等软件将离线包放入服务器指定目录,我这里上传到了/opt/docker目录下,没有的话可以自己创建docker文件夹,解压

bash 复制代码
tar -xf docker-25.0.5.tgz
mv docker/* /usr/local/bin/

3、创建系统配置文件

bash 复制代码
cat > /usr/lib/systemd/system/docker.service <<"EOF"
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
 
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/local/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
# 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
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
 
[Install]
WantedBy=multi-user.target
EOF

这个单元文件定义了Docker服务的配置和行为,包括以下几点:

[Unit]段中,描述了该服务的简要说明和相关文档链接,以及依赖的其他服务。

[Service]段中,定义了服务的启动、重新加载和关闭的命令,以及资源限制和重启策略等。

[Install]段中,指定了服务的启动级别。

启动docker服务并设置开机自启

bash 复制代码
systemctl start docker && systemctl enable docker

配置阿里镜像加速,并修改Cgroup Driver为systemd(新版无需执行),Kubernetes v1.22版本开始,未明确设置kubelet的cgroup driver时,则默认即会将其设置为systemd。从 Docker 20.03 版本开始,默认使用 systemd 作为 Cgroup 驱动程序。如果系统没有安装 systemd,Docker 会自动切换到 cgroupfs 驱动程序。因此 Docker 20.03 版本之后此步无需再执行此步

bash 复制代码
cat > /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://d6mtathr.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
EOF

重启docker服务

bash 复制代码
systemctl restart docker

部署cri-docker

自 1.24 版起,Dockershim 已从 Kubernetes 项目中移除。因为历史问题docker却不支持kubernetes主推的CRI(容器运行时接口)标准,所以docker不能再作为kubernetes的容器运行时了,即从kubernetesv1.24开始不再使用docker了。但是如果想继续使用docker的话,可以在kubelet和docker之间加上一个中间层cri-docker。cri-docker是一个支持CRI标准的shim(垫片)。一头通过CRI跟kubelet交互,另一头跟docker api交互,从而间接的实现了kubernetes以docker作为容器运行时。但是这种架构缺点也很明显,调用链更长,效率更低。

下载cri-docker: https://github.com/Mirantis/cri-dockerd/tags

bash 复制代码
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.11/cri-dockerd-0.3.11.amd64.tgz

解压,然后拷贝到其他节点

bash 复制代码
tar -xf cri-dockerd-0.3.11.amd64.tgz
cp cri-dockerd/cri-dockerd /usr/local/bin/
scp /usr/local/bin/cri-dockerd k8s-master2:/usr/local/bin/
scp /usr/local/bin/cri-dockerd k8s-master3:/usr/local/bin/

创建cri-docker启动文件,然后拷贝到其他节点

bash 复制代码
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/local/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
 
[Install]
WantedBy=multi-user.target
EOF

创建cri-docker.socket

bash 复制代码
cat > /usr/lib/systemd/system/cri-docker.socket << EOF
[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service
 
[Socket]
ListenStream=%t/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
 
[Install]
WantedBy=sockets.target
EOF

启动cri-docker并设置开机自动启动

bash 复制代码
systemctl enable cri-docker --now

查看状态

bash 复制代码
systemctl is-active cri-docker

部署Kubernetes集群

kubeadm部署高可用集群

kubeadm不仅支持集群部署,还支持集群升级、卸载、数字证书更新等功能。目前kubeadm安装的k8s集群证书默认是一年365天,过期后就无法使用。kubeadm支持部署如下两种高可用模型

安装kubelet kubeadm kubectl

配置kubernetes源,每台机器都执行

bash 复制代码
cat << EOF | tee /etc/yum.repos.d/kubernetes.repo
[k8s]
name=k8s
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/rpm/
gpgcheck=0
EOF

查看可安装的版本,选择合适的版本,这里选择1.30.0-150500.1.1

bash 复制代码
yum list kubeadm.x86_64 --showduplicates
yum list kubelet.x86_64 --showduplicates
yum list kubectl.x86_64 --showduplicates

yum -y install kubeadm-1.30.0-150500.1.1 kubelet-1.30.0-150500.1.1 kubectl-1.30.0-150500.1.1

修改kubelet文件,配置kublet的cgroup驱动与docker一致

bash 复制代码
[root@k8s-master1 ~]# cat /etc/docker/daemon.json
{
  ......
  "exec-opts": ["native.cgroupdriver=systemd"]
}
[root@k8s-master1 ~]# cat /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"

设置kubelet开机自启

bash 复制代码
systemctl enable kubelet

下载Kubernetes各版本镜像

查看各版本镜像列表,如果查看其他版本镜像列表,只需要修改版本号即可

bash 复制代码
[root@k8s-master1 ~]# kubeadm config images list --kubernetes-version=v1.30.0
registry.k8s.io/kube-apiserver:v1.30.0
registry.k8s.io/kube-controller-manager:v1.30.0
registry.k8s.io/kube-scheduler:v1.30.0
registry.k8s.io/kube-proxy:v1.30.0
registry.k8s.io/coredns/coredns:v1.11.1
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.12-0

使用下面脚本下载阿里云kubernetes核心镜像,然后修改tag,这样yaml文件的镜像名称就可以不用修改了

bash 复制代码
#!/bin/bash
url=registry.cn-hangzhou.aliyuncs.com/google_containers
version=v1.30.0
images=(`kubeadm config images list --kubernetes-version=$version|awk -F '/' '{print $NF}'`)
for imagename in ${images[@]} ; do
  docker pull $url/$imagename
  docker tag $url/$imagename registry.k8s.io/$imagename
  docker rmi -f $url/$imagename
done

coredns镜像比较特殊,需要手动处理

bash 复制代码
docker tag registry.k8s.io/coredns:v1.11.1 registry.k8s.io/coredns/coredns:v1.11.1
docker rmi registry.k8s.io/coredns:v1.11.1

Kubeadm初始化Kubernetes集群

这里只需要在第一个主节点k8s-master1操作,生成kubeadm-config.yaml配置文件。kubeadm config print init-defaults 是Kubeadm的命令,用于打印默认的Kubernetes初始化配置内容,并且输出到一个文件中。之后使用kubeadm init初始化k8s集群,可以使用这个文件作为输入,而不是手动输入

bash 复制代码
kubeadm config print init-defaults --component-configs KubeletConfiguration > kubeadm-config.yaml

修改kubeadm-config.yaml配置文件,需要修改和添加的部分包括:

1、advertiseAddress处 改为 k8s-master1的IP

2、添加或修改nodeRegistration: 对应的配置

3、添加certSANs 处配置,配置为keepalived VIP地址

4、修改etcd配置

5、修改imageRepository配置

6、添加controlPlaneEndpoint处配置,配置为VIP:16443

bash 复制代码
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s    #指定token有效期,默认24小时,0s为永不失效
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.209.101    #指定当前master主机IP
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/cri-dockerd.sock
  imagePullPolicy: IfNotPresent
  name: k8s-master1    							#修改为本机主机名
  taints: null
---
apiServer:
  certSANs:
  - 192.168.209.100
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
#内置ETCD,也就是pod方式部署
etcd:
  local:
    dataDir: /var/lib/etcd
#如果已经部署了ETCD,可以使用如下配置
#etcd:
#  external:
#    endpoints:
#      - http://192.168.209.101:2379
#      - http://192.168.209.102:2379
#      - http://192.168.209.103:2379
imageRepository: registry.k8s.io
kind: ClusterConfiguration
kubernetesVersion: 1.30.0
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16     # 指定Pod的网段
  serviceSubnet: 10.96.0.0/12  # 指定service的网段
controlPlaneEndpoint: "192.168.209.100:16443"
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 0s
    enabled: true
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 0s
    cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
containerRuntimeEndpoint: ""
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMaximumGCAge: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging:
  flushFrequency: 0
  options:
    json:
      infoBufferSize: "0"
    text:
      infoBufferSize: "0"
  verbosity: 0
memorySwap: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s

kubeadm初始化Kubenetes集群

bash 复制代码
kubeadm init --config kubeadm-config.yaml --upload-certs --v=9

如果我们执行kubeadm init初始化集群失败,或者不想把这台机器作为控制节点来使用了,那么我们可以使用kubeadm reset命令将kubernetes集群进行重置

bash 复制代码
kubeadm reset -f

配置Kubectl配置文件config

默认安装kubernetes后,kubectl是无权限访问kubernetes的API的,所以需要一个config文件,相当于是对kubectl进行授权,这样kubectl命令可以使用config文件中的用户和证书对kubernetes集群进行管理。 在家目录创建一个.kube目录,存放全局config文件

bash 复制代码
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 	# 将admin.conf拷贝到$HOME/.kube
sudo chown $(id -u):$(id -g) $HOME/.kube/config 			# 设置权限

查看kubernetes集群,节点状态为NotReady,因为没有安装网络插件

bash 复制代码
[root@k8s-master1 ~]# kubectl get nodes
NAME          STATUS     ROLES           AGE   VERSION
k8s-master1   NotReady   control-plane   13s   v1.30.0

在 k8s-master2 和 k8s-master3 执行主节点join,k8s-master1 执行init后提示的带control-plane的命令。在命令后添加--cri-socket unix:///var/run/cri-dockerd.sock

bash 复制代码
kubeadm join 192.168.209.100:16443 --token abcdef.0123456789abcdef \
	--discovery-token-ca-cert-hash sha256:40b8d855d33684256b9b20b332a13da397ca85cfa4379c8ae8f52c0a9d9788a3 \
	--control-plane --certificate-key e7888ec8bb448e002439d5b97856c420d2e694078ec76ba06614b35c24a55db6 \
    --cri-socket unix:///var/run/cri-dockerd.sock

k8s-master2和k8s-master3 join后,执行提示的三条命令

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

在node节点执行join,k8s-master1 init后提示的不带control-plane的命令,在命令后添加--cri-socket unix:///var/run/cri-dockerd.sock

bash 复制代码
kubeadm join 192.168.209.100:16443 --token abcdef.0123456789abcdef \
	--discovery-token-ca-cert-hash sha256:40b8d855d33684256b9b20b332a13da397ca85cfa4379c8ae8f52c0a9d9788a3 \
	--cri-socket unix:///var/run/cri-dockerd.sock

可以看到,集群中又增加了两位小伙伴,它们的角色现在都是None,通常来讲我们是将另外两个none角色的节点称之为工作节点,ok了,集群中状态都是NotReady状态,我们安装完网络插件就好了。至此,kubernetes的5个节点都安装好了

bash 复制代码
[root@k8s-master1 ~]# kubectl get node
NAME          STATUS     ROLES           AGE   VERSION
k8s-master1   NotReady   control-plane   2m    v1.30.0
k8s-master2   NotReady   control-plane   3m    v1.30.0
k8s-master3   NotReady   control-plane   3m    v1.30.0
k8s-node1     NotReady   <none>          66s   v1.30.0
k8s-node2     NotReady   <none>          50s   v1.30.0

安装网络插件Calico

直接执行

bash 复制代码
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml

如果无法下载,那么去github全局搜索calico,点击进入项目,在Releases下下载自己需要的calico版本的离线包(文章以3.27.3版本为例)。不同版本的kubernets需要不同版本的calico,具体对应版本需自行查询。我们解压calico的离线包后会得到很多文件,并不是全部需要。首先将calico.yaml文件上传至服务器,然后使用cat calico.yaml |grep image:命令查看calico所需的镜像包

bash 复制代码
cat calico.yaml |grep image:

这里显示安装calico需要三个镜像,去解压的离线包imgaes文件夹中找到对应的三个离线镜像包文件,这里对应的分别是calico-cni.tar,calico-kube-controllers.tar和calico-node.tar三个离线包,将这三个离线镜像上传至服务器。至此kubernets 1.30版本的calico部署完成,我们查看节点,发现都是Ready

bash 复制代码
[root@k8s-master1 ~]# kubectl get node
NAME          STATUS   ROLES           AGE     VERSION
k8s-master1   Ready    control-plane   19m     v1.30.0
k8s-master2   Ready    control-plane   18m     v1.30.0
k8s-master3   Ready    control-plane   16m     v1.30.0
k8s-node1     Ready    <none>          7m3s    v1.30.0
k8s-node2     Ready    <none>          6m47s   v1.30.0

下面我们来运行一个容器,验证是否可以正常运行

bash 复制代码
kubectl run nginx-pod --image=nginx

查看pod

bash 复制代码
[root@k8s-master1 ~]# kubectl get pod 
NAME        READY   STATUS    RESTARTS   AGE
nginx-pod   1/1     Running   0          10m

二进制高可用集群

证书

这里使用官方推荐的 CFSSL 工具来生成证书。CFSSL是CloudFlare开源的一款PKI/TLS工具,使用Go语言编写。所有的证书颁发出来都需要两个步骤:

1、有一个证书颁发机构

2、提交证书申请,根据申请CA机构颁发证书给我们、cfssl也一样

在kubernetes 集群中需要的证书种类如下:
etcd 节点需要标识自己服务的server cert,也需要client cert与etcd集群其他节点交互,当然可以分别指定2个证书,也可以使用一个对等证书
master 节点需要标识 apiserver服务的server cert,也需要client cert连接etcd集群,这里也使用一个对等证书
kubectl calico kube-proxy 只需要client cert,因此证书请求中 hosts 字段可以为空
kubelet证书比较特殊,不是手动生成,它由node节点TLS BootStrapapiserver请求,由master节点的controller-manager 自动签发,包含一个client cert 和一个server cert

client certificate:用于服务端认证客户端,例如etcdctl、etcd proxy、fleetctl、docker客户端

server certificate:服务端使用,客户端以此验证服务端身份,例如docker服务端、kube-apiserver

peer certificate:双向证书,用于etcd集群成员间通信

根据认证对象可以将证书分成三类:

服务器证书server cert

客户端证书client cert

对等证书peer cert,表示既是server cert又是client cert

安装 cfssl

下载 cfssl 工具用于生成证书,其他版本见 release 页面。只需要在其中一台master节点安装即可

bash 复制代码
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl_1.6.4_linux_amd64 -O cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssljson_1.6.4_linux_amd64-O cfssljson
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl-certinfo_1.6.4_linux_amd64 -O cfssl-certinfo

cfssljson:将从cfssl和multirootca等获得的json格式的输出转化为证书格式的文件(证书,密钥,CSR和bundle)进行存储
cfssl-certinfo:可显示CSR或证书文件的详细信息;可用于证书校验

赋予权限

bash 复制代码
chmod +x cfssl cfssljson cfssl-certinfo
mv cfssl* /usr/local/bin

验证

bash 复制代码
cfssl version
cfssljson -version

制作CA证书

创建工作目录

bash 复制代码
mkdir -p /etc/kubernetes/pki

创建证书颁发机构(CA)

创建ca配置文件,相当于证书颁发机构的工作规章制度

创建配置文件:使用命令生成、手动生成

bash 复制代码
#使用命令生成默认配置文件
#cfssl print-defaults config > /etc/kubernetes/pki/ca-config.json

#手动生成
cat > /etc/kubernetes/pki/ca-config.json << EOF
{
  "signing": {
    "default": {
      "expiry": "876000h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "876000h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

default.expiry:默认证书有效期(单位:h),我们这里证书有效期是十年
profiles.etcd:为服务使用该配置文件颁发证书的配置模块
signing:签署,表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE
key encipherment:密钥加密
profiles:指定了不同角色的配置信息;可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile
server auth:服务器身份验证;表示 client 可以用该 CA 对 server 提供的证书进行验证
client auth:客户端身份验证;表示 server 可以用该 CA 对 client 提供的证书进行验证

我们自己准备一个证书申请请求书。证书机构就会根据我们请求签发证书

bash 复制代码
#使用命令生成默认配置文件
#cfssl print-defaults csr > /etc/kubernetes/pki/ca-csr.json

#手动创建配置文件
cat > /etc/kubernetes/pki/ca-csr.json << EOF
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing",
            "O": "Kubernetes",
            "OU": "Kubernetes-manual"
        }
    ]
}
EOF

hosts:包含的授权范围,不在此范围的的节点或者服务使用此证书就会报证书不匹配错误,证书如果不包含可能会出现无法连接的情况;
Key: 指定使用的加密算法,一般使用rsa非对称加密算法(algo:rsa;size:2048)
CN:Common Name,从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;CN是域名,也就是你现在使用什么域名就写什么域名。
C:国家(CN中国)
ST:类似省份(如湖南省等)
L:城市(如北京市)
O:Organization,从证书中提取该字段作为请求用户所属的组 (Group)

创建证书

bash 复制代码
cfssl gencert -initca /etc/kubernetes/pki/ca-csr.json | cfssljson -bare /etc/kubernetes/pki/ca

检查

bash 复制代码
[root@k8s-master1 ~]# ls /etc/kubernetes/pki/
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem

创建kube-apiserver证书

配置kube-apiserver请求csr文件

bash 复制代码
cat > /etc/kubernetes/pki/kube-apiserver-csr.json << EOF
{
    "CN": "kube-apiserver",
    "hosts": [
        "10.0.0.1",
        "127.0.0.1",
        "192.168.209.101",
        "192.168.209.102",
        "192.168.209.103",
        "192.168.209.201",
        "192.168.209.202",
        "192.168.209.100",
        "10.96.0.1",
        "kubernetes",
        "kubernetes.default",
        "kubernetes.default.svc",
        "kubernetes.default.svc.cluster",
        "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing",
            "O": "Kubernetes",
            "OU": "Kubernetes-manual"
        }
    ]
}
EOF

hosts字段指定该证书的授权范围,包括apiserver节点IP、负载均衡器节点IP地址、VIP地址、Kubernetes服务IP和域名。其中Kubernetes服务IP是apiserver自动创建的,一般是--service-cluster-ip-range参数指定的网段的第一个IP地址。本例中为10.0.0.1,--service-cluster-ip-range参数在kube-apiserver.conf和kube-controller-manager.conf中配置。192.168.209.100是我准备的负载均衡器地址,负载均衡可以自己搭建,也可以购买云厂商LB

生成apiserver证书

bash 复制代码
cfssl gencert -ca=/etc/kubernetes/pki/ca.pem \
 -ca-key=/etc/kubernetes/pki/ca-key.pem \
 -config=/etc/kubernetes/pki/ca-config.json \
 -profile=kubernetes \
 /etc/kubernetes/pki/kube-apiserver-csr.json | cfssljson -bare /etc/kubernetes/pki/kube-apiserver

-ca=ca.pem:指定证书的颁发机构(CA)文件路径;

-ca-key=ca-key.pem:指定证书的颁发机构(CA)私钥文件路径;

-config=ca-config.json:指定CA配置文件的路径,该文件定义了证书的有效期、加密算法等设置;

-profile=kubernetes:指定使用的证书配置文件,该文件定义了证书的用途和扩展属性;

apiserver-csr.json:指定API Server的证书签名请求配置文件路径;

cfssljson -bare apiserver:通过管道符将cfssl命令的输出传递给cfssljson命令,并使用-bare参数直接输出裸证书,即只生成证书文件,不包含其他格式的文件,最后指定证书文件名前缀为apiserver,实际生成的文件名为apiserver.csr、apiserver.pem、apiserver-key.pem;

所以,这个命令将会生成API Server的证书和私钥,并保存到指定的文件中,查看生成的证书

bash 复制代码
[root@k8s-master1 ~]# ls /etc/kubernetes/pki/kube-apiserver*
/etc/kubernetes/pki/kube-apiserver.csr       /etc/kubernetes/pki/kube-apiserver-key.pem
/etc/kubernetes/pki/kube-apiserver-csr.json  /etc/kubernetes/pki/kube-apiserver.pem

生成 API Server 聚合证书

bash 复制代码
cat > /etc/kubernetes/pki/front-proxy-ca-csr.json << EOF 
{
  "CN": "front-proxy-ca",
  "key": {
     "algo": "rsa",
     "size": 2048
  },
  "ca": {
    "expiry": "876000h"
  }
}
EOF

生成apiserver聚合CA证书和私钥

bash 复制代码
cfssl gencert -initca /etc/kubernetes/pki/front-proxy-ca-csr.json | cfssljson -bare /etc/kubernetes/pki/front-proxy-ca

创建front-proxy-client-csr.json文件

bash 复制代码
cat > /etc/kubernetes/pki/front-proxy-client-csr.json << EOF 
{
  "CN": "front-proxy-client",
  "hosts": [""],
  "key": {
     "algo": "rsa",
     "size": 2048
  }
}
EOF

生成用于Kubernetes的front-proxy-client证书

bash 复制代码
cfssl gencert -ca=/etc/kubernetes/pki/front-proxy-ca.pem -ca-key=/etc/kubernetes/pki/front-proxy-ca-key.pem -config=/etc/kubernetes/pki/ca-config.json -profile=kubernetes /etc/kubernetes/pki/front-proxy-client-csr.json | cfssljson -bare /etc/kubernetes/pki/front-proxy-client

创建kube-controller-manager证书

配置kube-controller-manager请求csr文件

bash 复制代码
cat > /etc/kubernetes/pki/kube-controller-manager-csr.json << EOF
 {
     "CN": "system:kube-controller-manager",
     "key": {
         "algo": "rsa",
         "size": 2048
     },
     "names": [
         {
             "C": "CN",
             "L": "Beijing",
             "ST": "Beijing",
             "O": "system:kube-controller-manager",
             "OU": "Kubernetes-manual"
         }
     ]
 }
EOF

生成controller-manager证书

bash 复制代码
cfssl gencert -ca=/etc/kubernetes/pki/ca.pem \
 -ca-key=/etc/kubernetes/pki/ca-key.pem \
 -config=/etc/kubernetes/pki/ca-config.json \
 -profile=kubernetes \
 /etc/kubernetes/pki/kube-controller-manager-csr.json | cfssljson -bare /etc/kubernetes/pki/kube-controller-manager

创建kube-scheduler的证书

配置kube-scheduler请求csr文件

bash 复制代码
cat > /etc/kubernetes/pki/kube-scheduler-csr.json << EOF
 {
     "CN": "system:kube-scheduler",
     "key": {
         "algo": "rsa",
         "size": 2048
     },
     "names": [
         {
             "C": "CN",
             "L": "Beijing",
             "ST": "Beijing",
             "O": "system:kube-scheduler",
             "OU": "Kubernetes-manual"
         }
     ]
 }
EOF

生成kube-scheduler证书

bash 复制代码
cfssl gencert -ca=/etc/kubernetes/pki/ca.pem \
 -ca-key=/etc/kubernetes/pki/ca-key.pem \
 -config=/etc/kubernetes/pki/ca-config.json \
 -profile=kubernetes \
 /etc/kubernetes/pki/kube-scheduler-csr.json | cfssljson -bare /etc/kubernetes/pki/kube-scheduler

创建kube-proxy证书

bash 复制代码
cat > /etc/kubernetes/pki/kube-proxy-csr.json << EOF
 {
     "CN":"system:kube-proxy",
     "key":{
         "algo":"rsa",
         "size":2048
     },
     "names":[
         {
             "C":"CN",
             "L":"Beijing",
             "ST":"Beijing",
             "O":"system:kube-proxy",
             "OU":"Kubernetes-manual"
         }
     ]
 }
EOF

生成kube-proxy证书

bash 复制代码
cfssl gencert -ca=/etc/kubernetes/pki/ca.pem \
 -ca-key=/etc/kubernetes/pki/ca-key.pem \
 -config=/etc/kubernetes/pki/ca-config.json \
 -profile=kubernetes \
 /etc/kubernetes/pki/kube-proxy-csr.json | cfssljson -bare /etc/kubernetes/pki/kube-proxy

创建集群管理员证书

bash 复制代码
cat > /etc/kubernetes/pki/admin-csr.json << EOF
 {
     "CN":"admin",
     "key":{
         "algo":"rsa",
         "size":2048
     },
     "names":[
         {
             "C":"CN",
             "L":"Beijing",
             "ST":"Beijing",
             "O":"system:masters",
             "OU":"Kubernetes-manual"
         }
     ]
 }
EOF

为kubectl生成自签证书

bash 复制代码
cfssl gencert -ca=/etc/kubernetes/pki/ca.pem \
 -ca-key=/etc/kubernetes/pki/ca-key.pem \
 -config=/etc/kubernetes/pki/ca-config.json \
 -profile=kubernetes \
 /etc/kubernetes/pki/admin-csr.json | cfssljson -bare /etc/kubernetes/pki/admin

创建 ServiceAccount Key

bash 复制代码
openssl genrsa -out /etc/kubernetes/pki/sa.key 2048
openssl rsa -in /etc/kubernetes/pki/sa.key -pubout -out /etc/kubernetes/pki/sa.pub

kubernetes离线安装包

下载kubernetes离线安装包,我这里下载的是1.30.0版本

bash 复制代码
wget https://dl.k8s.io/v1.30.0/kubernetes-server-linux-amd64.tar.gz

在 k8s-master1 节点解压kubelet,kubectl等到 /usr/local/bin

bash 复制代码
tar -xf kubernetes-server-linux-amd64.tar.gz --strip-components=3 -C /usr/local/bin kubernetes/server/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy}

master需要全部组件

bash 复制代码
for i in k8s-master2 k8s-master3;do scp /usr/local/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy} $i:/usr/local/bin; done

node节点只需要 kubelet、kube-proxy

bash 复制代码
for i in k8s-node1 k8s-node2;do scp /usr/local/bin/{kubelet,kube-proxy} $i:/usr/local/bin; done

配置文件

配置apiserver服务

所有Master节点创建kube-apiserver.service,根据下方参数说明表和实际情况修改参数值。我们这里使用的k8s service网段为10.96.0.0/16,该网段不能和宿主机的网段、Pod网段的重复。特别注意:docker的网桥默认为 172.17.0.1/16,不要使用这个网段

bash 复制代码
cat > /etc/kubernetes/conf/kube-apiserver.conf << "EOF"
KUBE_APISERVER_OPTS="--v=2 \
--allow-privileged=true \
--bind-address=192.168.209.101 \
--secure-port=6443 \
--advertise-address=192.168.209.101 \
--service-cluster-ip-range=10.0.0.0/24 \
--service-node-port-range=30000-32767 \
--etcd-servers=https://192.168.209.101:2379,https://192.168.209.102:2379,https://192.168.209.103:2379 \
--etcd-cafile=/etc/etcd/cert/etcd-ca.pem \
--etcd-certfile=/etc/etcd/cert/etcd.pem \
--etcd-keyfile=/etc/etcd/cert/etcd-key.pem \
--client-ca-file=/etc/kubernetes/pki/ca.pem \
--tls-cert-file=/etc/kubernetes/pki/kube-apiserver.pem  \
--tls-private-key-file=/etc/kubernetes/pki/kube-apiserver-key.pem \
--kubelet-client-certificate=/etc/kubernetes/pki/kube-apiserver.pem \
--kubelet-client-key=/etc/kubernetes/pki/kube-apiserver-key.pem \
--service-account-key-file=/etc/kubernetes/pki/sa.pub \
--service-account-signing-key-file=/etc/kubernetes/pki/sa.key \
--service-account-issuer=https://kubernetes.default.svc.cluster.local \
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
--authorization-mode=RBAC,Node \
--enable-bootstrap-token-auth=true \
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.pem \
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client-key.pem \
--requestheader-allowed-names=aggregator \
--requestheader-group-headers=X-Remote-Group \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-username-headers=X-Remote-User \
--enable-aggregator-routing=true \
--token-auth-file=/etc/kubernetes/pki/token.csv \
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/var/log/k8s-audit.log \
--default-not-ready-toleration-seconds=20 \
--default-unreachable-toleration-seconds=20"
EOF

参数解释如下:

bash 复制代码
# 指定日志级别为 2(日志级别分 0-8),数字越大,日志越详细
KUBE_APISERVER_OPTS="--v=2 \
# 允许特权容器运行 
--allow-privileged=true \
# 设置监听地址 
--bind-address=192.168.209.101 \
# 设置监听端口,默认为 6443
--secure-port=6443 \
# 通告地址,让其他节点通过此 IP 来连接 API Server
--advertise-address=192.168.209.101 \
# 指定 Kubernetes 集群中 Service 的 CIDR 范围,例如 10.0.0.0/24,该 CIDR 范围不能与部署机器的 IP 地址有重合
--service-cluster-ip-range=10.0.0.0/24 \
# 指定 Kubernetes 集群中 NodePort 的范围,默认值为 30000~32767
--service-node-port-range=30000-32767 \
# 指定 etcd 服务器的地址
--etcd-servers=https://192.168.209.101:2379,https://192.168.209.102:2379,https://192.168.209.103:2379 \
# 指定 etcd 服务器的 CA 证书
--etcd-cafile=/etc/etcd/cert/etcd-ca.pem \
# 指定 etcd 服务器的证书
--etcd-certfile=/etc/etcd/cert/etcd.pem \
# 指定 etcd 服务器的私钥 
--etcd-keyfile=/etc/etcd/cert/etcd-key.pem \
# 指定客户端 CA 的证书
--client-ca-file=/etc/kubernetes/pki/ca.pem \
# 指定 API Server 服务的证书
--tls-cert-file=/etc/kubernetes/pki/kube-apiserver.pem  \
# 指定 API Server 服务的私钥
--tls-private-key-file=/etc/kubernetes/pki/kube-apiserver-key.pem \
# 指定与 kubelet 通信的客户端证书和私钥
--kubelet-client-certificate=/etc/kubernetes/pki/kube-apiserver.pem \
--kubelet-client-key=/etc/kubernetes/pki/kube-apiserver-key.pem \
# 指定服务账户公钥文件
--service-account-key-file=/etc/kubernetes/pki/sa.pub \
# 指定服务账户签名密钥文件
--service-account-signing-key-file=/etc/kubernetes/pki/sa.key \
# 指定服务账户的发布者
--service-account-issuer=https://kubernetes.default.svc.cluster.local \
# 指定启用的准入插件
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
# 指定授权模式
--authorization-mode=RBAC,Node \
# 启用 bootstrap token 引导令牌认证
--enable-bootstrap-token-auth=true \
# 指定请求头中的客户端 CA 证书
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \
# 指定代理客户端的证书和私钥
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.pem \
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client-key.pem \
# 指定请求头中允许的名字
--requestheader-allowed-names=aggregator \
# 指定请求头中的组头
--requestheader-group-headers=X-Remote-Group \
# 指定请求头中的额外头前缀
--requestheader-extra-headers-prefix=X-Remote-Extra- \
# 指定请求头中的用户名头
--requestheader-username-headers=X-Remote-User \
# 启用聚合路由
--enable-aggregator-routing=true \
# 指定用于身份验证的令牌文件
--token-auth-file=/etc/kubernetes/pki/token.csv \
# 设置日志轮转、日志路径相关的配置参数
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/var/log/k8s-audit.log \
--default-not-ready-toleration-seconds=20 \
--default-unreachable-toleration-seconds=20"

创建kube-apiserver的Service文件

bash 复制代码
cat > /usr/lib/systemd/system/kube-apiserver.service << "EOF"
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=/etc/kubernetes/conf/kube-apiserver.conf
ExecStart=/usr/local/bin/kube-apiserver $KUBE_APISERVER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

kube-controller-manage

创建kube-controller-manage配置文件,并根据下方参数说明表和实际情况修改参数值

bash 复制代码
cat > /etc/kubernetes/conf/kube-controller-manager.conf << "EOF"
KUBE_CONTROLLER_MANAGER_OPTS="--v=2 \
--bind-address=127.0.0.1 \
--root-ca-file=/etc/kubernetes/pki/ca.pem \
--cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem \
--cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem  \
--service-account-private-key-file=/etc/kubernetes/pki/sa.key \
--kubeconfig=/etc/kubernetes/conf/kube-controller-manager.kubeconfig \
--leader-elect=true \
--use-service-account-credentials=true \
--node-monitor-grace-period=20s \
--node-monitor-period=2s \
--controllers=*,bootstrapsigner,tokencleaner \
--allocate-node-cidrs=true \
--service-cluster-ip-range=10.0.0.0/24 \
--cluster-cidr=10.244.0.0/16 \
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \
--cluster-signing-duration=876000h0m0s \
--node-startup-grace-period=20s \
--node-eviction-rate=1"
EOF

参数解释如下:

bash 复制代码
# 指定日志级别为 2(日志级别分 0-8),数字越大,日志越详细
KUBE_CONTROLLER_MANAGER_OPTS="--v=2 \
# 设置监听地址
--bind-address=127.0.0.1 \
# 设置根证书的路径,用于验证其他组件的证书
--root-ca-file=/etc/kubernetes/pki/ca.pem \
# 设置用于签名集群证书的证书文件路径
--cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem \
# 设置用于签名集群证书的私钥文件路径
--cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem  \
# 设置用于签名服务账户令牌的私钥文件路径
--service-account-private-key-file=/etc/kubernetes/pki/sa.key \
# 指定 kubeconfig 文件的路径,此文件包含了与 Kubernetes API 服务器通信所需的配置信息
--kubeconfig=/etc/kubernetes/conf/kube-controller-manager.kubeconfig \
# 设置启用 Leader 选举机制,确保只有一个控制器管理器作为 Leader 在运行
--leader-elect=true \
# 设置使用服务账户的凭据进行认证和授权
--use-service-account-credentials=true \
# 设置将一个运行的 Node 节点标记为不健康之前允许其无响应的时间
--node-monitor-grace-period=20s \
# 设置节点控制器对节点状态进行同步的周期
--node-monitor-period=2s \
# --controllers:设置要启用的控制器列表。* 表示启用所有默认启用的控制器;foo 表示启用名为 foo 的控制器;-foo 表示禁用名为 foo 的控制器。控制器的全集:attachdetach、bootstrapsigner、cloud-node-lifecycle、clusterrole-aggregation、cronjob、csrapproving、csrcleaner、csrsigning、daemonset、deployment、disruption、endpoint、endpointslice、endpointslicemirroring、ephemeral-volume、garbagecollector、horizontalpodautoscaling、job、namespace、nodeipam、nodelifecycle、persistentvolume-binder、persistentvolume-expander、podgc、pv-protection、pvc-protection、replicaset、replicationcontroller、resourcequota、root-ca-cert-publisher、route、service、serviceaccount、serviceaccount-token、statefulset、tokencleaner、ttl、ttl-after-finished;
默认禁用的控制器:bootstrapsigner 和 tokencleaner
--controllers=*,bootstrapsigner,tokencleaner \
# 设置允许基于 CNI 来为 Pod 分配和设置子网掩码
--allocate-node-cidrs=true \
# 指定 Kubernetes 集群中 Service 的 CIDR 范围,与 kube-apiserver.conf 中的 --service-cluster-ip-range 参数配置保持一致
--service-cluster-ip-range=10.0.0.0/24 \
# 定义集群的 CIDR 范围,要与 CNI 插件的 CIDR 范围保持一致
--cluster-cidr=10.244.0.0/16 \
# 设置请求头中客户端 CA 的证书文件路径,用于认证请求头中的 CA 证书
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.pem \
# 设置签发证书的有效期
--cluster-signing-duration=876000h0m0s \
# 设置将一个启动节点标记为不健康之前允许其无响应的时间
--node-startup-grace-period=20s \
# 设置删除不健康节点上的 pod 的宽限时间
--node-eviction-rate=1"

生成kube-controller-manager访问apiserver的kubeconfig配置文件,只需在master1上执行。kubectl config set-cluster命令的作用是在kubeconfig文件中设置集群信息,包括证书颁发机构、证书、kube-apiserver地址等。

bash 复制代码
KUBE_APISERVER="https://192.168.209.100:16443"
KUBE_CONFIG="/etc/kubernetes/conf/kube-controller-manager.kubeconfig"
kubectl config set-cluster kubernetes \
     --certificate-authority=/etc/kubernetes/pki/ca.pem \
     --embed-certs=true \
     --server=${KUBE_APISERVER} \
     --kubeconfig=${KUBE_CONFIG}

--certificate-authority选项指定了集群的证书颁发机构(CA)的路径,这个CA会验证kube-apiserver提供的证书是否合法。

--embed-certs选项用于将证书嵌入到生成的kubeconfig文件中,这样就不需要在kubeconfig文件中单独指定证书文件路径。

--server选项指定kube-apiserver的地址,我这里的vip是192.168.209.100,nginx监听端口16433

--kubeconfig选项指定生成的kubeconfig文件的路径和名称。

设置一个用户项,以便后续使用该文件进行身份验证和访问 Kubernetes API

bash 复制代码
kubectl config set-credentials system:kube-controller-manager \
     --client-certificate=/etc/kubernetes/pki/kube-controller-manager.pem \
     --client-key=/etc/kubernetes/pki/kube-controller-manager-key.pem \
     --embed-certs=true \
     --kubeconfig=${KUBE_CONFIG}

system:kube-controller-manager: 是设置用户凭据的名称,system:是Kubernetes API Server内置的身份验证器使用的用户标识符前缀,它表示是一个系统用户,在本例中是kube-controller-manager组件使用的身份。

--client-certificate: 指定kube-controller-manager.pem客户端证书的路径。

--client-key: 指定kube-controller-manager-key.pem客户端私钥的路径。

--embed-certs: 表示将证书和私钥直接嵌入到生成的kubeconfig文件中,而不是通过引用外部文件。

--kubeconfig:指定生成的kubeconfig文件的路径和名称。

配置Kubernetes控制器管理器的上下文信息

bash 复制代码
kubectl config set-context system:kube-controller-manager@kubernetes \
    --cluster=kubernetes \
    --user=system:kube-controller-manager \
     --kubeconfig=${KUBE_CONFIG}

kubectl config set-context system:kube-controller-manager@kubernetes: 设置上下文的名称为system:kube-controller-manager@kubernetes,这是一个标识符,用于唯一标识该上下文。

--cluster=kubernetes: 指定集群的名称为kubernetes,这是一个现有集群的标识符,表示要管理的Kubernetes集群。

--user=system:kube-controller-manager: 指定使用的用户身份为system:kube-controller-manager。这是一个特殊的用户身份,具有控制 Kubernetes控制器管理器的权限。

--kubeconfig选项指定生成的kubeconfig文件的路径和名称。kubeconfig文件是一个用于管理Kubernetes配置的文件,包含了集群、用户和上下文的相关信息。

设置默认环境,设置kubectl使用指定的上下文环境来执行操作,上下文环境是kubectl用来确定要连接到哪个Kubernetes集群以及使用哪个身份验证信息的配置,通过执行这个命令,kubectl将使用指定的上下文来执行后续的操作,包括部署和管理Kubernetes资源。

bash 复制代码
kubectl config use-context system:kube-controller-manager@kubernetes \
     --kubeconfig=${KUBE_CONFIG}

kubectl config use-context是用来设置当前上下文环境的命令

system:kube-controller-manager@kubernetes是指定的上下文名称,它告诉kubectl要使用的Kubernetes集群和身份验证信息。

--kubeconfig选项指定生成的kubeconfig文件的路径和名称,kubeconfig文件是存储集群连接和身份验证信息的配置文件

创建kube-controller-manager的Service文件

bash 复制代码
cat > /usr/lib/systemd/system/kube-controller-manager.service << "EOF"
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=/etc/kubernetes/conf/kube-controller-manager.conf
ExecStart=/usr/local/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

kube-scheduler配置文件

创建kube-scheduler配置文件,并根据下方参数说明表和实际情况修改参数值

bash 复制代码
cat > /etc/kubernetes/conf/kube-scheduler.conf << "EOF"
KUBE_SCHEDULER_OPTS="--v=2 \
--bind-address=127.0.0.1 \
--leader-elect=true \
--kubeconfig=/etc/kubernetes/conf/kube-scheduler.kubeconfig"
EOF

参数解释如下:

bash 复制代码
# 指定日志级别为 2(日志级别分 0-8),数字越大,日志越详细
KUBE_SCHEDULER_OPTS="--v=2 \
# 设置监听地址
--bind-address=127.0.0.1 \
# 启用自动选举
--leader-elect=true \
# 指定 kubeconfig 文件的路径,此文件包含了与 Kubernetes API 服务器通信所需的配置信息
--kubeconfig=/etc/kubernetes/conf/kube-scheduler.kubeconfig"

生成kube-scheduler访问apiserver的kubeconfig配置文件

bash 复制代码
# KUBE_APISERVER地址修改为实际环境apiserver的IP:Port或VIP:Port
KUBE_APISERVER="https://192.168.209.100:16443"
KUBE_CONFIG="/etc/kubernetes/conf/kube-scheduler.kubeconfig"

kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/pki/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials system:kube-scheduler \
  --client-certificate=/etc/kubernetes/pki/kube-scheduler.pem \
  --client-key=/etc/kubernetes/pki/kube-scheduler-key.pem \
  --embed-certs=true \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context system:kube-scheduler@kubernetes \
  --cluster=kubernetes \
  --user=system:kube-scheduler \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context system:kube-scheduler@kubernetes --kubeconfig=${KUBE_CONFIG}

创建kube-scheduler的Service文件

bash 复制代码
cat > /usr/lib/systemd/system/kube-scheduler.service << "EOF"
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=/etc/kubernetes/conf/kube-scheduler.conf
ExecStart=/usr/local/bin/kube-scheduler $KUBE_SCHEDULER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

创建token

随机生成一个 32 位字符串,用以创建 token.csv 文件。token.csv文件的格式为:第一列为随机字符串,第二列为用户名,第三列为UID,第四列用户组。此处 apiserver 配置的 token(32 位随机字符串)必须要与后面 node 节点 bootstrap.kubeconfig 配置文件里的 token 一致

bash 复制代码
token=`head -c 16 /dev/urandom | od -An -t x | tr -d ' '`
echo "$token,kubelet-bootstrap,10001,'system:node-bootstrappers'" > /etc/kubernetes/pki/token.csv

分发配置

在master2和master3节点创建目录

bash 复制代码
mkdir /etc/kubernetes

分发配置文件和证书

bash 复制代码
scp -r /etc/kubernetes/{pki,conf} k8s-master2:/etc/kubernetes/
scp -r /etc/kubernetes/{pki,conf} k8s-master3:/etc/kubernetes/
scp -r /usr/lib/systemd/system/{kube-apiserver,kube-controller-manager,kube-scheduler}.service k8s-master2:/usr/lib/systemd/system/
scp -r /usr/lib/systemd/system/{kube-apiserver,kube-controller-manager,kube-scheduler}.service k8s-master3:/usr/lib/systemd/system/

修改其余 Master 节点上 kube-apiserver.conf 配置文件中的 --bind-address 和 --advertise-address 参数为本机 IP,以master2节点为例

bash 复制代码
[root@k8s-master2 ~]# cat /etc/kubernetes/conf/kube-apiserver.conf
...
--bind-address=192.168.209.102 \
--advertise-address=192.168.209.102 \
...

启动master组件

在所有 Master 节点上执行以下命令设置 api-server、controller-manager、scheduler 开机自启并启动

bash 复制代码
systemctl daemon-reload
systemctl start kube-apiserver && systemctl enable kube-apiserver
systemctl start kube-controller-manager && systemctl enable kube-controller-manager
systemctl start kube-scheduler && systemctl enable kube-scheduler

systemctl status kube-apiserver
systemctl status kube-controller-manager
systemctl status kube-scheduler

在 master1 节点上执行以下命令生成 kubectl 访问集群的 kubeconfig 文件

bash 复制代码
mkdir -p /root/.kube
# KUBE_APISERVER地址修改为实际环境apiserver的IP:Port或VIP:Port
KUBE_CONFIG="/root/.kube/config"
KUBE_APISERVER="https://192.168.209.100:16443"

kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/pki/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kubernetes-admin \
  --client-certificate=/etc/kubernetes/pki/admin.pem \
  --client-key=/etc/kubernetes/pki/admin-key.pem \
  --embed-certs=true \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context kubernetes-admin@kubernetes \
  --cluster=kubernetes \
  --user=kubernetes-admin \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context kubernetes-admin@kubernetes --kubeconfig=${KUBE_CONFIG}

将 /root/.kube 目录拷贝到其余 master 节点上,使得所有 master 节点均可通过 kubectl 访问集群

bash 复制代码
scp -r /root/.kube/ k8s-master2:/root/
scp -r /root/.kube/ k8s-master3:/root/

此时你可以通过执行 kubectl get cs 获取 Kubernetes 的各服务端组件状态看是否为 Healthy

bash 复制代码
[root@k8s-master1 ~]# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE   ERROR
controller-manager   Healthy   ok        
scheduler            Healthy   ok        
etcd-0               Healthy   ok    

在任意一台 master 上执行以下命令授权 kubelet-bootstrap 用户允许请求证书

bash 复制代码
kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

部署kubelet

在k8s node节点执行,创建kubelet.conf文件,并根据下方参数说明表和实际情况修改参数值

bash 复制代码
mkdir -p /etc/kubernetes/conf
cat > /etc/kubernetes/conf/kubelet.conf << "EOF"
KUBELET_OPTS="--v=2 \
--hostname-override=k8s-node1 \
--bootstrap-kubeconfig=/etc/kubernetes/conf/bootstrap.kubeconfig \
--kubeconfig=/etc/kubernetes/conf/kubelet.kubeconfig \
--config=/etc/kubernetes/conf/kubelet-config.yml \
--cert-dir=/etc/kubernetes/pki \
--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 \
--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock"
EOF

参数释义

bash 复制代码
# 指定日志级别为 2(日志级别分 0-8),数字越大,日志越详细
KUBELET_OPTS="--v=2 \
# 指定当前节点注册到 Kubernetes 显示的名称(集群内唯一),建议设置为本机主机名
--hostname-override=easyk8s1 \
# 指定用于启动引导 kubelet 的 kubeconfig 配置的 bootstrap-kubeconfig 文件路径和名称
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
# 指定 kubelet 的 kubeconfig 文件的路径和名称
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
# 指定 kubelet 的配置文件路径和名称
--config=/opt/kubernetes/cfg/kubelet-config.yml \
# 指定证书存放目录
--cert-dir=/opt/kubernetes/ssl \
# 指定管理 Pod 网络容器的 pause 镜像(registry.aliyuncs.com/google_containers/pause:3.9)[可选参数],此参数在新版本中已弃用,将在未来版本中删除,pause 镜像信息将从 CRI(例如 cri-dockerd)中获取
--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 \
# 指定使用的 CRI socket 路径,例如 unix:///var/run/cri-dockerd.sock [可选参数]\
--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock"

在启动 kubelet 时,如果 --kubeconfig 标志所指定的文件并不存在,会使用通过标志 --bootstrap-kubeconfig 所指定的启动引导 kubeconfig 配置来向 API 服务器请求客户端证书。在证书请求被批复并被 kubelet 收回时,一个引用所生成的密钥和所获得证书的 kubeconfig 文件会被写入到通过 --kubeconfig 所指定的文件路径下。证书和密钥文件会被放到 --cert-dir 所指定的目录中。

创建kubelet-config.yml配置文件,并根据下方参数说明表和实际情况修改参数值

bash 复制代码
# 创建kubelet-config.yml配置文件,并根据下方参数说明表和实际情况修改参数值
cat > /etc/kubernetes/conf/kubelet-config.yml << EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
cgroupDriver: systemd
clusterDNS:
- 10.0.0.2
clusterDomain: cluster.local 
failSwapOn: false
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 2m0s
    enabled: true
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.pem 
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 5m0s
    cacheUnauthorizedTTL: 30s
evictionHard:
  imagefs.available: 15%
  memory.available: 100Mi
  nodefs.available: 10%
  nodefs.inodesFree: 5%
maxOpenFiles: 1000000
maxPods: 110
EOF

clusterDNS:指定集群 DNS 服务器地址,一般是 --service-cluster-ip-range 参数指定的网段的第二个 IP 地址

clusterDomain:指定集群的域名后缀,默认为 cluster.local

创建kubelet的Service文件

bash 复制代码
cat > /usr/lib/systemd/system/kubelet.service << "EOF"
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Wants=docker.service

[Service]
EnvironmentFile=/etc/kubernetes/conf/kubelet.conf
ExecStart=/usr/local/bin/kubelet $KUBELET_OPTS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

执行以下操作生成 bootstrap.kubeconfig 配置文件和 kube-proxy.kubeconfig 配置文件,并拷贝到所有 Node 节点。在安装了cfssl工具的主机上生成kubelet bootstrap kubeconfig配置文件。建议用master1节点

bash 复制代码
# KUBE_APISERVER地址修改为实际环境apiserver的IP:Port或VIP:Port
# TOKEN修改为master节点/etc/kubernetes/pki/token.csv中的token值
KUBE_CONFIG="/etc/kubernetes/conf/bootstrap.kubeconfig"
KUBE_APISERVER="https://192.168.209.100:16443"
TOKEN="bd7f74be3a0ceaf28e4d920bf4d2f603"

kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/pki/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kubelet-bootstrap \
  --token=${TOKEN} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context kubelet-bootstrap@kubernetes \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context kubelet-bootstrap@kubernetes --kubeconfig=${KUBE_CONFIG}

将bootstrap.kubeconfig文件拷贝到所有node节点上

bash 复制代码
scp /etc/kubernetes/conf/bootstrap.kubeconfig k8s-node1:/etc/kubernetes/conf/
bash 复制代码
scp /etc/kubernetes/conf/{kubelet.conf,kubelet-config.yml,bootstrap.kubeconfig} k8s-node2:/etc/kubernetes/conf/
scp /usr/lib/systemd/system/kubelet.service k8s-node2:/usr/lib/systemd/system/

修改/etc/kubernetes/conf/kubelet.conf文件--hostname-override

部署kube-proxy

创建kube-proxy.conf文件,并根据下方参数说明表和实际情况修改参数值

bash 复制代码
cat > /etc/kubernetes/conf/kube-proxy.conf << "EOF"
KUBE_PROXY_OPTS="--v=2 \
--config=/etc/kubernetes/conf/kube-proxy-config.yml"
EOF

创建kube-proxy-config.yml配置文件,并根据下方参数说明表和实际情况修改参数值

bash 复制代码
cat > /etc/kubernetes/conf/kube-proxy-config.yml << EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
metricsBindAddress: 0.0.0.0:10249
clientConnection:
  kubeconfig: /etc/kubernetes/conf/kube-proxy.kubeconfig
hostnameOverride: k8s-node1
clusterCIDR: 10.0.0.0/24
mode: ipvs
ipvs:
  scheduler: "rr"
iptables:
  masqueradeAll: true
EOF

创建kube-proxy的Service文件

bash 复制代码
cat > /usr/lib/systemd/system/kube-proxy.service << "EOF"
[Unit]
Description=Kubernetes Proxy
After=network.target

[Service]
EnvironmentFile=/etc/kubernetes/conf/kube-proxy.conf
ExecStart=/usr/local/bin/kube-proxy $KUBE_PROXY_OPTS
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

在安装了cfssl工具的主机上生成kube-proxy.kubeconfig配置文件。建议用master1节点

bash 复制代码
# KUBE_APISERVER地址修改为实际环境apiserver的IP:Port或VIP:Port
KUBE_CONFIG="/etc/kubernetes/conf/kube-proxy.kubeconfig"
KUBE_APISERVER="https://192.168.209.100:16443"

kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/pki/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-proxy \
  --client-certificate=/etc/kubernetes/pki/kube-proxy.pem \
  --client-key=/etc/kubernetes/pki/kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context kube-proxy@kubernetes \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context kube-proxy@kubernetes --kubeconfig=${KUBE_CONFIG}

将kube-proxy.kubeconfig文件拷贝到所有node节点上

bash 复制代码
scp -r /etc/kubernetes/conf/kube-proxy.kubeconfig k8s-node1:/etc/kubernetes/conf/

拷贝 ca 证书和 kube-proxy 的自签证书和私钥到所有 Node 节点的 目录下

bash 复制代码
scp -r /etc/kubernetes/pki/{ca.pem,kube-proxy.pem,kube-proxy-key.pem} k8s-node1:/etc/kubernetes/pki/
bash 复制代码
scp /etc/kubernetes/conf/{kube-proxy.kubeconfig,kube-proxy.conf} k8s-node2:/etc/kubernetes/conf/
scp /etc/kubernetes/pki/{ca.pem,kube-proxy.pem,kube-proxy-key.pem} k8s-node2:/etc/kubernetes/pki/
scp /usr/lib/systemd/system/kube-proxy.service k8s-node2:/usr/lib/systemd/system/

启动kubelet和kube-proxy

设置 kubelet 和 kube-proxy 开机自启并启动

bash 复制代码
systemctl daemon-reload

systemctl start kubelet && systemctl enable kubelet
systemctl start kube-proxy && systemctl enable kube-proxy

systemctl status kubelet
systemctl status kube-proxy

如果启动失败,

bash 复制代码
journalctl -u kubelet -n 50 --no-pager

当 kubelet 和 kube-proxy 成功启动后,此时在任意一台 master 节点上执行 kubectl get csr 可以看到有新的节点请求颁发证书 (CONDITION 字段处于 Pending 状态)

bash 复制代码
[root@k8s-master1 ~]# kubectl get csr 
NAME                                                   AGE   SIGNERNAME                                    REQUESTOR           REQUESTEDDURATION   CONDITION
node-csr-7yFqd8ONnkvIfoHRCmkT-bWcP5gR54EjJUMkTaxLLJY   49s   kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   <none>              Pending

执行以下命令允许给 Node 颁发证书,node-csr-xxxxxx替换成执行kubectl get csr查询到的节点NAME值,多个用空格隔开

bash 复制代码
kubectl certificate approve node-csr-7yFqd8ONnkvIfoHRCmkT-bWcP5gR54EjJUMkTaxLLJY

授权颁发证书后,在任意一台 master 节点执行 kubectl get node 能看到 Node 节点都还处于 NotReady 状态,这是因为现在还没安装网络插件

若 kubectl 或 kube-proxy 配置文件中的 hostname-override 配置参数漏修改,导致授权后 master 无法正常获取到 Node 节点信息,除了修改 kubelet.conf 的 --hostname-override 配置和 kube-proxy-config.yml 的 hostnameOverride 配置外,还需要将 kubelet.kubeconfig 文件(这个文件是 master 认证后客户端自动生成的)删除,才可重新申请授权,否则报错信息类似如下:

bash 复制代码
kubelet_node_status.go:94] Unable to register node "k8s-node2" with API server: nodes "k8s-node2" is forbidden: node "k8s-node1" is not allowed to modify node "k8s-node2"

TLS Bootstrapping 机制流程(Kubelet)

授权 apiserver 访问 kubelet

为提供安全性,kubelet 禁止匿名访问,必须授权才可以。一个常见的表现就是无法通过 kubectl logs 查看 pod 的日志,错误输出类似如下:

bash 复制代码
Error from server (Forbidden): Forbidden (user=kube-apiserver, verb=get, resource=nodes, subresource=proxy) ( pods/log calico-node-gnh4r)

在任意一台 master 节点上执行以下命令进行授权

bash 复制代码
cat << EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
      - pods/log
    verbs:
      - "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver
  namespace: ""
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kube-apiserver
EOF

部署 CNI 网络

Kubernetes 支持多种网络类型,本文将介绍 Calico 网络的安装方法

Github 地址:https://github.com/projectcalico/calico

Calico 官方安装文档:https://docs.tigera.io/calico/latest/getting-started/

Calico 与 Kubernetes 版本兼容性说明:https://docs.tigera.io/calico/latest/getting-started/kubernetes/requirements#kubernetes-requirements

直接执行

bash 复制代码
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml

如果无法下载,那么去github全局搜索calico,点击进入项目,在Releases下下载自己需要的calico版本的离线包(文章以3.27.3版本为例)。不同版本的kubernets需要不同版本的calico,具体对应版本需自行查询。我们解压calico的离线包后会得到很多文件,并不是全部需要。首先将calico.yaml文件上传至服务器,然后使用cat calico.yaml |grep image:命令查看calico所需的镜像包

bash 复制代码
cat calico.yaml |grep image:

这里显示安装calico需要三个镜像,去解压的离线包imgaes文件夹中找到对应的三个离线镜像包文件,这里对应的分别是calico-cni.tar,calico-kube-controllers.tar和calico-node.tar三个离线包,将这三个离线镜像上传至服务器。至此kubernets 1.30版本的calico部署完成,我们查看节点,发现都是Ready

bash 复制代码
[root@k8s-master1 ~]# kubectl get node
NAME          STATUS   ROLES           AGE     VERSION
k8s-master1   Ready    control-plane   19m     v1.30.0
k8s-master2   Ready    control-plane   18m     v1.30.0
k8s-master3   Ready    control-plane   16m     v1.30.0
k8s-node1     Ready    <none>          7m3s    v1.30.0
k8s-node2     Ready    <none>          6m47s   v1.30.0

下面我们在任意一个 master 节点上执行以下命令创建一个 nginx pod 并暴露端口测试是否可以从外部正常访问。创建nginx deployment

bash 复制代码
kubectl create deployment web --image=nginx

暴露端口

bash 复制代码
kubectl expose deployment web --port=80 --type=NodePort

查看对应的访问端口

bash 复制代码
kubectl get service
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
web          NodePort    10.0.0.34    <none>        80:32163/TCP   61s

部署 CoreDNS

部署 CoreDNS 主要是为了给 Kubernetes 的 Service 提供 DNS 解析服务,使得程序可以通过 Service 的名称进行访问。DNS 服务监视 Kubernetes API,为每一个 Service 创建 DNS 记录用于域名解析。ClusterIP A 记录格式:<service-name>.<namespace-name>.svc.<domain_suffix>,示例:my-svc.my-namespace.svc.cluster.local

使用 kubeadm 方式部署的 Kubernetes 会自动安装 CoreDNS,二进制部署方式则需要自行安装。从 Github 地址https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns上下载 coredns.yaml.base 文件到任意 master 节点,并重命名为 coredns.yaml。然后参考下方标注修改其中的部分参数
__MACHINE_GENERATED_WARNING__替换为 This is a file generated from the base underscore template file: coredns.yaml.base
__PILLAR__DNS__DOMAIN__或__DNS__DOMAIN__替换为 cluster.local, 若要使用非默认域名如 koenli.net 记得要与 node 节点上 /etc/kubernetes/conf/kubelet-config.yml 文件中的 clusterDomain 参数保持一致,并要调整 api-server 证书中的 hosts 字段值并重新颁发证书
__PILLAR__DNS__MEMORY__LIMIT__或__DNS__MEMORY__LIMIT__替换为 170Mi,此内存限制的值可根据实际环境资源进行调整
__PILLAR__DNS__SERVER__或__DNS__SERVER__替换为 10.0.0.2,此 IP 地址需要与 Node 节点上 /etc/kubernetes/conf/kubelet-config.yml 文件中配置的 clusterDNS 字段的 IP 一致

官方提供的 yaml 文件中使用的镜像仓库registry.k8s.io/coredns/coredns在境外,国内无法访问。建议将其替换为国内阿里云的替代镜像仓库registry.cn-hangzhou.aliyuncs.com/google_containers/coredns。以下为我替换后最终的文件内容

bash 复制代码
# This is a file generated from the base underscore template file: coredns.yaml.base

apiVersion: v1
kind: ServiceAccount
metadata:
  name: coredns
  namespace: kube-system
  labels:
      kubernetes.io/cluster-service: "true"
      addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    addonmanager.kubernetes.io/mode: Reconcile
  name: system:coredns
rules:
- apiGroups:
  - ""
  resources:
  - endpoints
  - services
  - pods
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    addonmanager.kubernetes.io/mode: EnsureExists
  name: system:coredns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:coredns
subjects:
- kind: ServiceAccount
  name: coredns
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
  labels:
      addonmanager.kubernetes.io/mode: EnsureExists
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf {
            max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "CoreDNS"
spec:
  # replicas: not specified here:
  # 1. In order to make Addon Manager do not reconcile this replicas parameter.
  # 2. Default is 1.
  # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      priorityClassName: system-cluster-critical
      serviceAccountName: coredns
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                  - key: k8s-app
                    operator: In
                    values: ["kube-dns"]
              topologyKey: kubernetes.io/hostname
      tolerations:
        - key: "CriticalAddonsOnly"
          operator: "Exists"
      nodeSelector:
        kubernetes.io/os: linux
      containers:
      - name: coredns
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.11.1
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: 170Mi
          requests:
            cpu: 100m
            memory: 70Mi
        args: [ "-conf", "/etc/coredns/Corefile" ]
        volumeMounts:
        - name: config-volume
          mountPath: /etc/coredns
          readOnly: true
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        - containerPort: 9153
          name: metrics
          protocol: TCP
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 8181
            scheme: HTTP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          readOnlyRootFilesystem: true
      dnsPolicy: Default
      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
---
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "CoreDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.0.0.2
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
  - name: metrics
    port: 9153
    protocol: TCP

执行以下命令进行安装

bash 复制代码
kubectl apply -f coredns.yaml

查看 CoreDNS 的 pod 创建情况,待所有 Pod 均为 Running 状态后表示部署完成

bash 复制代码
watch kubectl get pod -n kube-system

在任意 master 节点上执行以下命令创建一个 busybox 容器,在容器中 ping service 的名称看是否可以正常解析出 IP 地址,如果可以则说明 DNS 服务部署成功。

bash 复制代码
cat > /root/bs.yaml << EOF
apiVersion: v1
kind: Pod
metadata: 
    name: busybox
    namespace: default
spec:
    containers:
      - image: busybox:1.28.4
        command:
          - sleep
          - "3600"
        imagePullPolicy: IfNotPresent
        name: busybox
    restartPolicy: Always
EOF

kubectl apply -f /root/bs.yaml
watch kubectl get pods

# 待pod处于Running状态后执行以下命令进入容器中
kubectl exec -ti busybox sh

# 在容器中执行以下命令如果出现类似输出则说明解析正常
/ # nslookup kubernetes
Server:    10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
/ # exit

# 删除测试容器
kubectl delete -f /root/bs.yaml

K8S卸载

注:这里针对的是使用Kubeadm方式安装的Kubernetes集群。以下全部操作都是使用root用户进行,非root用户可以使用sudo,并且全部命令都需要在Kubernetes集群的所有节点分别执行

1、停止K8S,所有节点执行:

bash 复制代码
systemctl stop kubelet
systemctl stop etcd
systemctl stop docker

2、清空K8S集群设置,所有节点执行:

bash 复制代码
kubeadm reset -f

3、删除K8S相关软件,所有节点执行:

列出kube关键字的软件

bash 复制代码
yum list installed | grep kube

卸载相关软件

bash 复制代码
yum -y remove kube*

再次查看确保都卸载完成

bash 复制代码
[root@k8s-master1 ~]# yum list installed | grep kube
cri-tools.x86_64                            1.26.0-0                   @kubernetes

单独卸载

bash 复制代码
yum -y remove cri-tools.x86_64

最终确认已经完全卸载掉

bash 复制代码
yum list installed | grep kube

4、删除docker,所有节点执行

卸载Docker Engine、CLI、Containerd和Docker合成包

bash 复制代码
yum -y remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras

手动删除所有镜像、容器和卷

bash 复制代码
rm -rf /var/lib/docker
rm -rf /var/lib/containerd

5、彻底删除相关文件,在所有节点使用root用户执行以下命令,如果是非root请全部命令前都加上sudo

bash 复制代码
rm -rvf $HOME/.kube
rm -rvf ~/.kube/
rm -rvf /etc/kubernetes/
rm -rvf /etc/systemd/system/kubelet.service.d
rm -rvf /etc/systemd/system/kubelet.service
rm -rvf /usr/bin/kube*
rm -rvf /etc/cni
rm -rvf /opt/cni
rm -rvf /var/lib/etcd
rm -rvf /var/etcd

6、至此已完成了Kubenetes的彻底卸载并清理相关文件的操作,若是不放心可以进行检验。如果以下命令执行后都没有输出,那就说明K8S已经彻底卸载完成

bash 复制代码
systemctl status docker
systemctl | grep kube

yum list installed | grep kube
yum list installed | docker

rpm -qa | grep kube
rpm -qa | grep docker
相关推荐
hour_go2 小时前
微服务架构的故障演练数字化:方法解析与实践优势
微服务·云原生·架构
Empty_7775 小时前
K8S-中的优先级
云原生·容器·kubernetes
❀͜͡傀儡师7 小时前
Docker部署Rustscan端口扫描工具
运维·docker·容器
一只懒鱼a8 小时前
docker搭建rabbit集群
docker·容器·rabbitmq
java_logo8 小时前
Onlyoffice Documentserver Docker 容器化部署指南
运维·人工智能·docker·容器·onlyoffice·milvus·documentserver
Heavydrink8 小时前
华为云EulerOS 2.0安装redis详细教程
docker·容器·华为云
总有刁民想爱朕ha8 小时前
银河麒麟v10服务器版Docker部署.NET 8 WebAPI教程
docker·容器·.net·银河麒麟v10服务器版
Henry Zhu1239 小时前
VPP中的DPDK插件源码详解第一篇:DPDK插件的作用和意义以及整体架构
运维·服务器·网络·计算机网络·云原生
Jerry9527062810 小时前
1.无服务器架构入门
云原生·架构·serverless·无服务器架构