10分钟部署K8s集群:kubeadm极简安装指南

10分钟部署K8s集群:kubeadm极简安装指南 前言还记得我第一次部署 Kubernetes的场景。那时候听说 K8s 很火想学习一下。网上找教程大部分都是推荐二进制部署说这样更灵活、“更底层”。好嘛那我就跟着做。结果这一折腾就是整整3天etcd 证书生成失败报错信息模糊不清kubelet 和 kube-apiserver 版本不匹配各种依赖包缺这少那网络插件装完Pod 就是连不通…最后一天深夜我实在受不了搜了下 “Kubernetes 最简单的安装方式”才发现有kubeadm这个神器。10分钟一个可用的集群就搭起来了。当时我那个心情啊——既高兴又懊恼。高兴的是终于跑通了懊恼的是为什么不早点知道 kubeadm。所以今天这篇文章把我用 kubeadm 部署集群的完整流程分享出来帮你少走3天弯路。一、环境准备1.1 服务器配置要求在开始之前先确认你的环境满足以下条件配置项最低要求推荐配置操作系统CentOS 7 / Ubuntu 18.04CentOS 7.9 / Ubuntu 20.04CPU2核4核内存2GB4GB硬盘20GB50GB网络节点间互通内网互通可访问外网节点数1 Master 1 Worker1 Master 2 Worker⚠️注意如果只有一台机器也可以部署单节点集群Master 同时作为 Worker但生产环境不推荐这样做。1.2 节点规划示例我的测试环境配置角色IP地址主机名配置Master192.168.0.112k8s-master4C8GWorker1192.168.0.113k8s-worker12C4GWorker2192.168.0.114k8s-worker22C4G二、前置准备工作2.1 修改主机名所有节点首先给每个节点设置一个有意义的主机名方便后续管理。# 在 Master 节点执行hostnamectl set-hostname k8s-master# 在 Worker1 节点执行hostnamectl set-hostname k8s-worker1# 在 Worker2 节点执行hostnamectl set-hostname k8s-worker2# 查看修改结果hostnamectl status2.2 配置 hosts 解析所有节点确保每个节点都能通过主机名访问其他节点# 编辑 /etc/hosts 文件添加以下内容cat/etc/hostsEOF 192.168.0.112 k8s-master 192.168.0.113 k8s-worker1 192.168.0.114 k8s-worker2 EOF# 验证pingk8s-master-c3小贴士生产环境建议使用内网 DNS 或 Consul 等服务发现方案而不是手动配置 hosts。2.3 关闭防火墙和 SELinux所有节点Kubernetes 需要开放很多端口为避免网络问题先关闭防火墙# 关闭防火墙systemctl stop firewalld systemctl disable firewalld# 关闭 SELinuxsetenforce0sed-is/^SELINUXenforcing$/SELINUXdisabled//etc/selinux/config# 验证getenforce# 应该显示 Disabled 或 Permissive坑点警示我第一次部署时没关 SELinux结果 kubelet 一直启动失败报错信息还不明显。折腾了2小时才发现是 SELinux 的问题。务必关闭2.4 关闭 swap所有节点Kubernetes 要求关闭 swap否则 kubelet 无法启动# 临时关闭swapoff-a# 永久关闭注释掉 swap 相关的行sed-i/swap/d/etc/fstab# 验证free-h# 确认 swap 显示为 0⚠️为什么必须关闭 swap因为 K8s 需要精确控制内存分配swap 会干扰资源调度。不过 K8s 1.22 版本开始支持在特定场景下启用 swap。2.5 配置内核参数所有节点# 加载必要的内核模块cat/etc/modules-load.d/k8s.confEOF overlay br_netfilter EOFmodprobe overlay modprobe br_netfilter# 配置 sysctl 参数cat/etc/sysctl.d/k8s.confEOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF# 生效sysctl--system三、安装容器运行时所有节点Kubernetes 需要一个容器运行时Container Runtime。常见的选择有Docker最常用生态完善containerd更轻量K8s 1.24 的默认选择这里我们使用 Docker# 安装依赖yuminstall-yyum-utils device-mapper-persistent-data lvm2# 添加阿里云镜像源yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo# 安装 Dockeryuminstall-ydocker-ce-20.10.17 docker-ce-cli-20.10.17 containerd.io# 启动 Dockersystemctl startdockersystemctlenabledocker# 验证dockerversion3.1 配置镜像加速器国内访问 Docker Hub 很慢建议配置镜像加速器# 创建 Docker 配置文件mkdir-p/etc/docker# 配置阿里云镜像加速器换成你自己的cat/etc/docker/daemon.jsonEOF { registry-mirrors: [ https://registry.cn-hangzhou.aliyuncs.com, https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com ], exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m }, storage-driver: overlay2 } EOF# 重启 Dockersystemctl daemon-reload systemctl restartdocker获取个人加速器登录 阿里云容器镜像服务左侧菜单找到镜像工具-“镜像加速器”复制你的专属地址。四、安装 kubeadm、kubelet、kubectl所有节点这三个工具是 Kubernetes 的核心kubeadm集群初始化和管理工具kubelet运行在每个节点上管理 Pod 生命周期kubectlK8s 命令行工具用于操作集群4.1 使用一键安装脚本为了简化安装我用了一个开源的安装脚本# 设置镜像仓库使用阿里云镜像exportREGISTRY_MIRRORhttps://registry.cn-hangzhou.aliyuncs.com# 执行安装脚本安装 v1.21.0 版本# 最后一个参数 1.21.0 用于指定 Kubernetes 版本支持所有 1.21.x 版本curl-sSLhttps://kuboard.cn/install-script/v1.21.x/install_kubelet.sh|sh-s1.21.0坑点警示不设置REGISTRY_MIRROR的话默认从 Google 仓库拉镜像在国内基本拉不下来。务必配置国内镜像脚本会自动完成以下工作配置 Kubernetes yum 源安装指定版本的 kubeadm、kubelet、kubectl启动 kubelet 服务4.2 验证安装# 查看版本kubeadm version kubectl version--clientkubelet--version# 设置 kubelet 开机自启systemctlenablekubelet为什么 kubelet 启动失败是正常的因为 kubelet 需要连接 API Server而此时集群还没有初始化。等 Master 初始化完成后kubelet 会自动恢复正常。五、初始化 Master 节点5.1 配置环境变量# 替换为你的 Master 节点实际内网 IPexportMASTER_IP192.168.0.112# 设置 API Server 的域名可以自定义exportAPISERVER_NAMEapiserver.demo# Kubernetes Pod 网段确保该网段不与你的物理网络冲突exportPOD_SUBNET10.100.0.0/16# 添加 hosts 解析echo${MASTER_IP}${APISERVER_NAME}/etc/hosts⚠️重要提示POD_SUBNET必须是你的物理网络中没有使用的网段。如果你的内网是 10.x.x.x可能需要改成 172.16.0.0/16 或 192.168.x.x。5.2 执行初始化# 执行初始化脚本curl-sSLhttps://kuboard.cn/install-script/v1.21.x/init_master.sh|sh-s1.21.0脚本会自动使用 kubeadm 初始化集群安装网络插件Flannel 或 Calico配置 kubectl输出加入集群的命令5.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 Then, you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.0.112:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxx务必保存好这个 join 命令Worker 节点需要用它加入集群。5.4 配置 kubectlMaster 节点# 配置 kubectlmkdir-p$HOME/.kubesudocp-i/etc/kubernetes/admin.conf$HOME/.kube/configsudochown$(id-u):$(id-g)$HOME/.kube/config# 验证kubectl get nodes如果看到 Master 节点状态是NotReady不要着急等网络插件启动完成# 查看系统 Pod 状态kubectl get pods-nkube-system# 等待所有 Pod 状态变为 Runningwatchkubectl get pods-nkube-system⏱️时间参考网络插件初始化通常需要 1-3 分钟。六、Worker 节点加入集群6.1 配置 hostsWorker 节点# 配置环境变量exportMASTER_IP192.168.0.112exportAPISERVER_NAMEapiserver.demo# 添加 hosts 解析echo${MASTER_IP}${APISERVER_NAME}/etc/hosts6.2 执行加入命令在每个 Worker 节点上执行 Master 初始化时保存的 join 命令kubeadmjoin192.168.0.112:6443--tokenabcdef.0123456789abcdef\--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxx如果成功会看到This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run kubectl get nodes on the control-plane to see this node join the cluster.6.3 验证集群状态Master 节点# 查看所有节点kubectl get nodes# 预期输出# NAME STATUS ROLES AGE VERSION# k8s-master Ready control-plane,master 5m v1.21.0# k8s-worker1 Ready none 1m v1.21.0# k8s-worker2 Ready none 1m v1.21.0恭喜你的 Kubernetes 集群已经搭建完成七、验证集群功能7.1 部署一个测试应用# 创建一个 Nginx Deploymentkubectl create deployment nginx--imagenginx:alpine--replicas3# 暴露为 Servicekubectl expose deployment nginx--port80--typeNodePort# 查看 Pod 状态kubectl get pods-owide# 查看 Servicekubectl get svc nginx7.2 访问测试应用# 获取 NodePortNODE_PORT$(kubectl get svc nginx-ojsonpath{.spec.ports[0].nodePort})echoNginx 访问地址: http://NodeIP:$NODE_PORT# 测试访问curlhttp://192.168.0.112:$NODE_PORT如果能看到 Nginx 的欢迎页面说明集群工作正常八、我踩过的坑避坑指南坑 1镜像拉取失败现象Pod 状态一直是ImagePullBackOff原因Docker 没有配置镜像加速器从 Docker Hub 拉镜像超时解决# 配置阿里云镜像加速器cat/etc/docker/daemon.jsonEOF { registry-mirrors: [https://registry.cn-hangzhou.aliyuncs.com] } EOFsystemctl restartdocker坑 2Node 无法加入集群现象执行kubeadm join报错connection refused原因Worker 节点无法访问 Master 的 6443 端口解决# 在 Worker 节点测试连通性telnet192.168.0.1126443# 如果不通检查# 1. Master 防火墙是否放行 6443# 2. hosts 配置是否正确坑 3Coredns Pod 一直 Pending现象kubectl get pods -n kube-system看到 coredns 状态为 Pending原因网络插件如 Flannel没有正确安装解决# 手动安装 Flannelkubectl apply-fhttps://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml# 或者安装 Calicokubectl apply-fhttps://docs.projectcalico.org/manifests/calico.yaml坑 4忘记保存 join token现象初始化 Master 后没有保存 join 命令Worker 无法加入解决# 在 Master 节点重新生成 tokenkubeadm token create --print-join-command坑 5Pod 无法跨 Node 通信现象Pod 在同节点内可以通信跨节点不通原因网络插件配置问题或者节点间网络策略限制解决# 检查网络插件是否正常kubectl get pods-nkube-system-lappflannel# 检查节点间连通性从 Worker ping Master 的 POD_CIDRping10.100.0.1九、常用命令速查命令说明kubectl get nodes查看所有节点kubectl get pods -A查看所有命名空间的 Podkubectl get pods -o wide查看 Pod 详细信息包括 IP、Nodekubectl describe node node-name查看节点详情kubectl logs pod-name查看 Pod 日志kubectl exec -it pod-name -- /bin/sh进入 Pod 容器kubectl get svc查看所有 Servicekubectl delete pod pod-name删除 Podkubeadm token create --print-join-command重新生成 join 命令十、清理集群如需重建如果你想重新部署可以先清理# 在 Worker 节点执行kubeadm reset-f# 在 Master 节点执行kubeadm reset-frm-rf$HOME/.kube/configrm-rf/etc/cni/net.d iptables-Fiptables-tnat-Fiptables-tmangle-Fiptables-Xipvsadm--clear总结跟着这篇指南你应该已经在 10 分钟内搭建好了一个可用的 Kubernetes 集群。关键步骤回顾✅ 环境准备修改主机名、关闭防火墙/swap✅ 安装 Docker 并配置镜像加速器✅ 安装 kubeadm、kubelet、kubectl✅ 初始化 Master 节点✅ Worker 节点加入集群✅ 验证集群功能