零基础K8s v1.35.7 集群部署保姆级搭建零坑

k8s版本: v1.35.7

部署 OS:Rocky Linux 10(零基础适配)

集群架构:1 控制节点 + 2 工作节点

容器运行时:containerd

网络组件:flannel:v0.28.9

适配说明:本手册专为零基础编写,摒弃专业默认知识点,每一条命令带详细注释、每一步操作带作用讲解、标注必做/禁忌项,由 CentOS7 迁移适配 Rocky Linux10,全程可无脑复刻执行。

前置零基础认知:K8s 集群必须统一环境、关闭系统防护、配置网络内核,否则 100% 部署报错,本文所有全局操作三台机器必须全部执行。

1 集群搭建方案选型(零基础科普)

新手必看:不同搭建方式适配不同场景,本教程选择裸机手动部署,适合学习企业真实部署逻辑,是运维必备技能。

搭建方式 适用场景 零基础通俗讲解
minikube 单机测试、零基础入门体验 只能在一台电脑上跑的简易 K8s,功能残缺,只能用来简单看看界面,学不到真实集群部署逻辑,不推荐深度学习
k3s 边缘设备、小型测试集群 精简版 K8s,自动简化很多配置,部署快,但屏蔽了底层原理,新手学不到核心知识
裸机手动部署 企业测试、生产集群、运维学习 完全手动配置每一项参数,和企业生产环境一致,能吃透 K8s 底层逻辑,新手首选学习方式,本教程全程采用此方式
云平台托管集群 企业线上生产环境 云端一键搭建,不用自己配置,成本高,新手无法学习部署原理,只适合直接使用,不适合学习

实验架构说明:本次搭建 1 主 2 从简易集群,满足学习需求;企业生产必须 3 台控制节点实现高可用,防止单点故障。

2 集群环境准备(企业标准|零基础全注释)

💡 核心重点:本章所有命令,三台节点(1主2从)必须全部执行!集群环境不一致,后续 100% 报错。

2.1 硬件配置要求(新手必读)

  • 节点数量:3 台 Rocky Linux 10 虚拟机/物理机

  • 最低配置:内存≥2G、CPU≥2核、硬盘≥30G(配置过低会导致集群卡顿、Pod 启动失败)

  • 网络要求:三台机器内网互通、能正常上网(需要下载软件、拉取镜像)

2.2 集群 IP 固定规划

K8s 集群禁止 IP 动态变化,必须固定 IP,以下为本次统一规划:

主机名 节点角色 固定 IP 地址
k8s‑master 控制节点(主节点) 192.48.75.10
k8s‑node1 工作节点(从节点) 192.48.75.11
k8s‑node2 工作节点(从节点) 192.48.75.12

注意: 如果你的主机是用克隆的, 一定要把网络配置里面的 uuid 修改或删除

# 生成本机的 uuid
[root@node ~]# uuidgen 
42b63197-dca2-4f7f-abed-b6edef9b51c1

# 修改配置
[root@node ~]# vim /etc/NetworkManager/system-connections/ens160.nmconnection 
[connection]
id=ens160
uuid=42b63197-dca2-4f7f-abed-b6edef9b51c1
type=ethernet

# 重启服务
[root@node ~]# systemctl restart NetworkManager
[root@node ~]# nmcli con down ens160 ;nmcli con up ens160 

2.3 全局环境统一配置(三台节点全执行|逐行注释)

2.3.1 设置主机名(作用:区分集群节点,方便集群识别)

原理:K8s 通过主机名+IP 识别节点,三台机器必须拥有不同主机名,永久生效

# ========== 仅 k8s-node1(主节点)执行 ==========
# hostnamectl set-hostname 主机名:永久修改系统主机名,重启不失效
hostnamectl set-hostname k8s-master

# ========== 仅 k8s-node2(从节点)执行 ==========
hostnamectl set-hostname k8s-node1

# ========== 仅 k8s-node3(从节点)执行 ==========
hostnamectl set-hostname k8s-node2

2.3.2 配置 hosts 域名解析(作用:让三台机器互相识别主机名)

原理:默认机器无法通过主机名互通,配置 hosts 后,机器输入主机名即可对应到固定 IP,避免集群通信失败

# cat >> /etc/hosts:向系统域名配置文件追加内容
# EOF 为起止标识,中间内容会写入文件
cat >> /etc/hosts <<EOF
192.48.75.10  k8s-master
192.48.75.11  k8s-node1
192.48.75.12  k8s-node2
EOF

2.3.3 关闭防火墙(作用:放行集群所有通信端口)

新手必懂原理:Linux 防火墙会拦截端口通信,K8s 集群有成百上千个端口需要互通,手动放行极其麻烦,测试环境直接关闭防火墙,规避端口拦截报错

# systemctl stop:临时关闭防火墙,当前立即生效
systemctl stop firewalld

# systemctl disable:永久禁止防火墙开机自启,重启机器不会自动开启
systemctl disable firewalld

2.3.4 关闭 SELinux(作用:解除系统权限拦截,K8s 必关项)

原理:SELinux 是 Linux 安全权限机制,会拦截 K8s 读写、创建资源的权限,不关闭集群百分百启动失败

# setenforce 0:临时关闭 SELinux,立即生效
setenforce 0

# sed 替换命令:修改系统配置文件,永久关闭 SELinux
# 匹配以SELINUX=开头的行,替换为SELINUX=disabled
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

2.3.5 关闭 swap 交换分区(K8s 强制要求)

新手核心知识点:swap 是硬盘虚拟内存,K8s 调度 Pod 时不允许使用虚拟内存,swap 不关闭,kubeadm 初始化直接报错终止

# swapoff -a:临时关闭所有swap分区,立即生效
swapoff -a

# sed 注释fstab文件中的swap挂载行,永久关闭,重启不恢复
sed -ri 's/.*swap.*/#&/' /etc/fstab

# 检查是否关闭
[root@k8s-master ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            3877         570        3245           9         289        3306
Swap:              0           0           0

注意: 改完fstab先重启,再做下面的操作

reboot

2.3.6 系统时间同步(作用:保证集群所有节点时间一致)

原理:K8s 证书、日志、Pod 调度依赖系统时间,三台机器时间偏差过大,会出现鉴权失败、节点离线问题

  • 每台主机安装软件

    # 判断软件是否安装
    rpm -aq chrony
    
    # dnf install:安装系统时间同步工具chrony(Rocky10默认工具)
    dnf install chrony -y
    
    # 启动chronyd服务并设置开机自启
    systemctl enable --now chronyd
    
    # 查看当前时间同步源,确认同步成功
    chronyc sources
    
  • master控制节点,设置为时间同步主节点

    # 修改相关配置
    [root@k8s-master ~]# vim /etc/chrony.conf 
    ……
    server ntp.aliyun.com iburst
    ……
    allow 192.48.75.0/24
    
    # 重启服务
    [root@k8s-master ~]# systemctl restart chronyd
    
  • 其他两个工作节点配置

    # 修改相关配置
    [root@k8s-node2 ~]# vim /etc/chrony.conf 
    …… 
    pool k8s-master  iburst
    …… 
    
    # 重启服务
    [root@k8s-node2 ~]# systemctl restart chronyd
    

    测试 是否成功

    [root@k8s-node1 ~]# chronyc sources
    MS Name/IP address         Stratum Poll Reach LastRx Last sample               
    ===============================================================================
    ^* k8s-master                    4   6    77    45   -162us[-6383us] +/-   42ms
    

    image

    注意: 一定要是 * 号才代表成功


2.3.7 加载内核模块+配置网络参数( 集群网络基础核心 | 所有节点执行 )

原理:overlay 是容器存储驱动(容器文件分层存储依赖),br_netfilter 是桥接网络模块(K8s 跨节点网络通信依赖),必须提前加载

# 创建内核模块加载配置文件,开机自动加载所需模块
cat > /etc/modules-load.d/containerd.conf <<EOF
overlay      # 容器存储内核模块
br_netfilter # 网桥过滤内核模块,用于集群网络转发
EOF


# 手动加载模块,无需重启立即生效
cat <<EOF > mod.sh
modprobe overlay
modprobe br_netfilter
modprobe ip_conntrack
EOF

bash mod.sh


-------------------------------------------------------------------------

# 加载ipvs相关内核模块
cat <<EOF > /etc/modules-load.d/ipvs.conf 
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_nq
ip_vs_sed
ip_vs_ftp
ip_vs_sh
nf_conntrack_ipv4
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF


# 配置转发相关参数,否则可能会出错
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF


# 生效所有内核参数配置
sysctl -p /etc/sysctl.d/k8s.conf

# 重启系统
reboot

# 查看是否加载成功
lsmod | grep ip_vs   # 必须重启之后 , 这个才能查到

2.4 安装 containerd 容器运行时(所有节点执行|K8s 容器引擎)

零基础科普:K8s 1.24 及以上版本不再支持 Docker,必须使用 containerd 作为容器运行引擎,所有 Pod 容器都由它启动管理

# 获取阿里云docker yum源
[root@k8s-master ~]#  wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 清理并加载
[root@k8s-master ~]# yum clean all;  yum makecache; yum repolist -v

# 查看YUM源中Containerd软件
[root@k8s-master ~]# yum list | grep containerd
containerd.io.x86_64          2.3.3-1.el10              docker-ce-stable
  1. 安装 containerd

# 安装软件
[root@k8s-master ~]# yum -y install containerd.io.x86_64 

# 设置containerd服务启动及开机自启动
[root@k8s-master ~]# systemctl enable --now containerd

# 测试可用性
[root@k8s-master ~]# ctr version
  1. 配置containerd

    • 生成containerd配置文件

      # 生成默认配置,config.toml这个文件二进制安装方式默认不存在,如果是Yum安装则直接覆盖
      containerd config default > /etc/containerd/config.toml
      
    • 配置containerd cgroup 驱动程序systemd

      # 把SystemdCgroup = false修改为:SystemdCgroup = true,
      sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
      
      cat /etc/containerd/config.toml | grep SystemdCgroup
                  SystemdCgroup = true
      
    • 修改sandbox_image 镜像源

      # 修改sandbox_image 镜像源,1.24以下k8s.gcr.io 、1.25 改成了registry.k8s.io,如果FQ了,这步就不用做了
      sed -i "s#registry.k8s.io/pause#registry.aliyuncs.com/google_containers/pause#g" /etc/containerd/config.toml
      
    • Containerd配置镜像加速

      endpoint位置添加阿里云的镜像源,https://1qfxozzy.mirror.aliyuncs.com这个地址是我自己阿里加速器地址,每个人都不一样

      # 新配置,k8s1.34版本之后,没有了上面mirrors相关的配置,直接修改下面这个config_path选项
      # 创建目录
      [root@k8s-master ~]# mkdir -p /etc/containerd/certs.d
      
      [root@k8s-master ~]# vim /etc/containerd/config.toml
      
      [plugins.'io.containerd.cri.v1.images'.registry]
         config_path = '/etc/containerd/certs.d'
            
      # 然后,在 /etc/containerd/certs.d 目录下为每个需要配置的镜像仓库创建子目录,并添加相应的配置文件。例如,为 docker.io 创建配置:
      
      mkdir -p /etc/containerd/certs.d/{docker.io,aliyuncs.com}
      
      # 创建index.conf文件添加镜像源地址:
      cat <<EOF | tee /etc/containerd/certs.d/docker.io/index.conf
      mirrors:
        - https://registry-1.docker.io
      EOF
        
      cat <<EOF | tee /etc/containerd/certs.d/aliyuncs.com/index.conf
      mirrors:
        - https://1qfxozzy.mirror.aliyuncs.com
      EOF
      
  2. 配置crictl

    注意:这是1.36之前的操作,1.36版本只需要****yum install cri-tools -y即可)


    因为ctr命令查看镜像非常混乱,可以用这个命令查看镜像

    cat <<EOF | tee /etc/crictl.yaml
    runtime-endpoint: unix:///run/containerd/containerd.sock
    image-endpoint: unix:///run/containerd/containerd.sock
    timeout: 10
    debug: false
    EOF
    

重启containerd

systemctl restart containerd

手动安装crictl,这个工具会自动下载,如果不想等,可以自己手动安装

https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.27.0/crictl-v1.27.0-linux-amd64.tar.gz

# 下载 crictl 的最新版本
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.27.0/crictl-v1.27.0-linux-amd64.tar.gz -P /opt/bin

# 解压 tar 文件
tar zxvf crictl-v1.27.0-linux-amd64.tar.gz -C /usr/local/bin/

echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc
source ~/.bashrc

crictl --version

# 查看镜像
crictl image list

2.5 配置 K8s 官方软件源(所有节点执行)

# 官方源 v1.35
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF

# 清理旧缓存,刷新新软件源缓存
[root@k8s-node1 ~]# yum clean all; yum makecache ; yum repolist -v

2.6 安装 K8s 核心组件(所有节点执行)

组件零基础通俗讲解:

  • kubeadm:集群初始化工具,负责创建集群、节点加入、重置集群

  • kubelet:节点守护进程,常驻后台,管理当前节点所有 Pod 的启动、停止、重启

  • kubectl:集群命令行工具,所有查看、操作集群的命令都靠它执行

# 查看软件源中 有什么版本
[root@k8s-master ~]# dnf list --showduplicates kubeadm --disableexcludes=kubernetes

# 安装最新版
# 默认为最新版,对应最新版k8s
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# --disableexcludes=kubernetes 禁掉除了这个kubernetes之外的别的仓库

# 查看版本
[root@k8s-master ~]# kubectl version
Client Version: v1.35.7
[root@k8s-master ~]# yum info kubeadm
……
Name         : kubeadm
Version      : 1.35.7

# 设置kubelet开机自启,集群必备后台服务
systemctl enable --now kubelet
systemctl status kubelet

⚠️ 新手须知:集群未初始化前 kubelet 会报错,属于正常现象,无需处理!

服务会出现起不来的现象

2.7 获取镜像

特别说明:

三个节点都要下载

注意下载时把版本号修改到官方最新版,即使下载了最新版也可能版本不对应,需要按报错提示下载

每次部署都会有版本更新,具体版本要求,运行初始化过程失败会有版本提示

kubeadm的版本和镜像的版本最好是对应的

# 查看镜像 
[root@k8s-master ~]# kubeadm config images list --kubernetes-version v1.35.7
registry.k8s.io/kube-apiserver:v1.35.7
registry.k8s.io/kube-controller-manager:v1.35.7
registry.k8s.io/kube-scheduler:v1.35.7
registry.k8s.io/kube-proxy:v1.35.7
registry.k8s.io/coredns/coredns:v1.13.1
registry.k8s.io/pause:3.10.1
registry.k8s.io/etcd:3.6.6-0

-----------------------------------------------------------
# 查看国内镜像
[root@k8s-master ~]# kubeadm config images list --kubernetes-version v1.35.7 --image-repository  registry.aliyuncs.com/google_containers
registry.aliyuncs.com/google_containers/kube-apiserver:v1.35.7
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.35.7
registry.aliyuncs.com/google_containers/kube-scheduler:v1.35.7
registry.aliyuncs.com/google_containers/kube-proxy:v1.35.7
registry.aliyuncs.com/google_containers/coredns:v1.13.1
registry.aliyuncs.com/google_containers/pause:3.10.1
registry.aliyuncs.com/google_containers/etcd:3.6.6-0

------------------------------------------------------------------------------------
下载镜像
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/etcd:3.6.6-0
注意:必须用-n指定namespace,否则k8s和crictr都看不到镜像
下载下来的镜像名称不用重新修改,直接使用aliyun的镜像


----------------------------------------------------------------------
1.35版本官方镜像
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.35.7
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.35.7
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.35.7
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/kube-proxy:v1.35.7
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/coredns:v1.13.1
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/pause:3.10.1
ctr -n=k8s.io image pull registry.aliyuncs.com/google_containers/etcd:3.6.6-0

image

3 集群初始化(仅控制节点执行|参数逐行详解)

💡 核心:仅 k8s-node1(192.48.75.10) 执行,工作节点禁止执行!本命令用于创建整个 K8s 集群核心架构。

这里推荐两种方式, 一种命令行, 一种配置文件, 命令行是 相对较老的版本, 建议用配置文件, 两种结果一样

  • 配置文件
[root@k8s-master ~]# kubeadm config print init-defaults > kubeadm.yml

修改刚生成的配置文件 advertiseAddress:为控制平面地址( Master 主机 IP ) criSocket:为 containerd 的 socket 文件地址 imageRepository:阿里云镜像代理地址,否则拉取镜像会失败 kubernetesVersion:为 k8s 版本

podSubnet: 10.244.0.0/16 : 同步网络插件flannal默认的pod网段地址

  • socket文件位置
[root@master ~]# find / -name 'containerd.sock'
/run/containerd/containerd.sock
  • 配置文件
apiVersion: kubeadm.k8s.io/v1beta4
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.48.75.10                               # 修改为自己master的ip
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///run/containerd/containerd.sock    # 修改为containerd的socket
  imagePullPolicy: IfNotPresent
  imagePullSerial: true
  name: k8s-master                                 # 主节点名称
  taints: null
timeouts:
  controlPlaneComponentHealthCheck: 4m0s
  discovery: 5m0s
  etcdAPICall: 2m0s
  kubeletHealthCheck: 4m0s
  kubernetesAPICall: 1m0s
  tlsBootstrap: 5m0s
  upgradeManifests: 5m0s
---
apiServer: {}
apiVersion: kubeadm.k8s.io/v1beta4
caCertificateValidityPeriod: 87600h0m0s
certificateValidityPeriod: 8760h0m0s
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
encryptionAlgorithm: RSA-2048
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers               # 修改为阿里云镜像仓库
kind: ClusterConfiguration
kubernetesVersion: 1.35.7                        # 要安装的版本号
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
  podSubnet: 10.244.0.0/16    # 新添加的行,和即将要安装的网络插件有关
proxy: {}
scheduler: {}

---                                                       # 此处所有内容为追加
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd

开始初始化

kubeadm init --config=kubeadm.yml

如果报错, 请先清理, 然后在初始化

kubeadm reset -f; rm -rf /etc/kubernetes/*; rm -rf /var/lib/kubelet/*; rm -rf /var/lib/etcd

结果如下

image

上面记录了完成的初始化输出的内容,根据输出可以看出手动初始化安装一个Kubernetes集群所需要的关键步骤。其中有以下关键内容:

[kubelet] 生成kubelet的配置文件"/var/lib/kubelet/config.yaml"
[certificates]生成相关的各种证书
[kubeconfig]生成相关的kubeconfig文件
[bootstraptoken]生成token记录下来,后边使用kubeadm join往集群中添加节点时会用到

image

按照初始化结果运行以下指令

export KUBECONFIG=/etc/kubernetes/admin.conf

# 创建用户kubeconfig配置目录
mkdir -p $HOME/.kube

# 将集群管理员配置文件复制到用户目录
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

# 修改文件归属为当前用户,授权操作权限
sudo chown $(id -u):$(id -g) $HOME/.kube/config

检测

[root@k8s-master ~]# kubectl get nodes
NAME         STATUS     ROLES           AGE     VERSION
k8s-master   NotReady   control-plane   3m54s   v1.35.7

因为网络插件没有配置


  • 命令模式

无注释

kubeadm init \
--apiserver-advertise-address=192.48.75.10 \
--pod-network-cidr=10.244.0.0/16 \
--image-repository registry.aliyuncs.com/google_containers \
--cri-socket=unix:///var/run/containerd/containerd.sock

image

  • 这一步需要一定时间

注释详解

kubeadm init \
# 指定主节点API服务监听IP(必须是本机固定IP)
--apiserver-advertise-address=192.48.75.10 \
# 指定集群Pod网段,flannel网络插件固定适配此网段
--pod-network-cidr=10.244.0.0/16 \
# 指定阿里云镜像仓库,替代国外谷歌仓库,解决镜像拉取失败
--image-repository registry.aliyuncs.com/google_containers \
# 指定容器运行时socket路径,告知K8s使用containerd而非docker
--cri-socket=unix:///var/run/containerd/containerd.sock

3.1 配置管理员集群权限(新手操作集群必备)

原理:初始化后集群证书默认在系统目录,普通用户无法操作,复制到用户目录并授权,实现普通用户使用 kubectl 命令

export KUBECONFIG=/etc/kubernetes/admin.conf

# 创建用户kubeconfig配置目录
mkdir -p $HOME/.kube

# 将集群管理员配置文件复制到用户目录
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

# 修改文件归属为当前用户,授权操作权限
sudo chown $(id -u):$(id -g) $HOME/.kube/config

3.2 生成永久节点加入命令(解决token过期问题)

零基础知识点:默认集群加入令牌24小时过期,此命令生成永久有效的加入命令,方便后续节点加入集群

# 生成永久有效join命令,输出结果复制到两台工作节点执行
kubeadm token create --print-join-command --ttl=0

示例输出(新手直接复制自己机器输出的整条命令):

image

kubeadm join 192.48.75.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxxx

kubeadm join 192.48.75.10:6443 --token wfbics.7byjzuftbp70rvc0 --discovery-token-ca-cert-hash sha256:a71bc4fc467db17043269a08914f1e8ec08a4f81b526ae8d6d0c22749cd34c61 

✅ 操作:两台工作节点执行上述命令,即可加入集群

image

3.3、测试

[root@k8s-master ~]# kubectl get nodes
NAME         STATUS     ROLES           AGE     VERSION
k8s-master   NotReady   control-plane   8m50s   v1.26.0
k8s-node1    NotReady   <none>          53s     v1.26.0
k8s-node2    NotReady   <none>          50s     v1.26.0

此时 master 节点状态是NotReady这个是正常现象,还没装网络插件

4 部署 Flannel 网络插件(仅控制节点执行|零基础网络原理)

新手必懂:集群初始化后,所有节点都是 NotReady(未就绪) 状态,因为缺少网络插件!Flannel 负责集群所有 Pod 跨节点通信,不部署集群无法使用。

注意:flannel和calico只能二选一

master节点下载yaml配置文件

版本会经常更新,flannel官方存储与github上,如果无法下载需要FQ直接github搜索flannel得到如下地址https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml,然后浏览器打开右键另存到本地。

因为版本更新比较快, 可以直接访问 https://github.com/search?g=flannel

image

image

image

image

可以根据这个网址下载文件

下载镜像

用其他docker 主机下载了镜像

# 下载镜像
docker pull rancher/mirrored-flannelcni-flannel:v0.20.2 
docker pull rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.2

# 打包镜像
docker save rancher/mirrored-flannelcni-flannel:v0.20.2 -o flannel-v0.20.2.tar
docker save rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.2 -o flannel-cni-v1.1.2.tar

# k8s‑master 节点导入镜像到 containerd
ctr -n=k8s.io image import flannel-v0.20.2.tar 
ctr -n=k8s.io image import flannel-cni-v1.1.2.tar

# 查看
[root@k8s-master ~]# ctr -n=k8s.io image list | grep flannel

修改镜像

apiVersion: v1
kind: Namespace
metadata:
  labels:
    k8s-app: flannel
    pod-security.kubernetes.io/enforce: privileged
  name: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: flannel
  name: flannel
  namespace: kube-flannel
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: flannel
  name: flannel
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: flannel
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-flannel
---
apiVersion: v1
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "EnableNFTables": false,
      "Backend": {
        "Type": "vxlan"
      }
    }
kind: ConfigMap
metadata:
  labels:
    app: flannel
    k8s-app: flannel
    tier: node
  name: kube-flannel-cfg
  namespace: kube-flannel
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: flannel
    k8s-app: flannel
    tier: node
  name: kube-flannel-ds
  namespace: kube-flannel
spec:
  selector:
    matchLabels:
      app: flannel
      k8s-app: flannel
  template:
    metadata:
      labels:
        app: flannel
        k8s-app: flannel
        tier: node
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - linux
      containers:
      - args:
        - --ip-masq
        - --kube-subnet-mgr
        command:
        - /opt/bin/flanneld
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: EVENT_QUEUE_DEPTH
          value: "5000"
        - name: CONT_WHEN_CACHE_NOT_READY
          value: "false"
        image: ghcr.io/flannel-io/flannel:v0.28.9
        name: kube-flannel
        resources:
          requests:
            cpu: 100m
            memory: 50Mi
        securityContext:
          capabilities:
            add:
            - NET_ADMIN
            - NET_RAW
          privileged: false
        volumeMounts:
        - mountPath: /run/flannel
          name: run
        - mountPath: /etc/kube-flannel/
          name: flannel-cfg
        - mountPath: /run/xtables.lock
          name: xtables-lock
      hostNetwork: true
      initContainers:
      - args:
        - -f
        - /flannel
        - /opt/cni/bin/flannel
        command:
        - cp
        image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.2
        name: install-cni-plugin
        volumeMounts:
        - mountPath: /opt/cni/bin
          name: cni-plugin
      - args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        command:
        - cp
        image: docker.io/rancher/mirrored-flannelcni-flannel:v0.20.2
        name: install-cni
        volumeMounts:
        - mountPath: /etc/cni/net.d
          name: cni
        - mountPath: /etc/kube-flannel/
          name: flannel-cfg
      priorityClassName: system-node-critical
      serviceAccountName: flannel
      tolerations:
      - effect: NoSchedule
        operator: Exists
      volumes:
      - hostPath:
          path: /run/flannel
        name: run
      - hostPath:
          path: /opt/cni/bin
        name: cni-plugin
      - hostPath:
          path: /etc/cni/net.d
        name: cni
      - configMap:
          name: kube-flannel-cfg
        name: flannel-cfg
      - hostPath:
          path: /run/xtables.lock
          type: FileOrCreate
        name: xtables-lock

执行部署命令(零基础直接复制):

# 如果重新修改了配置文件, 需要先删除旧的  daemonset 
[root@k8s-master ~]# kubectl delete daemonset kube-flannel-ds -n kube-flannel

# 应用yaml配置,部署flannel网络插件
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml

5 集群状态验证(零基础结果解读教学)

部署完成后等待 1-3 分钟,等待所有网络 Pod 启动就绪,执行以下验证命令:

# 查看所有集群节点状态
[root@k8s-master ~]# kubectl get pods -n kube-flannel -o wide

# 正常结果:三个节点全部显示 Ready
[root@k8s-master ~]#  kubectl get nodes

# 查看集群所有Pod运行状态
# 正常结果:所有Pod状态为Running,无报错、无重启
[root@k8s-master ~]#  kubectl get pod -A

集群搭建成功标准:节点全部 Ready、系统 Pod 全部 Running,无异常状态。

image


6 kubectl命令补全设置

默认的 kubectl 是没有命令补全的, 需要我们自己设置

kubectl 自动补全
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
需要退出当前shell重新登录以使其生效

现在使用, 就可以直接 tab 了

7 k8s 接入Harbor

  1. 环境准备

    # 创建仓库证书统一存放目录(新标准规范)
    mkdir -p /etc/containerd/certs.d
    
  2. 域名解析配置(所有节点)

    所有K8s节点配置hosts解析,保证能正常解析Harbor地址:

    # 替换为你的Harbor服务器IP与域名
    echo "192.48.75.165 harbor.company.local" >> /etc/hosts
    

  1. Harbor HTTPS 带证书仓库(生产环境)

    生产环境强制使用HTTPS,导入Harbor CA证书,保证镜像拉取安全可信。

步骤 1:所有 K8s 节点配置 hosts 域名解析

集群每一台机器,master、每个 worker 都执行

#写入hosts
echo "192.48.75.165 harbor.company.local" >> /etc/hosts

#验证解析是否生效
ping harbor.company.local

步骤 2:操作系统全局信任 Harbor CA 根证书(所有节点)

让 curl、wget 等系统工具信任 harbor 的 https 证书

mkdir -p /etc/pki/ca-trust/source/anchors/
#把harbor服务器ca.crt拷贝到本机
scp root@192.48.75.165:/opt/harbor/cert/ca.crt /etc/pki/ca-trust/source/anchors/
#更新系统证书库
update-ca-trust

#验证系统https访问harbor是否正常
curl -I https://harbor.company.local

步骤 3:containerd 镜像仓库证书目录配置(所有节点)

containerd 拉镜像,会读取/etc/containerd/certs.d目录下证书,这是 containerd 独立证书体系,不依赖系统 ca‑trust。 目录名必须完全等于 harbor 域名harbor.company.local

#创建根目录
mkdir -p /etc/containerd/certs.d
#创建对应域名的证书目录
mkdir -p /etc/containerd/certs.d/harbor.company.local

#拷贝harbor ca.crt到此目录
scp root@192.48.75.165:/opt/harbor/cert/ca.crt /etc/containerd/certs.d/harbor.company.local/
chmod 644 /etc/containerd/certs.d/harbor.company.local/ca.crt

步骤 4:修改 containerd 配置文件 /etc/containerd/config.toml

⚠️删掉文档里面的 [].auth 明文账号密码块!!不要写 username password!! 只保留 registry 的 config_path,mirrors、tls 配置。 重点:mirrors、configs 的 key 域名必须是真实域名harbor.company.local,不要写 harbor.k8s.local!

找到 [plugins."io.containerd.grpc.v1.cri".registry],修改 config_path:

[plugins."io.containerd.grpc.v1.cri".registry]
  config_path = "/etc/containerd/certs.d"

文件末尾追加下面完整片段

#镜像仓库镜像配置,key写真实harbor域名 harbor.company.local
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.company.local"]
  endpoint = ["https://harbor.company.local"]

#TLS证书配置,关闭跳过证书校验
[plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.company.local".tls]
  ca_file = "/etc/containerd/certs.d/harbor.company.local/ca.crt"
  insecure_skip_verify = false

###########【重要】这里不要加auth块!不要写admin密码!!生产禁止明文!!###########

所有节点重启 containerd 生效

systemctl daemon-reload;systemctl restart containerd
systemctl status containerd

校验配置是否加载成功,检查没有报错即可。

测试 containerd 能否拉镜像(节点本地测试)

--creds仅临时测试用,不会写入配置文件,测试完就完事

crictl pull --creds admin:Harbor123456 harbor.company.local/nginx/nginx:v1.19

成功:代表节点证书、网络全部正常。

失败:排查 hosts、ca.crt 文件路径、config.toml 语法、containerd 状态。

注意:crictl 测试成功 ≠ Pod 可以跑起来。Pod 不会使用--creds参数,Pod 依赖 k8s 的 secret。

步骤 5:K8s 集群创建 ImagePullSecret(只需要在 master 执行,集群资源,worker 不用执行)

secret 是 k8s 集群资源,只需要执行一次,生效在当前命名空间 (default) --docker-server 只写域名,不带 https://

kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.company.local \
--docker-username=admin \
--docker-password=Harbor123456

查看 secret 是否创建成功

kubectl get secrets

输出列表能看到harbor‑secret

步骤 6【推荐】配置当前命名空间全局默认镜像秘钥

default 命名空间所有 Pod 自动带上拉取秘钥,yaml 不需要每次写imagePullSecrets 仅 master 执行

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-secret"}]}'

校验 sa 配置是否写入成功:

kubectl get sa default -o yaml

看到输出包含imagePullSecrets: - name: harbor-secret代表配置完成。

⚠️注意:已经存在的旧 Pod 不会自动继承 sa 配置,旧 Pod 必须删除重建

# 删除旧的 pod
  kubectl delete pod harbor-demo-pod

步骤 7:编写测试 Pod yaml harbor-demo-pod.yaml

因为已经配置全局 sa,yaml 中不需要写 imagePullSecrets

apiVersion: v1
kind: Pod
metadata:
  name: harbor-demo-pod
spec:
  containers:
  - name: nginx
    image: harbor.company.local/nginx/nginx:v1.19
    ports:
    - containerPort: 80

执行创建 pod

# 构建pod
[root@k8s-master ~]# kubectl apply -f harbor-demo-pod.yaml

# 查看
[root@k8s-master ~]# kubectl get po
NAME              READY   STATUS             RESTARTS   AGE
harbor-demo-pod   1/1     Running            0          13m

步骤 8:排错流程(出现 ImagePullBackOff 必做)

#查看pod完整事件,看真实报错原因
kubectl describe pod harbor-demo-pod

  1. crictl 命令

注意:crictl 没有 push 推送镜像命令!推送镜像请用 docker 或者 nerdctl,crictl 只负责 CRI,也就是 K8s 节点拉镜像,不负责上传镜像到 Harbor

命令 作用 常用示例
crictl images 列出本地所有镜像 crictl images
crictl pull 拉取镜像 crictl pull --creds user:pass harbor.company.local/xxx:tag
crictl rmi 删除本地镜像 crictl rmi harbor.company.local/nginx/nginx:v1.19
crictl inspecti 查看镜像详细元数据 crictl inspecti harbor.company.local/nginx/nginx:v1.19
crictl load 导入本地 tar 镜像包 crictl load -i xxx.tar
crictl save 导出镜像到 tar 包 crictl save -o output.tar harbor.company.local/nginx/nginx:v1.19

8 新手高频报错解决方案

  1. 节点一直 NotReady

  • 90% 原因:Flannel Pod 未启动成功,执行 kubectl get pod -n kube-flannel 查看异常日志

  • 10% 原因:swap 未彻底关闭、内核参数未生效,重新执行环境配置命令

  1. containerd 启动失败

  • 核心原因:toml 配置文件空格、缩进错误(新手最容易出错)

  • 解决方案:直接复制本教程完整配置覆盖,不要手动修改格式

  1. 初始化镜像拉取失败

  • 检查机器外网是否通畅

  • 确认初始化命令使用了阿里云镜像仓库参数

  • Swap 没关闭

  • 主机名填写错误

  1. 工作节点加入集群失败

  • 核对三台机器 hosts 解析是否一致

  • 确认防火墙、SELinux、swap 全部关闭

  • 确认所有节点时间同步一致

posted @ 2026-09-06 11:24  Docker-沫老师  阅读(16)  评论(0)    收藏  举报