简介
本文从零开始搭建一套完整的Kubernetes学习环境,包含Harbor私有镜像仓库 、iKuai软路由网关 以及1 Master + 2 Node的K8s集群。
与常规教程不同,本文将带你深入理解:
- 为什么需要单独安装cri-dockerd?
- Master和Node节点各自需要哪些组件?
- 容器运行时(Docker vs containerd)该如何选择?
- Pod创建背后的完整调用链路
无论你是刚入门K8s还是想理清底层原理,这篇实战指南都值得一读。
前言
主机规划:Harbor + iKuai + K8s 集群(1 Master + 2 Node)
网络说明 :
K8s 集群采用仅主机模式 部署,节点间可互通但无法访问外网。为实现镜像拉取、外部通信等需求,引入 iKuai 软路由 作为集群网关。iKuai 通过 NAT 模式提供外网出口,并为各节点分配网关(
192.168.10.200)与 DNS,确保集群在一个隔离、可控、具备外网访问能力的网络环境中运行。
ikuai主机
1.下载与虚拟机创建
- 下载镜像:从 iKuai 官网下载 32 位 ISO(实验环境要求低,真实环境用 64 位)。
- 创建虚拟机 :
- 使用 VMware 新建虚拟机,选择"稍后安装操作系统"。
- 操作系统类型选择"其他"。
- 配置处理器(至少 1 核)、内存(1GB)、磁盘(默认 IDE 类型,32 位 iKuai 仅支持 IDE)。
- 网络:第一块网卡使用仅主机模式 (用于与 Kubernetes 集群通信),后续再添加第二块 NAT 模式网卡(用于访问外网)。
- 择 I/O 控制器类型选推荐:BusLogic
- 磁盘类型选推荐:IDE
- 选创建新磁盘 & 磁盘存储为单个文件
2.虚拟机配置与系统安装
先不开机!!!
- 编辑虚拟机设置 :
- 添加第二块网卡(NAT 模式)。
- 将 CD/DVD 关联到下载的 iKuai ISO 镜像。
- 启动虚拟机 ,按提示输入
y开始安装,安装完成后自动重启。
3.基本网络配置(控制台操作)
-
重启后进入控制台菜单,选择
2、设置 LAN/WAN 地址。 -
输入
0设置 LAN1 地址,例如:192.168.10.100/255.255.255.0 -
按
Esc返回上级菜单,输入q退出到控制台,再输入q锁定配置。

4.Web 管理页面配置
-
浏览器访问
http://192.168.10.100,默认用户名/密码:admin/admin。 -
首次登录强制修改密码(如
Ikuai888,需大小写字母+数字,≥8位)。 -
进入管理页面后:
- 点击 网络设置 → 内外网设置。
- 内网网口(仅主机模式)已自动启用(显示绿色)。
- 点击灰色的外网网口图标 → 选择网卡
eth1→ 绑定。 - 接入方式选择 DHCP(动态获取) → 保存。
-
返回内外网设置页面,确认外网网口也变为绿色,表示已正常工作。

5.作用说明
- 该 iKuai 虚拟机作为 Kubernetes 集群的软路由。
- 为集群中的主机(Master/Node)提供:
- 网关 :
192.168.10.200 - DNS 和 DHCP 服务(外网通过 NAT 转发)
- 集群内部通信(仅主机模式隔离)
- 网关 :
私人仓库harbor
不是必要的,但是推荐学习搭建一下!!!
之前搭建过,见:Harbor构建私有仓库---个人专属-CSDN博客,但是之前是NAT模式的一张网卡。
因为后面k8s集群可能要在harbor上拉取/推送镜像。
现在再加一张仅主机的网卡,通过ikuai主机通信。
1.改ip,主机名
bash
[root@harbor ~]# nmcli c show
NAME UUID TYPE DEVICE
ens160 54c13d54-3ae5-3f23-ab5e-a1b8bbe047f3 ethernet ens160
Wired connection 1 c1c42f97-fcd6-3c02-9bd0-55b9fd924fe8 ethernet ens224
br-d12a67195c76 9b37912d-12cf-492c-bada-b9e66647ed62 bridge br-d12a67195c76
lo 5605fb5c-0551-45ba-8154-ed65cbe9f646 loopback lo
docker0 93814bc6-ad85-4fe2-8457-778cb279e74c bridge docker0
[root@harbor ~]# nmcli c m Wired\ connection\ 1 connection.id ens224
[root@harbor ~]# nmcli c show
NAME UUID TYPE DEVICE
ens160 54c13d54-3ae5-3f23-ab5e-a1b8bbe047f3 ethernet ens160
ens224 c1c42f97-fcd6-3c02-9bd0-55b9fd924fe8 ethernet ens224
br-d12a67195c76 9b37912d-12cf-492c-bada-b9e66647ed62 bridge br-d12a67195c76
lo 5605fb5c-0551-45ba-8154-ed65cbe9f646 loopback lo
docker0 93814bc6-ad85-4fe2-8457-778cb279e74c bridge docker0
nmcli c m ens224 ipv4.method manual ipv4.addresses
192.168.10.20/24 ipv4.dns "223.5.5.5 8.8.8.8" ipv4.gateway 192.168.10.200
connection.autoconnect yes && nmcli c up ens224
[root@harbor ~]# tail -2 /etc/hosts
#192.168.64.134 hb.reg.com harbor
192.168.10.20 hb.reg.com harbor
2.创建个人镜像
运行nginx容器改首页即可,再把容器导出为新镜像,再推送到私人仓库
bash
[root@harbor ~]# docker run --name myapp -d nginx:1.28.1
61f1b48a6ad6880d3965b417bc603c40af42a8bdca76c25320c79ae97fe3cdc0
[root@harbor ~]#
[root@harbor ~]#
[root@harbor ~]# docker ps | grep myapp
61f1b48a6ad6 nginx:1.28.1 "/docker-entrypoint...." 11 seconds ago Up 10 seconds 80/tcp myapp
[root@harbor ~]#
[root@harbor ~]# docker exec -it myapp /bin/bash
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# ls /usr/share/
X11 ca-certificates doc-base gdb lintian nginx tabset
apt common-licenses dpkg info locale pam terminfo
base-files debconf fish java man pam-configs util-linux
base-passwd debianutils fontconfig keyrings maven-repo perl5 xml
bash-completion dict fonts libc-bin menu pixmaps zoneinfo
bug doc gcc libgcrypt20 misc polkit-1 zsh
root@61f1b48a6ad6:/# ls /usr/share/nginx/html/
50x.html index.html
root@61f1b48a6ad6:/# echo "myapp | version:1.0 "> /usr/share/nginx/html/index.html
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# cat /usr/share/nginx/html/index.html
myapp | version:1.0
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# curl localhost
myapp | version:1.0
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# exit
exit
bash
步骤1:将容器提交为新镜像
docker commit myapp myapp:1.0
#此时本地已经有改镜像
步骤2:标记镜像(准备推送到Harbor)
docker tag myapp:1.0 hb.reg.com/library/myapp:1.0
步骤3:登录Harbor仓库
docker login -u admin -p Harbor12345 hb.reg.com
步骤4:推送镜像到Harbor
docker push hb.reg.com/library/myapp:1.0
步骤5:验证推送结果
同理再创建并推送两个myapp镜像
bash
[root@harbor ~]# docker exec -it myapp /bin/bash
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# echo "myapp | version:2.0 "> /usr/share/nginx/html/index.html
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# exit
exit
[root@harbor ~]# docker commit myapp myapp:2.0
sha256:90369ca73ddca863389f8c8eb807b5a70a02d2b116128c40333708450ba5396e
[root@harbor ~]# docker tag myapp:2.0 hb.reg.com/library/myapp:2.0
[root@harbor ~]# docker push hb.reg.com/library/myapp:2.0
[root@harbor ~]# docker exec -it myapp /bin/bash
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# echo "myapp | version:3.0 "> /usr/share/nginx/html/index.html
root@61f1b48a6ad6:/#
root@61f1b48a6ad6:/# exit
exit
[root@harbor ~]# docker commit myapp myapp:3.0
sha256:f6c50086974e54fa45f61f6f531fac4da54e13bdff9e0cac9a273beb3d08f739
[root@harbor ~]#
[root@harbor ~]# docker tag myapp:3.0 hb.reg.com/library/myapp:3.0
[root@harbor ~]#
[root@harbor ~]# docker push hb.reg.com/library/myapp:3.0
结果:

k8s集群
环境初始化&准备
克隆3台虚拟机。
条件包括:
已经关闭防火墙/selinux,搭建好本地仓库,安装好常用软件。
并且开启路由转发。
两张网卡(仅主机/NAT),并提前查看仅主机模式的网卡的网段。
关闭交换分区
可以做完这些再克隆。
再每太主机分别:
5.改主机名
- 改ip信息(特别注意网关改为ikuai主机的内网ip)
- 关闭NAT模式的网卡。暂时关闭NAT模式网卡,以防止安装集群时出现绑定网卡错误的问题。
- 配置主机映射(没有做harbor的就不用写harbor)
1.k8s-master
Node1和Node2同理。改IP相关配置,主机名,暂时关闭NAT网卡
bash
hostnamectl hostname k8s-master01 && bash
#改网卡名
nmcli c m Wired\ connection\ 1 connection.id ens224
nmcli c m ens224 ipv4.method manual ipv4.addresses 192.168.10.11/24 ipv4.dns "223.5.5.5 8.8.8.8" ipv4.gateway 192.168.10.200 connection.autoconnect yes && nmcli c up ens224
暂时关闭NAT网卡,以防止安装集群时出现绑定网卡错误的问题。
bash
ls /etc/NetworkManager/system-connections/
nmcli c m ens160 connection.autoconnect no && nmcli c up ens160
配置主机映射
bash
cat >> /etc/hosts <<EOF
192.168.10.11 k8s-master01 m1
192.168.10.12 k8s-node01 n1
192.168.10.13 k8s-node02 n2
192.168.10.20 hb.registry.com harbor
EOF
2.node1 & node2
bash
hostnamectl hostname k8s-node1 && bash
nmcli c m Wired\ connection\ 1 connection.id ens224
nmcli c m ens224 ipv4.method manual ipv4.addresses 192.168.10.12/24 ipv4.dns "223.5.5.5 8.8.8.8" ipv4.gateway 192.168.10.200 connection.autoconnect yes && nmcli c up ens224
nmcli c m ens160 connection.autoconnect no && nmcli c up ens160
hostnamectl hostname k8s-node1 && bash
nmcli c m Wired\ connection\ 1 connection.id ens224
nmcli c m ens160 ipv4.method manual ipv4.addresses
192.168.10.13/24 ipv4.dns "223.5.5.5 8.8.8.8" ipv4.gateway 192.168.10.200
connection.autoconnect yes && nmcli c up ens160
nmcli c m ens160 connection.autoconnect no && nmcli c up ens160
主机映射同上
上面做了k8s三个节点的的基本网络设置(IP,网卡,防火墙等等)
搭建k8s集群
不知道大家有没有困惑:为什么要下载cri-dockerd,为什么要下载containerd?选择containerd作为容器运行时为什么要单独下载runc& cni-plugin,而如果cri-dockerd不用?
在阅读官网和别人的博客时,总是有很多额外的东西要自己去搞定,而这些东西很容易失败。
所以:我想在搭建k8s集群前,先了解这个集群的运行机制,底层原理。知道为什么需要单独去安装这些!!!
如果你赶时间,可以跳过这部分,直接到:正式安装&部署部分
一些相关知识点
eg.我们现在搭建一个简单的k8s集群:1master,2node。其中master是管理节点,node是工作节点。
Master /Node节点功能
Master 节点 (控制平面)
- API Server:所有请求的唯一入口,类似"前台/网关"
- etcd:存储集群状态(Pod在哪、配置、Secret等)
- Scheduler:决定新Pod放到哪个Node
- Controller Manager:运行各种控制器(如Deployment控制器、Node控制器)
Node 节点
- kubelet:Node的"管家",负责Pod生命周期,与Master通信
- kube-proxy:负责Service的网络规则(iptables/IPVS)
- CRI (容器运行时):真正拉镜像、启停容器。如 containerd、CRI‑dockerd

当我们要运行一个pod实例时,比如创建一个yaml文档去创建这个pod。
YAML → kubectl POST → API Server 存 etcd → Scheduler 设 nodeName → kubelet watch 到 → kubelet 调用 CRI 拉镜像+建 pause+启容器 → kubelet 更新状态为 Running
text
┌─────────────────────────────────────────────┐
│ MASTER 节点 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │API Server│ │ etcd │ │Scheduler│ │
│ │接收请求 │ │存Pod对象│ │分配节点 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────┬──────────────────────────┘
│ watch & 回写
↓
┌─────────────────────────────────────────────┐
│ NODE 节点 (node1) │
│ ┌──────────────────────────────────────┐ │
│ │ kubelet │ │
│ │ 1. 发现 Pod 分配给自己 │ │
│ │ 2. 调用 CRI 拉镜像/创建容器/启停 │ │
│ │ 3. 调用 CNI 配网络 │ │
│ │ 4. 回写状态 │ │
│ └──────────────────────────────────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ pause │ ←共享NS→ │ nginx │ │
│ │(沙盒容器)│ │(业务容器)│ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────┘
我们可以发现node节点:2. 调用 CRI 拉镜像/创建容器/启停,这里的CRI就是容器运行时。
容器运行时的选择&准备
目前比较常用的容器运行时就是Docker Engine (通过 cri-dockerd)和containerd。
选择哪种其实我们要根据实际情况!!!
其实k8s集群管理就是:要么是通过k8s管理编排docker 容器,或者是 containerd 容器(和 docker 无关了)。
++现在k8s官方推荐的是containerd ,但是大多数人学习过程都是docker->k8s。从有docker环境开始入手会更平滑。++
生产环境是否继续用 Docker,取决于业务对 docker 命令和工具的依赖程度。
1.选择Docker Engine
第一种,肯定每一个节点都是要有docker环境的,这里我们可以不用太管docker所需的组件,docker比较集成,安装好docker后,这些组件已经ok了。
只需要安装cri-dockerd 作为容器运行时的适配器。
这里需要先明确一点:
cri-dockerd本身不是一个容器运行时,它只是一个适配器。它的作用是让Kubernetes可以通过标准的CRI(容器运行时接口)来调用传统的Docker Engine。
再安装**kubelet, kubectl(master必须,node可略), kubeadm**(一些组件依赖其来自动安装)
2.选择containerd
第二种,则需要准备的部分有:containerd,runc, cni-plugin
再安装**kubelet, kubectl(master必须,node可略), kubeadm**(一些组件依赖其来自动安装)
由组件决定安装什么
今天我们先介绍第一种。从组件的角度来部署安装。
先了解各节点到底需要什么!!!由上面Master /Node节点功能可知不同节点需要的组件也不同。
Master 节点
组件 如何获得 kube-apiserver、etcd、kube-scheduler、kube-controller-manager kubeadm 自动安装 kubectl yum/apt 安装 kubelet yum/apt 安装 kubeadm yum/apt 安装 需要安装kubeadm,kubectl,kubelet
Node 节点
组件 如何获得 kube-proxy kubeadm 自动安装 Docker + cri-dockerd 手动安装 kubelet yum/apt 安装 kubeadm yum/apt 安装 需要安装kubeadm,kubelet,Docker + cri-dockerd
注意:纯 Master(不跑 Pod)可以不装 Docker + cri-dockerd。但本文档的 Master 会运行 Calico等系统 Pod,所以也需要安装。
为了方便,最后我们决定所有节点都先安装docker环境后,再安装cri-dockerd,再安装kubelet,kubeadm,kubectl。
正式安装&部署
1.安装docker环境
1.1添加dock5er源
bash
yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/rhel/docker-ce.repo
可以检查一下
bash
[root@k8s-master01 ~]# dnf repolist
repo id repo name
AppStream AppStream
BaseOS BaseOS
docker-ce-stable Docker CE Stable - x86_64
#其它节点一样
1.2安装docker
bash
yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
1.3配置docker
配置了 Docker 的数据目录、日志限制、cgroup 驱动、私有仓库支持和镜像加速器,目的是让 Docker 在 K8s 集群环境下稳定、高效、合规地运行。
bash
cat > /etc/docker/daemon.json <<EOF
{
"default-ipc-mode": "shareable",
"data-root": "/data/docker",
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "50"
},
"insecure-registries": ["https://harbor.registry.com"],
"registry-mirrors":[
"https://docker.m.daocloud.io",
"https://docker.imgdb.de",
"https://docker-0.unsee.tech",
"https://docker.hlmirror.com",
"https://docker.1ms.run",
"https://func.ink",
"https://lispy.org",
"https://docker.xiaogenban1993.com"
]
}
EOF
详细解释:
配置项 值 作用 default-ipc-mode"shareable"允许容器共享 IPC 命名空间(Pod 内多容器通信需要) data-root"/data/docker"修改 Docker 数据存储目录(默认 /var/lib/docker),避免根分区占满exec-opts["native.cgroupdriver=systemd"]关键配置:让 Docker 使用 systemd 作为 cgroup 驱动,与 kubelet 保持一致 log-driver"json-file"日志驱动类型(Docker 默认) log-optsmax-size: 100mmax-file: 50每个容器日志文件最大 100MB,最多保留 50 个文件,防止日志暴涨 insecure-registries["https://hb.registry.com"]允许访问的私有镜像仓库(跳过 HTTPS 证书验证) registry-mirrors8 个国内加速器地址 拉取镜像时优先从这些镜像站下载,解决 registry.k8s.io、docker.io访问慢/被墙问题
1.4启动docker
bash
systemctl enable --now docker
1.5验证docker
bash
docker --version
结果:Docker version 29.5.2, build 79eb04c
docker info
结果:略
2.安装CRI
CRI 为容器运行时,常见的有 cri-docker 和 containerd,两者任选其一安装即可,不要两者都安装。
这里我们是选择 cri-docker,能够去兼容docker环境
2.1.下载cri-docker
bash
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.17/cri-dockerd-0.3.17.amd64.tgz
比较慢,可以在一台机器下载再传输给另外两台
bash
scp cri-dockerd-0.3.17.amd64.tgz n1:~
scp cri-dockerd-0.3.17.amd64.tgz n2:~
2.2解压
bash
tar -xf cri-dockerd-0.3.17.amd64.tgz
2.3将解压文件复制到可执行目录下
bash
cp cri-dockerd/cri-dockerd /usr/bin/
2.4设置文件可执行权限
bash
chmod +x /usr/bin/cri-dockerd
2.5配置cri-docker服务
目的是:让
kubelet能够通过cri-dockerd适配器,使用pause:3.10镜像作为每个 Pod 的"基础沙箱"来管理 Docker 容器。简单来说,它就是打通 Kubernetes 与 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/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.10
#ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=registry.k8s.io/pause:3.10
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
2.6 配置cri-docker套接字
为
cri-dockerd创建一个监听套接字(socket),让kubelet能通过这个 socket 与cri-dockerd通信,并支持按需启动服务。
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
2.7启动cri-docker服务
bash
systemctl daemon-reload
systemctl enable --now cri-docker
systemctl is-active cri-docker#检验
3.安装kubernete&初始化集群
3.1添加kubenete源
bash
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/rpm/repodata/repomd.xml.key
EOF
3.2安装kubenete
kubelet kubeadm kubectl
bash
dnf install -y kubelet kubeadm kubectl
3.3启动kubelet服务
bash
systemctl enable --now kubelet
3.4验证安装
bash
kubeadm version
结果:kubeadm version: &version.Info{Major:"1", Minor:"33", EmulationMajor:"", EmulationMinor:"", MinCompatibilityMajor:"", MinCompatibilityMinor:"", GitVersion:"v1.33.12", GitCommit:"1f348c8e82cf0f170df4ac2b1e859ea0d398ff09", GitTreeState:"clean", BuildDate:"2026-05-12T09:45:31Z", GoVersion:"go1.25.9", Compiler:"gc", Platform:"linux/amd64"}
3.5 查看所需镜像
主节点需要导入全部镜像,从节点只需导入 kube-proxy、coredns、pause 这三个镜像。
bash
kubeadm config images list
结果:
registry.k8s.io/kube-apiserver:v1.33.12
registry.k8s.io/kube-controller-manager:v1.33.12
registry.k8s.io/kube-scheduler:v1.33.12
registry.k8s.io/kube-proxy:v1.33.12
registry.k8s.io/coredns/coredns:v1.12.0
registry.k8s.io/pause:3.10
registry.k8s.io/etcd:3.5.24-0
可以看出:kubeadm 支持 v1.33.12 版本
3.6初始化节点
此操作只需要在 k8s-master01 节点上执行。
先拉取镜像,否则初始化很慢,且极有可能不成功
bash
[root@k8s-master01 ~]# kubeadm config images pull \
--kubernetes-version=v1.33.12 \
--image-repository=registry.aliyuncs.com/google_containers \
--cri-socket unix:///var/run/cri-dockerd.sock
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-apiserver:v1.33.12
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-controller-manager:v1.33.12
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-scheduler:v1.33.12
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-proxy:v1.33.12
[config/images] Pulled registry.aliyuncs.com/google_containers/coredns:v1.12.0
[config/images] Pulled registry.aliyuncs.com/google_containers/pause:3.10
[config/images] Pulled registry.aliyuncs.com/google_containers/etcd:3.5.24-0
[root@k8s-master01 ~]#
初始化(master上执行)
bash
kubeadm init --apiserver-advertise-address=192.168.10.11 \
--image-repository=registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.33.12 \
--service-cidr=10.10.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--ignore-preflight-errors=all \
--cri-socket unix:///var/run/cri-dockerd.sock
命令解析如下:
--apiserver-advertise-address=192.168.10.11:指定主服务器的地是多少,也就是 master
主机的地址
--image-repository:指定控制平面镜像的仓库地址(默认 registry.k8s.io),当前为阿里镜
像仓库地址,也可指向自己的私有镜像仓库地址如my-registry.com/k8s
--kubernetes-version=v1.33.12:因为 kubeadm 版本是 v1.33.12 ,所以
--kubernetes-version必须指定为 v1.33.12--service-cidr=10.10.0.0/12:指定service资源的网络范围
--pod-network-cidr=10.244.0.0/16:指定pos的网络范围
--ignore-preflight-errors=all:跳过所有前置的错误检测
--cri-socket unix:///var/run/cri-dockerd.sock:指定 CRI(容器运行时)的 socket 路径,如
果是containerd则为unix:///run/containerd/containerd.sock
初始化信息
bash
[init] Using Kubernetes version: v1.33.12
[preflight] Running pre-flight checks
[WARNING Mem]: the system RAM (1673 MB) is less than the minimum 1700 MB
[WARNING Port-6443]: Port 6443 is in use
[WARNING Port-10259]: Port 10259 is in use
[WARNING Port-10257]: Port 10257 is in use
[WARNING FileAvailable--etc-kubernetes-manifests-kube-apiserver.yaml]: /etc/kubernetes/manifests/kube-apiserver.yaml already exists
[WARNING FileAvailable--etc-kubernetes-manifests-kube-controller-manager.yaml]: /etc/kubernetes/manifests/kube-controller-manager.yaml already exists
[WARNING FileAvailable--etc-kubernetes-manifests-kube-scheduler.yaml]: /etc/kubernetes/manifests/kube-scheduler.yaml already exists
[WARNING FileAvailable--etc-kubernetes-manifests-etcd.yaml]: /etc/kubernetes/manifests/etcd.yaml already exists
[WARNING Port-10250]: Port 10250 is in use
[WARNING Port-2379]: Port 2379 is in use
[WARNING Port-2380]: Port 2380 is in use
[WARNING DirAvailable--var-lib-etcd]: /var/lib/etcd is not empty
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Using existing ca certificate authority
[certs] Using existing apiserver certificate and key on disk
[certs] Using existing apiserver-kubelet-client certificate and key on disk
[certs] Using existing front-proxy-ca certificate authority
[certs] Using existing front-proxy-client certificate and key on disk
[certs] Using existing etcd/ca certificate authority
[certs] Using existing etcd/server certificate and key on disk
[certs] Using existing etcd/peer certificate and key on disk
[certs] Using existing etcd/healthcheck-client certificate and key on disk
[certs] Using existing apiserver-etcd-client certificate and key on disk
[certs] Using the existing "sa" key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/admin.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/super-admin.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Using existing kubeconfig file: "/etc/kubernetes/scheduler.conf"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests"
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 502.255841ms
[control-plane-check] Waiting for healthy control plane components. This can take up to 4m0s
[control-plane-check] Checking kube-apiserver at https://192.168.10.11:6443/livez
[control-plane-check] Checking kube-controller-manager at https://127.0.0.1:10257/healthz
[control-plane-check] Checking kube-scheduler at https://127.0.0.1:10259/livez
[control-plane-check] kube-apiserver is healthy after 3.006452ms
[control-plane-check] kube-controller-manager is healthy after 3.026871ms
[control-plane-check] kube-scheduler is healthy after 4.116445ms
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8s-master01 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node k8s-master01 as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: ma44bu.m6ku932h1b9yrmap
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Configured RBAC rules to allow the API server kubelet client certificate to access the kubelet API
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.10.11:6443 --token ma44bu.m6ku932h1b9yrmap \
--discovery-token-ca-cert-hash sha256:4d4dea5b8ca94a671d5115fdfd6237df2cb1f485f1492e8f6a801c3f0191b7e4
3.7创建.kube目录
bash
[root@k8s-master01 ~]# mkdir -p $HOME/.kube
[root@k8s-master01 ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master01 ~]# chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane 5m31s v1.33.12
3.8 增加工作节点
bash
kubeadm join 192.168.10.11:6443 --token ma44bu.m6ku932h1b9yrmap \
--discovery-token-ca-cert-hash sha256:4d4dea5b8ca94a671d5115fdfd6237df2cb1f485f1492e8f6a801c3f0191b7e4 \
--cri-socket unix:///var/run/cri-dockerd.sock
如果不加--cri-socket会冲突。kubeadm 发现系统里有 两个 可用的容器运行时(
containerd和cri-dockerd),不知道该用哪个来创建容器,所以就报错停止了。虽然没有主动安装
containerd,它是在你之前执行安装 Docker 的命令时,作为依赖包被自动安装进来的
Tips:
如果这里加入不成功,在再次尝试前要先删掉之前的一些残留
bash
# 1. 彻底清理之前的 Kubernetes 痕迹
kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock -f
# 2. 删除残留文件(可选,reset 应该已经清理)
rm -rf /etc/kubernetes/
rm -rf /var/lib/kubelet/
rm -rf ~/.kube/
# 3. 重启 kubelet
systemctl restart kubelet
# 4. 重新执行 join 命令
kubeadm join 192.168.10.11:6443 \
--token ma44bu.m6ku932h1b9yrmap \
--discovery-token-ca-cert-hash sha256:4d4dea5b8ca94a671d5115fdfd6237df2cb1f485f1492e8f6a801c3f0191b7e4 \
--cri-socket unix:///var/run/cri-dockerd.sock
3.9查看集群状态
bash
[root@k8s-master01 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane 26m v1.33.12
k8s-node1 NotReady <none> 7m55s v1.33.12
k8s-node2 NotReady <none> 6s v1.33.12
4.部署网络插件
Kubernetes 集群如果要能够正常工作,所有容器都必须工作在一个扁平的网络空间中。
接下来我们就需要部署网络插件来实现这个扁平化网络空间,让 Kubernetes 集群可以正常工作。
官网可看:

选择第2个。按照上面的步骤。
4.1 下载配置文件
bash
curl https://raw.githubusercontent.com/projectcalico/calico/v3.30.7/manifests/calico-typha.yaml -o calico.yaml
[root@k8s-master01 ~]# grep image* calico.yaml
image: docker.io/calico/cni:v3.30.7
imagePullPolicy: IfNotPresent
image: docker.io/calico/cni:v3.30.7
imagePullPolicy: IfNotPresent
image: docker.io/calico/node:v3.30.7
imagePullPolicy: IfNotPresent
image: docker.io/calico/node:v3.30.7
imagePullPolicy: IfNotPresent
image: docker.io/calico/kube-controllers:v3.30.7
imagePullPolicy: IfNotPresent
- image: docker.io/calico/typha:v3.30.7
imagePullPolicy: IfNotPresent
[root@k8s-master01 ~]#
4.2修改配置文件calico.yaml
bash
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
value: "Off"
# Enable or Disable VXLAN on the default IP pool.
- name: CALICO_IPV4POOL_VXLAN
value: "Never"
# Enable or Disable VXLAN on the default IPv6 IP pool.
- name: CALICO_IPV6POOL_VXLAN
value: "Never"
。。。。。。
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
1.将 CALICO_IPV4POOL_IPIP 和CALICO_IPV4POOL_VXLAN 都关闭,即使用 BGP 模式。
2.CALICO_IPV4POOL_CIDR 修改为初始集群时指定的 Pod 地址,即 --pod
network-cidr=10.244.0.0/16 参数所指定的地址。
4.3安装网络插件
bash
kubectl apply -f calico.yaml
4.4查看集群状态
bash
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready control-plane 42m v1.33.12
k8s-node1 Ready <none> 24m v1.33.12
k8s-node2 Ready <none> 16m v1.33.12
[root@k8s-master01 ~]# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master01 Ready control-plane 43m v1.33.12 192.168.10.11 <none> Red Hat Enterprise Linux 10.1 (Coughlan) 6.12.0-124.8.1.el10_1.x86_64 docker://29.5.2
k8s-node1 Ready <none> 24m v1.33.12 192.168.10.12 <none> Red Hat Enterprise Linux 10.1 (Coughlan) 6.12.0-124.8.1.el10_1.x86_64 docker://29.5.2
k8s-node2 Ready <none> 17m v1.33.12 192.168.10.13 <none> Red Hat Enterprise Linux 10.1 (Coughlan) 6.12.0-124.8.1.el10_1.x86_64 docker://29.5.2
查看所有命名空间的 Pod
bash
[root@k8s-master01 ~]# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-75545bc648-6xhb9 1/1 Running 0 9m10s
kube-system calico-node-6drsp 1/1 Running 0 9m10s
kube-system calico-node-fw9gj 1/1 Running 0 9m10s
kube-system calico-node-ww6s5 1/1 Running 0 9m10s
kube-system calico-typha-79c48599db-7rhp5 1/1 Running 0 9m10s
kube-system coredns-757cc6c8f8-r7xw9 1/1 Running 0 39m
kube-system coredns-757cc6c8f8-wrljm 1/1 Running 0 39m
kube-system etcd-k8s-master01 1/1 Running 0 42m
kube-system kube-apiserver-k8s-master01 1/1 Running 0 42m
kube-system kube-controller-manager-k8s-master01 1/1 Running 0 42m
kube-system kube-proxy-lb44f 1/1 Running 0 39m
kube-system kube-proxy-m5z8c 1/1 Running 0 24m
kube-system kube-proxy-phdxn 1/1 Running 0 16m
kube-system kube-scheduler-k8s-master01 1/1 Running 0 42m
查看指定命名空间(kube-system)
bash
[root@k8s-master01 ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-75545bc648-6xhb9 1/1 Running 0 9m19s
calico-node-6drsp 1/1 Running 0 9m19s
calico-node-fw9gj 1/1 Running 0 9m19s
calico-node-ww6s5 1/1 Running 0 9m19s
calico-typha-79c48599db-7rhp5 1/1 Running 0 9m19s
coredns-757cc6c8f8-r7xw9 1/1 Running 0 39m
coredns-757cc6c8f8-wrljm 1/1 Running 0 39m
etcd-k8s-master01 1/1 Running 0 42m
kube-apiserver-k8s-master01 1/1 Running 0 42m
kube-controller-manager-k8s-master01 1/1 Running 0 42m
kube-proxy-lb44f 1/1 Running 0 39m
kube-proxy-m5z8c 1/1 Running 0 24m
kube-proxy-phdxn 1/1 Running 0 16m
kube-scheduler-k8s-master01 1/1 Running 0 42m
Kubernetes 集群已经完全正常运行!
所有系统组件都是
Running状态:
- Calico 网络插件(CNI)
calico-node-xxx(3个):每个节点一个,负责网络连通性calico-kube-controllers:Calico 的控制器,管理网络策略calico-typha:Calico 的代理,减少 API 负载
- CoreDNS(DNS 服务)
coredns-xxx(2个):为集群提供 DNS 解析服务,让 Pod 之间可以通过服务名通信
- Kubernetes 核心组件(仅在 master 节点)
kube-apiserver:API 服务器,集群的入口kube-controller-manager:控制器管理器,管理各种控制器kube-scheduler:调度器,负责将 Pod 分配到节点etcd:集群的数据库,存储所有配置和状态kube-proxy(3个):每个节点一个,负责网络代理和负载均衡
Tips:
如果**kubectl apply -f calico.yaml安装失败,多半是镜像拉取失败**
1.上传镜像文件
由于 calico 镜像在国内很难下载,因此我已经提前将所需要的镜像下载好
通过网盘分享的文件:calico-images-v3.30.2.tar 和calico.yaml
链接: https://pan.baidu.com/s/122ubjrO8CotnXCl7NJ4vAw?pwd=zlpz 提取码: zlpz
2.导入镜像文件
bash
tar -xvf calico-v3.30.2.tar
cni:v3.30.2.tar.gz
kube-controllers:v3.30.2.tar.gz
node:v3.30.2.tar.gz
typha:v3.30.2.tar.gz
docker load -i xxx#导入上面解压的4个到3个节点
3.安装网络插件
bash
#先下载
curl https://raw.githubusercontent.com/projectcalico/calico/v3.30.2/manifests/calico-typha.yaml -o calico.yaml
#再安装
kubectl apply -f calico.yaml
应该就OK了。
简单测试:创建一个pod
bash
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 62m
[root@k8s-master01 ~]#
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl expose deployment nginx --port=80 --type=NodePort
service/nginx exposed
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 62m
nginx NodePort 10.1.229.182 <none> 80:31568/TCP 5s
[root@k8s-master01 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5869d7778c-26mlm 1/1 Running 0 24s
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready control-plane 63m v1.33.12
k8s-node1 Ready <none> 44m v1.33.12
k8s-node2 Ready <none> 37m v1.33.12
[root@k8s-master01 ~]#
#通过集群内部地址访问
[root@k8s-master01 ~]# curl http://10.1.229.182:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, nginx is successfully installed and working.
Further configuration is required for the web server, reverse proxy,
API gateway, load balancer, content cache, or other features.</p>
<p>For online documentation and support please refer to
<a href="https://nginx.org/">nginx.org</a>.<br/>
To engage with the community please visit
<a href="https://community.nginx.org/">community.nginx.org</a>.<br/>
For enterprise grade support, professional services, additional
security features and capabilities please refer to
<a href="https://f5.com/nginx">f5.com/nginx</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
在查看nginx容器在哪个节点
bash
[root@k8s-master01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-5869d7778c-26mlm 1/1 Running 0 9m45s 10.244.36.64 k8s-node1 <none> <none>
[root@k8s-node1 ~]# docker ps | grep nginx
2c5f23018cf7 5aca99593157 "/docker-entrypoint...." 7 minutes ago Up 7 minutes k8s_nginx_nginx-5869d7778c-26mlm_default_1504b5a4-ff13-4a77-9076-8109391a9d24_0
36edf5fe5c6b registry.aliyuncs.com/google_containers/pause:3.10 "/pause" 7 minutes ago Up 7 minutes k8s_POD_nginx-5869d7778c-26mlm_default_1504b5a4-ff13-4a77-9076-8109391a9d24_0