(一)线程是什么
本文来研究一下k8s的安装。
# 1、3 台虚拟机的硬件资源规划
K8s 的核心组件(尤其是 Master 节点上的 etcd 和 kube-apiserver)对硬件有硬性要求。我用 VMware工具 虚拟出以下三台机器:
| 虚拟机角色 | 主机名(Hostname) | CPU 最低要求 | IP | 作用 |
|---|---|---|---|---|
| Master 节点 | k8s-master | 2C+4GB 20GB | 192.168.1.50 | 集群的大脑,负责控制、调度和存储状态(etcd) |
| Worker 节点 1 | k8s-node1 | 2C+2GB 20GB | 192.168.1.51 | 负责运行具体的业务 Pod |
| Worker 节点 2 | k8s-node2 | 2C+2GB 20GB | 192.168.1.52 | 负责运行具体的业务 Pod |
机器均是 Centos 8 版本
# 2、🛠️ 第一阶段:所有节点执行
💡 **操作提示:(Master 和 2 个 Worker)的初始化准备工作,三台机器都要执行,**你也可以先在第一台机器安装好,通过 VMware 克隆。(注意改主机名称)
# 1. 修复 CentOS 8 软件源(核心避坑)
# 替换过期的官方向导源为阿里云 Vault 历史镜像源
cat <<EOF | sudo tee /etc/yum.repos.d/CentOS-Linux-BaseOS.repo
[baseos]
name=CentOS Linux \$releasever - BaseOS - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos-vault/8.5.2111/BaseOS/x86_64/os/
gpgcheck=0
enabled=1
EOF
cat <<EOF | sudo tee /etc/yum.repos.d/CentOS-Linux-AppStream.repo
[appstream]
name=CentOS Linux \$releasever - AppStream - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos-vault/8.5.2111/AppStream/x86_64/os/
gpgcheck=0
enabled=1
EOF
# 清理并重建缓存
yum clean all && yum makecache
# 2. 关闭妨碍 K8s 运行的系统组件
K8s 需要对内存、网络和权限进行接管,所以必须关闭系统的防火墙、SELinux 和 Swap 交换分区。
# 1. 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 2. 禁用 SELinux(临时+永久)
setenforce 0
sed -i 's/enforcing/disabled/g' /etc/selinux/config
# 3. 关闭 Swap 分区(面试常考点,保证容器性能可控)
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 3. 配置内核转发参数与网桥过滤
K8s 容器之间需要跨主机通信,必须开启 Linux 内核的 IPv4 转发,并让 iptables 能够过滤网桥流量。
# 加载内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# 配置内核参数
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# 立即应用内核参数
sudo sysctl --system
# 4. 安装 Containerd 容器运行时(CRI 标准)
我们在这里配置 Systemd cgroup 驱动,这是 K8s 生产环境稳定运行的关键。
# 安装基础依赖与 Docker 官方源(Containerd 在这里面)
yum install -y yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装 containerd
yum install -y containerd.io
# 生成默认配置并修改
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 修改 SystemdCgroup 为 true,并将默认沙箱镜像(Pause 容器)切到国内阿里云源
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
sed -i 's|registry.k8s.io/pause:3.8|registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9|g' /etc/containerd/config.toml
# 启动并开机自启
systemctl daemon-reload
systemctl restart containerd
systemctl enable containerd
# 5. 安装 K8s 三剑客:kubelet、kubeadm、kubectl
# 添加阿里云 K8s 软件源
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseos=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF
# 安装指定稳定版本(这里以 v1.28.2 为例,稳定且避开了早期版本的坑)
yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2
# 设置开机自启(此时不要主动 start,等后面初始化自动拉起)
systemctl enable kubelet
# 3、🚀 第二阶段:Master 节点初始化
(仅在 k8s-master 上运行)
kubeadm init \
--apiserver-advertise-address=192.168.1.50 \
--image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers \
--kubernetes-version=v1.28.2 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
--apiserver-advertise-address=192.168.1.50 你的Master节点内网IP
--pod-network-cidr=10.244.0.0/16 是为接下来的 Flannel 网络插件 预留的虚拟网段。
执行该命令时,kubeadm 会通过 Containerd 去阿里云拉取 kube-apiserver、kube-controller-manager、kube-scheduler 和 etcd 的镜像,并将它们作为 Static Pod(静态 Pod) 跑在本地。
这一步可能会遇到不少错误
你可以使用下面的命令查看日志:
journalctl -xeu kubelet --no-pager
# 网络问题
6月 13 05:00:52 yudianxx kubelet[10481]: E0613 05:00:52.338669 10481 kuberuntime_sandbox.go:72] "Failed to create sandbox for pod" err="rpc error: code = DeadlineExceeded desc = failed to get sandbox image \"registry.k8s.io/pause:3.6\": failed to pull image \"registry.k8s.io/pause:3.6\": failed to pull and unpack image \"registry.k8s.io/pause:3.6\": failed to resolve reference \"registry.k8s.io/pause:3.6\": failed to do request: Head \"https://asia-east1-docker.pkg.dev/v2/k8s-artifacts-prod/images/pause/manifests/3.6\": dial tcp [2404:6800:4008:c15::52]:443: i/o timeout" pod="kube-system/kube-apiserver-yudianxx"
修改镜像地址:
# 1. 备份原有的配置文件防止改错
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
# 2. 强行重写一份完整的、已经配好国内镜像代理和 SystemdCgroup 的完美版 config.toml
cat << 'EOF' > /etc/containerd/config.toml
disabled_plugins = []
imports = []
oom_score = 0
plugin_dir = ""
required_plugins = []
root = "/var/lib/containerd"
state = "/run/containerd"
version = 2
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9"
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = ""
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
# 当容器运行时去找 registry.k8s.io 时,强行重定向到国内阿里云镜像源!
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://registry.cn-hangzhou.aliyuncs.com/google_containers"]
# 顺便把普通的 docker.io 也重定向到国内网易和中科大源,防止后续拉业务镜像被墙
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://hub-mirror.c.163.com", "https://docker.mirrors.ustc.edu.cn"]
EOF
# 3、重启 Containerd 刷新引擎
systemctl daemon-reload
systemctl restart containerd
修改后重新执行初始化命令。
# 成功运行
初始化成功后在终端末尾会输出一段日志:
[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.1.50:6443 --token o9kd9q.f9gqij4ku48rw8kc \
--discovery-token-ca-cert-hash sha256:16892988d4aedfd135315fda8892362758273f41774c1cbb03816048d39631d3
终端最后会生成一行极具价值的加入命令(kubeadm join ...),我们把它复制下来。
kubeadm join 192.168.1.50:6443 --token o9kd9q.f9gqij4ku48rw8kc \
--discovery-token-ca-cert-hash sha256:16892988d4aedfd135315fda8892362758273f41774c1cbb03816048d39631d3
请把这行命令完整复制并保存下来。
随后组件etcd、kube-apiserver、kube-scheduler、kube-controller-manager 就会被拉起:
[root@yudianxx ~]# crictl ps -a
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
0c20cf868d863 7a5d9d67a13f6 10 seconds ago Running kube-scheduler 0 348e3e62d3538 kube-scheduler-yudianxx
48103438775a4 73deb9a3f7025 10 seconds ago Running etcd 0 941148065f757 etcd-yudianxx
c4a68dcd3e6be 55f13c92defb1 10 seconds ago Running kube-controller-manager 1 05138a574a775 kube-controller-manager-yudianxx
8d911b893e104 cdcab12b2dd16 10 seconds ago Running kube-apiserver 0 5cc21550a8c8d kube-apiserver-yudianxx
# 🎉 初始化成功后的收尾工作
初始化成功后,终端会打印出一段提示。我们需要在 Master 上配置 kubectl 认证访问权限:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Kubernetes 集群安装完成后,管理员凭证文件
/etc/kubernetes/admin.conf保存着集群管理员权限、API 访问地址、证书密钥,只有 root 用户能读取。普通
root用户直接执行kubectl可以正常操作集群;但你用普通账号(哪怕带 sudo)执行 kubectl 会报错:找不到 kubeconfig、权限不足。下面两条命令就是把管理员权限配置拷贝到当前用户目录,让当前用户免 sudo 操作 kubectl。
# 4、👥 第三阶段:Worker 节点加入集群
⚠️ 注意: 接下来的操作只需在两台 Worker 虚拟机上分别执行。
把刚才在 Master 上生成的那行 kubeadm join 命令,直接粘贴进 两台 Worker 节点的终端里执行
把刚才在 Master 上生成的那行 kubeadm join 命令,直接粘贴进 Worker 节点的终端里执行:
kubeadm join 192.168.1.50:6443 --token o9kd9q.f9gqij4ku48rw8kc \
--discovery-token-ca-cert-hash sha256:16892988d4aedfd135315fda8892362758273f41774c1cbb03816048d39631d3
当看到终端输出 This node has joined the cluster 时,说明工人已经向大脑报到成功!
# 5、第四阶段:部署 CNI 网络插件(仅在 k8s-master 上运行)
此时,如果你在 Master 上运行 kubectl get nodes,你会发现节点的状态全都是 NotReady。
[root@yudianxx ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 108s v1.28.2
k8s-node2 Ready <none> 3s v1.28.2
yudianxx Ready control-plane 18m v1.28.2
我们在 Master 上一键部署最经典的 Flannel 网络组件:
在 Kubernetes 的世界里,Flannel 和 Calico 是两款最主流、市场占有率最高的 CNI(容器网络接口)插件。
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
等待 1~2 分钟,让镜像下载完毕并启动。
[root@yudianxx ~]# kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
[root@yudianxx ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 4m16s v1.28.2
k8s-node2 Ready <none> 2m31s v1.28.2
yudianxx Ready control-plane 20m v1.28.2
当你看到 3 台机器全部整整齐齐地变为 Ready 状态时,属于你自己的原生多节点 Kubernetes 集群就彻底宣告搭建成功了!
# k8s架构图
# 节点信息汇总
| 角色 | 主机名 | IP 地址 | 核心组件 |
|---|---|---|---|
| Master | yudianxx | 192.168.1.50 | kube-apiserver, etcd, kube-scheduler, kube-controller-manager, coredns(2个), kube-proxy |
| Worker-1 | k8s-node1 | 192.168.1.51 | kubelet, containerd, kube-proxy |
| Worker-2 | k8s-node2 | 192.168.1.52 | kubelet, containerd, kube-proxy |
# Master 节点组件
| 组件 | 作用 |
|---|---|
| kube-apiserver | 集群的统一入口,所有操作都通过它 |
| etcd | 分布式键值存储,保存所有集群数据 |
| kube-scheduler | 负责将 Pod 调度到合适的 Worker 节点 |
| kube-controller-manager | 运行各种控制器(节点、副本、端点等) |
| coredns | 集群内部 DNS 服务,用于服务发现 |
coredns
在 K8s 中,Pod 的 IP 是经常随着重启而改变的。为了让 Hermes 机器人能稳定连接到数据库,我们不能在代码里写死 IP,而是写死一个 K8s 内部域名(例如
mysql.default.svc.cluster.local)。每当容器发起网络请求时,它底层的 DNS 解析请求都会自动转发给这两个
coredns组件,由它们实时查阅 Etcd 保险箱,将域名精准翻译成当前最新的 Pod IP。它是 K8s 实现**分布式服务发现(Service Discovery)**的灵魂组件。”
# Worker 节点组件
| 组件 | 作用 |
|---|---|
| kubelet | 节点代理,负责管理 Pod 和容器 |
| containerd | 容器运行时,负责运行容器 |
| kube-proxy | 维护网络规则,实现服务负载均衡 |
来看下整个集群有哪些角色:
[root@yudianxx ~]# kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-6554b8b87f-smnx5 1/1 Running 0 4h12m 10.88.0.2 yudianxx <none> <none>
coredns-6554b8b87f-vnjvd 1/1 Running 0 4h12m 10.88.0.3 yudianxx <none> <none>
etcd-yudianxx 1/1 Running 0 4h12m 192.168.1.50 yudianxx <none> <none>
kube-apiserver-yudianxx 1/1 Running 0 4h12m 192.168.1.50 yudianxx <none> <none>
kube-controller-manager-yudianxx 1/1 Running 1 4h12m 192.168.1.50 yudianxx <none> <none>
kube-proxy-4f2kd 1/1 Running 0 3h54m 192.168.1.52 k8s-node2 <none> <none>
kube-proxy-5mkb5 1/1 Running 0 4h12m 192.168.1.50 yudianxx <none> <none>
kube-proxy-sknrl 1/1 Running 0 3h56m 192.168.1.51 k8s-node1 <none> <none>
kube-scheduler-yudianxx 1/1 Running 0 4h12m 192.168.1.50 yudianxx <none> <none>
架构图:
- 🟠 橙色(systemd 服务):这些是 Kubernetes 的“骨架”,必须直接在宿主机上运行。
kubelet是节点加入集群的“敲门砖”,containerd是运行容器的“发动机”。 - 🟢 绿色(Pod 服务):这些是 Kubernetes 的“血肉”,作为普通 Pod 被调度和管理。
kube-proxy虽然负责网络规则,但它本身就是一个 Pod;coredns为集群提供 DNS 服务,也运行在 Pod 中。这也验证了“Kubernetes 自身的组件也可以用 Kubernetes 来管理”的设计理念。
# 通信流程简述
- 用户或 Pod 通过
kube-apiserver发起请求 kube-scheduler监控未调度的 Pod,根据资源策略分配到合适的 Worker 节点- Worker 节点的
kubelet收到指令,通过containerd启动 Pod kube-proxy在各节点维护 iptables/IPVS 规则,实现服务访问- Pod 之间通过 CNI 网络通信,跨节点经过隧道或路由