CentOS 7 上部署 Kubernetes 1.20 集群:从系统初始化到生产级配置全指南

发布时间:2026/6/16 4:38:20
CentOS 7 上部署 Kubernetes 1.20 集群:从系统初始化到生产级配置全指南 1. 项目概述与环境准备最近在帮团队搭建一套新的开发测试环境核心要求是基于 CentOS 7 系统部署一个稳定、可复现的 Kubernetes 1.20 集群。Kubernetes 1.20 是一个承上启下的版本它移除了 Docker 作为默认容器运行时但依然保持着良好的稳定性和广泛的生态兼容性非常适合用来学习和理解 K8s 的架构演进。选择 CentOS 7 则是因为其生命周期长、企业存量环境多掌握在其上的部署技能实用性很强。整个操作过程涉及从系统初始化、容器运行时安装、K8s 组件部署到网络插件配置等一系列步骤我会把每一步的原理、踩过的坑和最佳实践都详细记录下来目标是让你能跟着操作一次成功并理解每一步背后的“为什么”。开始之前你需要准备至少两台或更多安装了 CentOS 7.6 或 7.9 的虚拟机或物理机。一台作为 Master控制平面节点其他的作为 Worker工作节点。每台机器建议配置 2核 CPU、4GB 内存、20GB 磁盘以上并确保它们在同一网络内可以互相通信。接下来的所有操作除非特别说明都需要在所有节点上执行。1.1 核心前置操作系统初始化与内核调优安装 Kubernetes 的第一步不是直接装软件而是为它准备一个“干净”且“强壮”的操作系统环境。很多安装失败的问题根源都出在系统配置上。1.1.1 关闭并禁用防火墙与 SELinux这是几乎所有教程都会提到的第一步但我们需要理解原因。Kubernetes 自己有一套复杂的网络规则通过 iptables 或 nftables 实现如果系统防火墙firewalld开启两者规则会产生冲突导致 Pod 之间网络不通。SELinux 则是一种强制访问控制安全模块在某些配置下可能会阻止容器进程访问宿主机资源对于学习环境关闭它可以减少很多权限相关的疑难杂症。# 停止并禁用 firewalld systemctl stop firewalld systemctl disable firewalld # 临时关闭 SELinux立即生效 setenforce 0 # 永久关闭 SELinux需重启生效 sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config注意在生产环境中直接关闭防火墙和 SELinux 是极不安全的。通常的做法是配置 firewalld 放行 K8s 所需端口如 6443, 2379-2380, 10250, 10259等并针对容器运行时和 K8s 组件设置合适的 SELinux 策略。但对于初次部署和测试环境关闭它们是最高效的排错方式。1.1.2 关闭系统 Swap 分区Kubernetes 的设计理念是Pod 的内存使用应该由它自身的资源请求和限制来控制并由 kubelet 来保障。如果允许使用 Swap当内存不足时节点性能会因磁盘 I/O 而急剧下降并且内存资源的统计会变得不准确影响调度器决策。因此从 1.8 版本开始Kubernetes 就要求禁用 Swap。# 临时关闭当前已启用的 Swap swapoff -a # 永久关闭注释掉 /etc/fstab 中所有包含 swap 的行 sed -i / swap / s/^\(.*\)$/#\1/g /etc/fstab你可以通过free -h命令验证 Swap 是否已经全部为 0。1.1.3 配置内核参数与加载模块容器网络和流量转发需要内核支持。我们需要修改sysctl参数并加载必要的内核模块。# 加载内核模块 cat /etc/modules-load.d/k8s.conf EOF br_netfilter ip_vs ip_vs_rr ip_vs_sh ip_vs_wrr nf_conntrack EOF # 立即加载模块 modprobe br_netfilter modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_sh modprobe ip_vs_wrr modprobe nf_conntrack # 配置系统参数 cat /etc/sysctl.d/k8s.conf EOF net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 net.ipv4.ip_forward 1 vm.swappiness 0 EOF # 使配置生效 sysctl --systembr_netfilter和bridge-nf-call-iptables为了让 Linux 网桥设备能够正确处理 iptables 规则这是 Calico、Flannel 等网络插件正常工作所必需的。ip_vs相关模块为后续使用kube-proxy的 IPVS 模式做准备这是一种性能更好的负载均衡实现。net.ipv4.ip_forward 1启用 IP 转发这是实现 Pod 跨节点通信的基础。vm.swappiness 0尽可能避免使用 Swap即使它被禁用这个设置也能提供额外保障。1.1.4 配置主机名与 Hosts 解析清晰的节点标识对于集群管理至关重要。# 在 Master 节点执行 hostnamectl set-hostname k8s-master # 在 Worker 节点执行例如 worker1 hostnamectl set-hostname k8s-worker1 # 编辑所有节点的 /etc/hosts 文件添加所有节点的 IP 和主机名映射 # 假设 Master IP 为 192.168.1.100 Worker1 IP 为 192.168.1.101 cat /etc/hosts EOF 192.168.1.100 k8s-master 192.168.1.101 k8s-worker1 EOF配置后建议使用ping k8s-master和ping k8s-worker1在所有节点上测试网络连通性和解析是否正确。1.1.5 时间同步Chrony集群内所有节点的时间必须高度同步否则会导致证书错误、日志时间错乱、调度问题等。# 安装 chrony yum install -y chrony # 启动并设置开机自启 systemctl start chronyd systemctl enable chronyd # 查看同步状态 chronyc sources -v确保输出中有一个^*标记的源表示当前已成功同步。1.2 容器运行时安装Containerd 的选型与配置从 Kubernetes 1.20 开始官方不再将 Docker 作为默认的容器运行时CRI而是转向更轻量、更专注于 Kubernetes 的containerd或CRI-O。这里我们选择containerd因为它由 Docker 公司贡献成熟稳定且是很多云厂商的默认选择。1.2.1 为什么选择 Containerd 而非 DockerDocker 本身是一个完整的容器平台包含了容器运行时containerd、构建工具、镜像管理、网络和存储插件等。而 Kubernetes 只需要其中的容器运行时功能并通过 CRI容器运行时接口与它交互。使用完整的 Docker 会引入不必要的组件和复杂性。Containerd 是一个纯粹的、高性能的容器运行时它实现了 CRI并且是 CNCF 毕业项目与 Kubernetes 的集成更直接、更高效。1.2.2 安装 Containerd我们将从官方 GitHub Release 页面下载特定版本。这里选择1.4.13这是一个与 K8s 1.20 兼容性很好的稳定版本。# 下载 containerd wget https://github.com/containerd/containerd/releases/download/v1.4.13/containerd-1.4.13-linux-amd64.tar.gz # 解压到系统目录 tar Cxzvf /usr/local containerd-1.4.13-linux-amd64.tar.gz # 下载并安装 runccontainerd 依赖的底层容器工具 wget https://github.com/opencontainers/runc/releases/download/v1.0.3/runc.amd64 install -m 755 runc.amd64 /usr/local/sbin/runc # 下载并安装 cni-plugins容器网络接口插件 wget https://github.com/containernetworking/plugins/releases/download/v0.9.1/cni-plugins-linux-amd64-v0.9.1.tgz mkdir -p /opt/cni/bin tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v0.9.1.tgz1.2.3 配置 Containerd 系统服务与配置文件为了让 containerd 作为系统服务运行我们需要创建 systemd 单元文件。# 创建 systemd 服务文件 cat /etc/systemd/system/containerd.service EOF [Unit] Descriptioncontainerd container runtime Documentationhttps://containerd.io Afternetwork.target local-fs.target [Service] ExecStartPre-/sbin/modprobe overlay ExecStart/usr/local/bin/containerd Typenotify Delegateyes KillModeprocess Restartalways RestartSec5 LimitNPROCinfinity LimitCOREinfinity LimitNOFILEinfinity TasksMaxinfinity OOMScoreAdjust-999 [Install] WantedBymulti-user.target EOF接下来是核心的config.toml配置文件。这里我们生成一个基础配置并关键地配置 systemd 作为 cgroup 驱动。Kubernetes 推荐使用systemd而非cgroupfs作为 cgroup 驱动以获得更好的资源隔离和与系统服务的集成。# 生成默认配置文件 mkdir -p /etc/containerd containerd config default /etc/containerd/config.toml # 使用 sed 修改配置文件将 cgroup 驱动改为 systemd sed -i s/SystemdCgroup false/SystemdCgroup true/g /etc/containerd/config.toml # 还可以修改沙箱镜像Pause 镜像地址为国内源加速拉取 sed -i s|registry.k8s.io/pause:3.2|registry.aliyuncs.com/google_containers/pause:3.2|g /etc/containerd/config.toml1.2.4 启动并验证 Containerd# 重新加载 systemd 配置 systemctl daemon-reload # 启动 containerd 并设置开机自启 systemctl start containerd systemctl enable containerd # 查看状态 systemctl status containerd # 运行一个测试容器 ctr images pull docker.io/library/hello-world:latest ctr run --rm docker.io/library/hello-world:latest hello-world-test如果能看到 “Hello from Docker!” 之类的输出说明 containerd 安装成功且可以正常运行容器。2. Kubernetes 组件安装与集群初始化系统环境和容器运行时准备就绪后我们就可以安装 Kubernetes 的核心组件了kubeadm、kubelet和kubectl。kubeadm是官方的集群引导工具kubelet是运行在每个节点上的代理kubectl是命令行管理工具。2.1 配置 Kubernetes Yum 源并安装组件由于网络原因直接使用谷歌的源速度很慢。我们使用阿里云的镜像源。# 创建 kubernetes 的 yum 源配置文件 cat /etc/yum.repos.d/kubernetes.repo EOF [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled1 gpgcheck1 repo_gpgcheck1 gpgkeyhttps://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF # 安装指定版本1.20.15的 kubelet, kubeadm, kubectl yum install -y kubelet-1.20.15 kubeadm-1.20.15 kubectl-1.20.15 --disableexcludeskubernetes # 启动 kubelet 并设置开机自启 systemctl enable --now kubelet注意此时kubelet的状态可能是active (exited)或不断重启这是正常的因为它的配置文件由kubeadm init生成还不存在。不要试图去手动启动它等kubeadm init完成后自然会正常。2.2 使用 Kubeadm 初始化 Master 节点这是最关键的一步。我们将在 Master 节点上执行kubeadm init命令来引导集群的控制平面。2.2.1 生成初始化配置文件直接使用kubeadm init加一堆参数也可以但使用配置文件更清晰也便于版本控制和复用。# 生成默认的初始化配置文件 kubeadm config print init-defaults kubeadm-config.yaml编辑这个kubeadm-config.yaml文件修改以下几个关键部分apiVersion: kubeadm.k8s.io/v1beta2 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.100 # 修改为 Master 节点的 IP 地址 bindPort: 6443 nodeRegistration: criSocket: /run/containerd/containerd.sock # 指定 containerd 的 socket 路径 name: k8s-master # 修改为 Master 节点的主机名 taints: [] --- apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration kubernetesVersion: v1.20.15 # 指定版本 controlPlaneEndpoint: 192.168.1.100:6443 # 控制平面端点单节点集群就是 Master IP imageRepository: registry.aliyuncs.com/google_containers # 使用国内镜像仓库 networking: podSubnet: 10.244.0.0/16 # 设置 Pod 网络 CIDR这里为 Flannel 插件预留 serviceSubnet: 10.96.0.0/12 --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: systemd # 必须与 containerd 配置一致criSocket明确告诉 kubeadm 我们使用的是 containerd。imageRepository这是加速安装的核心将镜像源指向阿里云避免从k8s.gcr.io拉取失败。podSubnet这个网段需要与你后续安装的网络插件如 Flannel、Calico的默认网段匹配。Flannel 的默认网段就是10.244.0.0/16。cgroupDriver: systemd与之前 containerd 的配置保持一致这是避免kubelet启动失败的关键。2.2.2 预拉取镜像与执行初始化在真正初始化之前可以先拉取所需镜像检查是否有问题。# 根据配置文件预拉取镜像 kubeadm config images pull --config kubeadm-config.yaml如果一切顺利你会看到类似[config/images] Pulled registry.aliyuncs.com/google_containers/kube-apiserver:v1.20.15的成功信息。现在执行初始化命令kubeadm init --config kubeadm-config.yaml --upload-certs--upload-certs将控制平面证书上传到集群方便后续添加新的 Master 节点高可用部署。这个过程大约需要1-3分钟。如果成功你会在最后看到类似如下的输出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.100:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx请务必妥善保存最后的kubeadm join命令这是 Worker 节点加入集群的凭证。2.2.3 配置 kubectl 环境按照提示我们需要配置kubectl的认证信息。# 对于非 root 用户推荐 mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config # 对于 root 用户 export KUBECONFIG/etc/kubernetes/admin.conf # 可以将这行添加到 ~/.bashrc 中永久生效 echo export KUBECONFIG/etc/kubernetes/admin.conf ~/.bashrc现在在 Master 节点上执行kubectl get nodes你应该能看到k8s-master节点但其状态是NotReady这是因为 Pod 网络插件还没有安装。2.3 安装 Pod 网络插件CNIFlannelPod 网络插件是 Kubernetes 集群的“神经系统”负责为每个 Pod 分配 IP 地址并实现 Pod 跨节点通信。这里选择最经典和简单的 Flannel。# 下载 Flannel 的配置文件 wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml # 在应用之前有一个关键步骤检查 Flannel 配置的网段是否与 kubeadm 初始化时设置的 podSubnet 一致。 # 使用 grep 查看 grep -n net-conf.json kube-flannel.yml通常这个配置文件里会有一行Network: 10.244.0.0/16。如果与你kubeadm-config.yaml中的podSubnet一致就可以直接应用。如果不一致你需要修改kube-flannel.yml文件或者用你修改后的podSubnet重新初始化集群不推荐除非刚开始。应用 Flannelkubectl apply -f kube-flannel.yml这个命令会创建一系列 Namespace、ServiceAccount、ConfigMap、DaemonSet 等资源。DaemonSet 会确保在每个节点包括 Master上都运行一个flanneldPod。等待大约一分钟然后检查kubectl get pods -n kube-system -l appflannel你应该看到每个节点上都有一个kube-flannel-ds-xxxxxPod 处于Running状态。再检查节点状态kubectl get nodes现在k8s-master节点的状态应该变为Ready。2.4 将 Worker 节点加入集群回到你的 Worker 节点例如k8s-worker1确保你已经完成了1.1 节的所有系统初始化步骤以及1.2 节的 containerd 安装和2.1 节的 kubelet 安装。然后直接运行之前在 Master 初始化成功时得到的kubeadm join命令kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx如果 token 过期默认24小时可以在 Master 节点上重新生成# 生成新的 token kubeadm token create --print-join-command加入成功后在 Master 节点上执行kubectl get nodes稍等片刻你应该能看到k8s-worker1节点出现并且状态最终变为Ready。3. 集群验证与核心组件状态检查集群搭建完成后不要急于部署应用先进行全面的健康检查。3.1 基础资源状态检查# 1. 查看所有节点状态确保都是 Ready kubectl get nodes -o wide # 2. 查看所有系统 Podkube-system 命名空间的状态 kubectl get pods -n kube-system -o wide # 3. 查看核心组件的健康状态 kubectl get cs对于第3条命令在 Kubernetes 1.20 版本中componentstatus(cs) 已被废弃更推荐使用以下命令检查各组件# 检查 kube-apiserver kubectl get --raw/readyz?verbose # 检查 etcd kubectl get --raw/livez?verbose或者通过查看对应 Pod 的日志来确认# 查看 kube-apiserver 日志 kubectl logs -n kube-system kube-apiserver-k8s-master # 查看 kube-controller-manager 日志 kubectl logs -n kube-system kube-controller-manager-k8s-master # 查看 kube-scheduler 日志 kubectl logs -n kube-system kube-scheduler-k8s-master # 查看 etcd 日志 kubectl logs -n kube-system etcd-k8s-master注意组件 Pod 的名称后缀是你的节点主机名如k8s-master。如果 Pod 不是Running状态使用kubectl describe pod pod-name -n kube-system查看详细事件通常能定位到镜像拉取失败、配置错误等问题。3.2 网络连通性测试创建一个测试 Deployment 和服务验证跨节点网络和 DNS 是否正常。# 创建一个简单的 Nginx Deployment cat test-nginx.yaml EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-test spec: replicas: 2 selector: matchLabels: app: nginx-test template: metadata: labels: app: nginx-test spec: containers: - name: nginx image: nginx:alpine ports: - containerPort: 80 EOF kubectl apply -f test-nginx.yaml # 创建一个 NodePort 类型的 Service 来暴露它 cat test-nginx-svc.yaml EOF apiVersion: v1 kind: Service metadata: name: nginx-test-service spec: type: NodePort selector: app: nginx-test ports: - protocol: TCP port: 80 targetPort: 80 EOF kubectl apply -f test-nginx-svc.yaml检查 Pod 是否被调度到不同节点如果有多个 Worker并运行kubectl get pods -l appnginx-test -o wide查看 Service 信息获取 NodePort 端口在 30000-32767 之间kubectl get svc nginx-test-service现在你可以通过http://任意节点IP:NodePort来访问这个 Nginx 服务。如果能够看到 Nginx 欢迎页说明 Pod 网络、Service 网络和节点端口映射都是正常的。DNS 测试# 启动一个临时的 busybox Pod 进行 DNS 解析测试 kubectl run busybox --imagebusybox:1.28 --restartNever --rm -it -- sh # 进入容器后执行 nslookup kubernetes.default如果能够成功解析出kubernetes.default.svc.cluster.local的 ClusterIP通常是10.96.0.1说明集群内部的 DNS 服务CoreDNS工作正常。4. 生产环境考量与常见故障排查一个能跑起来的集群只是一个开始。要让集群稳定、可用还需要考虑一些生产级别的配置和知道如何排错。4.1 关键优化与安全配置1. 移除 Master 节点的污点Taint默认情况下Master 节点有node-role.kubernetes.io/master:NoSchedule污点普通 Pod 不会被调度上去。在开发或资源紧张的环境你可能希望允许 Pod 调度到 Master。# 查看节点污点 kubectl describe node k8s-master | grep Taint # 移除污点 kubectl taint nodes k8s-master node-role.kubernetes.io/master:NoSchedule-警告在生产环境中不建议移除 Master 的污点以保证控制平面的稳定性和安全。2. 配置 kube-proxy 为 IPVS 模式默认的iptables模式在 Service 数量很多时性能下降明显。IPVS 是专门为负载均衡设计的内核模块性能更好。# 首先确认内核模块已加载我们在 1.1.3 节已经做了 lsmod | grep ip_vs # 获取当前的 kube-proxy ConfigMap kubectl get configmap kube-proxy -n kube-system -o yaml kube-proxy-config.yaml # 编辑这个 yaml 文件找到 mode: 这一行修改为 mode: ipvs # 同时可以开启 strictARP 以更好地兼容某些网络环境 sed -i s/mode: \\/mode: \ipvs\/g kube-proxy-config.yaml # 在 data.config.conf 的末尾ipvs: 部分添加 strictARP: true (如果不存在则添加) # 更新 ConfigMap kubectl apply -f kube-proxy-config.yaml # 重启所有 kube-proxy Pod 以生效 kubectl rollout restart daemonset kube-proxy -n kube-system3. 配置镜像拉取策略与私有仓库在企业内部通常会搭建私有镜像仓库。需要在 containerd 和 Kubernetes 中配置认证。对于 containerd编辑/etc/containerd/config.toml在[plugins.io.containerd.grpc.v1.cri.registry.mirrors]下添加镜像加速器在[plugins.io.containerd.grpc.v1.cri.registry.configs]下添加认证信息然后重启 containerd。对于 Kubernetes需要创建imagePullSecrets。首先在 Master 节点登录私有仓库并生成 docker configdocker login myprivateregistry.com # 将生成的 ~/.docker/config.json 编码为 base64 cat ~/.docker/config.json | base64 -w 0然后创建一个 SecretapiVersion: v1 kind: Secret metadata: name: my-registry-secret namespace: default # 或者你需要的命名空间 type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: 上面生成的base64字符串在 Pod 的 spec 中引用它spec: containers: - name: myapp image: myprivateregistry.com/myapp:latest imagePullSecrets: - name: my-registry-secret4.2 典型故障排查实录即使按照步骤操作也可能会遇到问题。这里记录几个我踩过的坑和解决方法。问题1kubeadm init 时卡在[kubelet-check]或[control-plane]现象初始化命令长时间没有进展或者报错kubelet isnt running。排查systemctl status kubelet查看 kubelet 状态和日志journalctl -xeu kubelet。常见错误是cgroup driver不一致。确保 containerd 的config.toml和 kubelet 的配置通过kubeadm-config.yaml传递都是systemd。检查10-kubeadm.conf文件cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf确保环境变量正确。运行kubeadm reset清理环境修正配置后重试。问题2Pod 一直处于Pending状态现象kubectl get pods显示 Pod 状态为Pending。排查kubectl describe pod pod-name查看Events部分。最常见的原因Insufficient cpu/memory节点资源不足。0/1 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }Pod 无法容忍 Master 节点的污点。镜像拉取失败检查镜像名称是否正确网络是否通畅私有仓库密钥是否配置。问题3Pod 处于ImagePullBackOff或ErrImagePull状态现象Pod 无法启动事件显示拉取镜像失败。排查手动在节点上使用crictl pull或ctr images pull尝试拉取镜像看是否是网络问题。检查 Pod 定义中是否指定了正确的imagePullSecrets。对于k8s.gcr.io的镜像确保在kubeadm init时使用了--image-repository参数指向了正确的镜像仓库如阿里云。问题4Node 状态为NotReady现象kubectl get nodes显示节点状态不是Ready。排查登录该节点检查kubelet服务状态systemctl status kubelet。检查kubelet日志journalctl -xeu kubelet -f。检查网络插件 Pod如flannel在该节点上是否运行正常kubectl get pods -n kube-system -o wide | grep node-name。常见原因防火墙未关闭、内核模块未加载、/etc/hosts配置错误导致节点间通信失败。问题5Service 的 NodePort 无法访问现象Pod 运行正常Service 已创建但通过NodeIP:NodePort无法访问。排查检查节点防火墙是否关闭或者是否放行了 NodePort 范围30000-32767的端口。在节点上执行iptables -t nat -nL | grep NodePort看是否有对应的 DNAT 规则。如果没有可能是kube-proxy没有正常工作。检查kube-proxyPod 日志kubectl logs -n kube-system kube-proxy-pod-name。搭建 Kubernetes 集群是一个系统工程涉及操作系统、网络、存储、安全等多个层面。这份基于 CentOS 7 和 K8s 1.20 的详细指南涵盖了从零开始到可运行状态的完整路径并包含了关键的原理说明和排错经验。实际操作中耐心和仔细查看日志是解决问题的关键。希望这份记录能帮助你顺利搭建起自己的 Kubernetes 学习或测试环境。