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 修改或删除
Shell
# 生成本机的 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 识别节点,三台机器必须拥有不同主机名,永久生效
bash
# ========== 仅 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,避免集群通信失败
bash
# 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 集群有成百上千个端口需要互通,手动放行极其麻烦,测试环境直接关闭防火墙,规避端口拦截报错
bash
# systemctl stop:临时关闭防火墙,当前立即生效
systemctl stop firewalld
# systemctl disable:永久禁止防火墙开机自启,重启机器不会自动开启
systemctl disable firewalld
2.3.4 关闭 SELinux(作用:解除系统权限拦截,K8s 必关项)
原理:SELinux 是 Linux 安全权限机制,会拦截 K8s 读写、创建资源的权限,不关闭集群百分百启动失败
bash
# 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 初始化直接报错终止
bash
# 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先重启,再做下面的操作
Shell
reboot
2.3.6 系统时间同步(作用:保证集群所有节点时间一致)
原理:K8s 证书、日志、Pod 调度依赖系统时间,三台机器时间偏差过大,会出现鉴权失败、节点离线问题
-
每台主机安装软件
Shell# 判断软件是否安装 rpm -aq chrony # dnf install:安装系统时间同步工具chrony(Rocky10默认工具) dnf install chrony -y # 启动chronyd服务并设置开机自启 systemctl enable --now chronyd # 查看当前时间同步源,确认同步成功 chronyc sources -
master控制节点,设置为时间同步主节点
Shell# 修改相关配置 [root@k8s-master ~]# vim /etc/chrony.conf ...... server ntp.aliyun.com iburst ...... allow 192.48.75.0/24 # 重启服务 [root@k8s-master ~]# systemctl restart chronyd -
其他两个工作节点配置
Shell# 修改相关配置 [root@k8s-node2 ~]# vim /etc/chrony.conf ...... pool k8s-master iburst ...... # 重启服务 [root@k8s-node2 ~]# systemctl restart chronyd测试 是否成功
Shell[root@k8s-node1 ~]# chronyc sources MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== ^* k8s-master 4 6 77 45 -162us[-6383us] +/- 42ms
注意: 一定要是 * 号才代表成功
2.3.7 加载内核模块+配置网络参数( 集群网络基础核心 | 所有节点执行 )
原理:overlay 是容器存储驱动(容器文件分层存储依赖),br_netfilter 是桥接网络模块(K8s 跨节点网络通信依赖),必须提前加载
bash
# 创建内核模块加载配置文件,开机自动加载所需模块
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 容器都由它启动管理
bash
# 获取阿里云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
安装 containerd
Shell
# 安装软件
[root@k8s-master ~]# yum -y install containerd.io.x86_64
# 设置containerd服务启动及开机自启动
[root@k8s-master ~]# systemctl enable --now containerd
# 测试可用性
[root@k8s-master ~]# ctr version
配置containerd
-
生成containerd配置文件
Shell# 生成默认配置,config.toml这个文件二进制安装方式默认不存在,如果是Yum安装则直接覆盖 containerd config default > /etc/containerd/config.toml -
配置containerd cgroup 驱动程序systemd
Shell# 把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 镜像源
Shell# 修改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这个地址是我自己阿里加速器地址,每个人都不一样
Shell# 新配置,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
配置crictl
注意:这是1.36之前的操作,1.36版本只需要****yum install cri-tools -y即可)
因为ctr命令查看镜像非常混乱,可以用这个命令查看镜像
Bash
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
Shell
systemctl restart containerd
手动安装crictl,这个工具会自动下载,如果不想等,可以自己手动安装
Shell
# 下载 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 官方软件源(所有节点执行)
bash
# 官方源 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:集群命令行工具,所有查看、操作集群的命令都靠它执行
bash
# 查看软件源中 有什么版本
[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的版本和镜像的版本最好是对应的
Bash
# 查看镜像
[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

3 集群初始化(仅控制节点执行|参数逐行详解)
💡 核心:仅 k8s-node1(192.48.75.10) 执行,工作节点禁止执行!本命令用于创建整个 K8s 集群核心架构。
这里推荐两种方式, 一种命令行, 一种配置文件, 命令行是 相对较老的版本, 建议用配置文件, 两种结果一样
- 配置文件
Shell
[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文件位置
Shell
[root@master ~]# find / -name 'containerd.sock'
/run/containerd/containerd.sock
- 配置文件
YAML
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
开始初始化
Shell
kubeadm init --config=kubeadm.yml
如果报错, 请先清理, 然后在初始化
Shell
kubeadm reset -f; rm -rf /etc/kubernetes/*; rm -rf /var/lib/kubelet/*; rm -rf /var/lib/etcd
结果如下

上面记录了完成的初始化输出的内容,根据输出可以看出手动初始化安装一个Kubernetes集群所需要的关键步骤。其中有以下关键内容:
Shell
[kubelet] 生成kubelet的配置文件"/var/lib/kubelet/config.yaml"
[certificates]生成相关的各种证书
[kubeconfig]生成相关的kubeconfig文件
[bootstraptoken]生成token记录下来,后边使用kubeadm join往集群中添加节点时会用到

按照初始化结果运行以下指令
Shell
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
检测
Shell
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master NotReady control-plane 3m54s v1.35.7
因为网络插件没有配置
- 命令模式
无注释
Shell
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

- 这一步需要一定时间
注释详解
bash
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 命令
bash
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小时过期,此命令生成永久有效的加入命令,方便后续节点加入集群
bash
# 生成永久有效join命令,输出结果复制到两台工作节点执行
kubeadm token create --print-join-command --ttl=0
示例输出(新手直接复制自己机器输出的整条命令):

kubeadm join 192.48.75.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxxx
Shell
kubeadm join 192.48.75.10:6443 --token wfbics.7byjzuftbp70rvc0 --discovery-token-ca-cert-hash sha256:a71bc4fc467db17043269a08914f1e8ec08a4f81b526ae8d6d0c22749cd34c61
✅ 操作:两台工作节点执行上述命令,即可加入集群

3.3、测试
Shell
[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




可以根据这个网址下载文件
下载镜像
用其他docker 主机下载了镜像
Shell
# 下载镜像
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
修改镜像
YAML
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
执行部署命令(零基础直接复制):
bash
# 如果重新修改了配置文件, 需要先删除旧的 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 启动就绪,执行以下验证命令:
bash
# 查看所有集群节点状态
[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,无异常状态。

6 kubectl命令补全设置
默认的 kubectl 是没有命令补全的, 需要我们自己设置
Shell
kubectl 自动补全
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
需要退出当前shell重新登录以使其生效
现在使用, 就可以直接 tab 了
7 k8s 接入Harbor
环境准备
Shell
# 创建仓库证书统一存放目录(新标准规范)
mkdir -p /etc/containerd/certs.d
域名解析配置(所有节点)
所有K8s节点配置hosts解析,保证能正常解析Harbor地址:
Shell
# 替换为你的Harbor服务器IP与域名
echo "192.48.75.165 harbor.company.local" >> /etc/hosts
Harbor HTTPS 带证书仓库(生产环境)
生产环境强制使用HTTPS,导入Harbor CA证书,保证镜像拉取安全可信。
步骤 1:所有 K8s 节点配置 hosts 域名解析
集群每一台机器,master、每个 worker 都执行
Shell
#写入hosts
echo "192.48.75.165 harbor.company.local" >> /etc/hosts
#验证解析是否生效
ping harbor.company.local
步骤 2:操作系统全局信任 Harbor CA 根证书(所有节点)
让 curl、wget 等系统工具信任 harbor 的 https 证书
Shell
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
Shell
#创建根目录
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:
TOML
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
文件末尾追加下面完整片段
TOML
#镜像仓库镜像配置,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 生效
Shell
systemctl daemon-reload;systemctl restart containerd
systemctl status containerd
校验配置是否加载成功,检查没有报错即可。
测试 containerd 能否拉镜像(节点本地测试)
--creds仅临时测试用,不会写入配置文件,测试完就完事
Plain
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://
Plain
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.company.local \
--docker-username=admin \
--docker-password=Harbor123456
查看 secret 是否创建成功
Plain
kubectl get secrets
输出列表能看到harbor‑secret。
步骤 6【推荐】配置当前命名空间全局默认镜像秘钥
default 命名空间所有 Pod 自动带上拉取秘钥,yaml 不需要每次写
imagePullSecrets仅 master 执行
Shell
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-secret"}]}'
校验 sa 配置是否写入成功:
Plain
kubectl get sa default -o yaml
看到输出包含imagePullSecrets: - name: harbor-secret代表配置完成。
⚠️注意:已经存在的旧 Pod 不会自动继承 sa 配置,旧 Pod 必须删除重建。
Shell
# 删除旧的 pod
kubectl delete pod harbor-demo-pod
步骤 7:编写测试 Pod yaml harbor-demo-pod.yaml
因为已经配置全局 sa,yaml 中不需要写 imagePullSecrets
YAML
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
Shell
# 构建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 必做)
Plain
#查看pod完整事件,看真实报错原因
kubectl describe pod harbor-demo-pod
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 新手高频报错解决方案
节点一直 NotReady
-
90% 原因:Flannel Pod 未启动成功,执行
kubectl get pod -n kube-flannel查看异常日志 -
10% 原因:swap 未彻底关闭、内核参数未生效,重新执行环境配置命令
containerd 启动失败
-
核心原因:toml 配置文件空格、缩进错误(新手最容易出错)
-
解决方案:直接复制本教程完整配置覆盖,不要手动修改格式
初始化镜像拉取失败
-
检查机器外网是否通畅
-
确认初始化命令使用了阿里云镜像仓库参数
-
Swap 没关闭
-
主机名填写错误
工作节点加入集群失败
-
核对三台机器 hosts 解析是否一致
-
确认防火墙、SELinux、swap 全部关闭
-
确认所有节点时间同步一致