1. 这不是“又一个K8s教程”,而是生产环境里真正跑得起来的部署路径
你搜“K8s部署教程”,首页弹出的大多是三步装Docker、五步启Minikube、十行yaml跑个Nginx——看着很顺,一上真机就卡在证书过期、节点NotReady、Service死活不通。我带过7个从零搭建生产级K8s集群的项目,最短耗时14小时,最长拖了6天,问题全出在教程没说透的“中间地带”:证书怎么续、etcd怎么备份、kube-proxy用iptables还是ipvs、CoreDNS要不要改上游、NodePort端口范围够不够用……这些细节不写进步骤里,就等于把人扔进深水区却只发一根吸管。
标题里“从零到生产可用”这六个字,是硬指标,不是口号。它意味着:集群能扛住连续72小时CPU 85%负载;节点宕机后Pod自动漂移不丢数据;滚动更新时API响应延迟波动不超过±15ms;所有组件日志可集中采集、错误能精准定位到具体Pod的容器内;安全策略默认拒绝所有入向流量,只放行明确声明的服务端口。这些不是K8s自带的,是你亲手配置出来的。本篇全程基于v1.28.10(LTS长期支持版),用kubeadm作为唯一安装工具——不推荐二进制手动装(易错难维护),也不用Rancher或OpenShift这类封装层(掩盖底层逻辑)。所有命令、配置、参数均来自我们线上集群实测验证,包括证书有效期设为10年(避免90天过期导致凌晨告警)、etcd快照压缩策略调优、kube-apiserver内存限制从默认2G提升至4G以支撑300+节点规模。如果你正准备给公司核心业务上K8s,或者要通过CKA认证但总在实操环节翻车,这篇就是为你写的。它不讲“K8s是什么”,只解决“怎么让它在生产环境里稳稳站着”。
2. 部署设计的核心逻辑:为什么必须放弃“一键脚本”,坚持kubeadm分步控制
2.1 生产环境的三个不可妥协前提
很多团队栽在第一步:用Ansible一键脚本装完集群,发现Node节点状态飘红,查日志全是x509: certificate has expired or is not yet valid。根源在于脚本把所有证书有效期硬编码成365天,而K8s官方要求CA证书至少10年——因为重签CA会触发整个集群证书链轮换,涉及etcd、apiserver、kubelet、controller-manager全部重启,业务中断无法避免。kubeadm允许你用--cert-expiry参数显式指定,这是脚本做不到的精细控制。
第二个前提是网络插件选型必须与CNI规范深度对齐。Calico、Cilium、Flannel看似都能跑通Pod通信,但在生产中差异巨大:Calico的NetworkPolicy执行粒度到IP+端口+协议,Cilium基于eBPF能实现L7层策略且性能损耗低于5%,Flannel纯UDP封装在万兆网卡下吞吐比Calico低37%。我们最终选Cilium,不是因为它新,而是它能把Ingress控制器、服务网格、安全策略三合一,减少组件数量——每少一个DaemonSet,就少一个潜在故障点。而这个决策必须在kubeadm init前通过--pod-network-cidr和后续CNI配置文件共同确定,脚本往往固化为Flannel,改起来要重装。
第三个前提是节点角色分离必须物理化而非标签化。教程里常说“打label让Master也跑Pod”,但生产环境严禁这么做。Control Plane节点要独占CPU资源处理etcd Raft日志、apiserver请求路由、scheduler调度决策,一旦混跑业务Pod,etcd写延迟飙升会导致整个集群失联。我们强制三台Master仅运行系统组件,Worker节点单独规划,且Worker按业务域再细分:计算型(高CPU)、存储型(大IO)、GPU型(CUDA驱动预装)。这种架构只能靠kubeadm init + join时精确指定--control-plane和--node-labels实现,脚本通常忽略此细节。
2.2 kubeadm不是“简化工具”,而是生产级部署的编排中枢
kubeadm常被误解为“新手玩具”,其实它是K8s官方认证的生产部署引擎。它的设计哲学是:把集群生命周期管理拆解为可审计、可回滚、可组合的原子操作。比如kubeadm init phase系列命令:
kubeadm init phase certs all:生成全部证书,支持自定义CA、指定SAN(Subject Alternative Name)包含内网DNS名和VIPkubeadm init phase etcd local:本地启动etcd,可传入--config指定data-dir、wal-dir、heartbeat-interval等关键参数kubeadm init phase kubeconfig admin:生成admin.conf,但你可以用--certificate-key将其加密后存入KMS,杜绝配置文件泄露风险
这些phase不是内部实现细节,而是你每天要打交道的操作单元。当某次升级后apiserver启动失败,你不需要重装集群,只需kubeadm init phase control-plane重装控制平面组件,其他节点证书和etcd数据完好无损。而脚本式部署一旦出错,基本只能rm -rf /etc/kubernetes重来。
2.3 版本锁定与依赖收敛:为什么v1.28.10是当前最优解
截至2024年Q3,v1.28是最后一个支持Dockershim的LTS版本(虽已废弃,但大量遗留系统仍依赖),v1.29起彻底移除,要求所有节点预装containerd。我们选择v1.28.10而非最新v1.30,基于三个硬性约束:
- 硬件兼容性:某客户旧服务器BIOS不支持cgroup v2,而v1.29+强制要求cgroup v2,降级到v1.28可启用
systemd.unified_cgroup_hierarchy=0内核参数绕过 - Operator生态成熟度:主流数据库Operator(如Percona、CrunchyData)对v1.28的CRD支持最完整,v1.30中部分字段已标记deprecated
- 安全补丁密度:v1.28.10集成了CVE-2024-21626(kubelet权限提升)和CVE-2024-23322(etcd拒绝服务)的修复,而v1.30尚未发布对应补丁
依赖收敛同样关键。Docker CE 24.0.7与containerd 1.7.18存在镜像层解析冲突,我们锁定containerd 1.7.13 + runc 1.1.12组合,该组合经300+节点压测验证无OOM异常。所有版本号不是随便选的,而是从CNCF Certified Kubernetes Conformance列表中逐条比对得出。
3. 实操全流程:从裸机到生产就绪的12个关键步骤
3.1 环境准备:操作系统与内核参数的硬性清单
生产环境不用Ubuntu桌面版或CentOS Stream,我们统一采用Rocky Linux 9.3(Kernel 5.14.0-362.18.1.el9_3)。选择依据:RHEL系内核长期稳定、SELinux默认启用(增强安全)、dnf包管理器依赖解析更严谨。以下是必须执行的初始化操作:
# 关闭swap(K8s强制要求) sudo swapoff -a sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab # 加载内核模块 cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # 配置sysctl参数(永久生效) 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 vm.swappiness = 0 fs.inotify.max_user_watches = 524288 EOF sudo sysctl --system # 时间同步(生产环境严禁NTP漂移) sudo chronyd -q 'server ntp1.aliyun.com iburst' sudo systemctl enable chronyd && sudo systemctl start chronyd提示:
vm.swappiness=0不是简单关闭swap,而是防止内核在内存压力下将匿名页交换出去,导致kubelet误判OOM Killer触发。我们曾因未设此参数,在节点内存95%时kubelet主动驱逐Pod,实际物理内存仍有2GB空闲。
3.2 容器运行时:containerd配置的5处致命细节
K8s v1.28默认使用containerd,但官方配置模板(/etc/containerd/config.toml)有5处必须修改:
镜像仓库加速:国内访问docker.io超时,需配置registry.mirrors
[plugins."io.containerd.grpc.v1.cri".registry] [plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://registry.cn-hangzhou.aliyuncs.com"]镜像解压优化:默认使用tar-split解压,速度慢且占用CPU高,改为native
[plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "native"CNI插件路径:kubeadm默认找/opt/cni/bin,但Cilium安装到/opt/cni/bin/cilium,需显式指定
[plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d"日志轮转:容器日志不轮转会撑爆根分区,设置max-size和max-file
[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime] [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options] SystemdCgroup = true [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] BinaryName = "/usr/local/bin/runc" SystemdCgroup = trueRootless模式禁用:生产环境必须用root运行containerd,否则无法挂载hostPath卷
[plugins."io.containerd.grpc.v1.cri".containerd] disable_pivot = false
配置完成后执行sudo systemctl restart containerd,并用crictl ps验证是否正常。
3.3 kubeadm初始化:证书、网络、高可用的三位一体配置
Master节点执行kubeadm init前,必须准备一个定制化的kubeadm-config.yaml:
apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.28.10 controlPlaneEndpoint: "192.168.10.100:6443" # VIP,由Keepalived管理 networking: podSubnet: "10.244.0.0/16" # Cilium固定要求 serviceSubnet: "10.96.0.0/12" certificatesDir: /etc/kubernetes/pki clusterName: prod-cluster etcd: local: dataDir: /var/lib/etcd extraArgs: listen-metrics-urls: http://0.0.0.0:2381 auto-compaction-retention: "1h" # 每小时压缩wal日志 quota-backend-bytes: "8589934592" # 8GB,防etcd OOM --- apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration nodeRegistration: criSocket: unix:///run/containerd/containerd.sock taints: [] # 移除NoSchedule污点,Master可调度(仅限测试,生产应保留) kubeletExtraArgs: node-labels: "node-role.kubernetes.io/control-plane=true" --- apiVersion: kubeadm.k8s.io/v1beta3 kind: JoinConfiguration controlPlane: localAPIEndpoint: advertiseAddress: 192.168.10.101 # 当前节点IP bindPort: 6443执行命令:
sudo kubeadm init --config kubeadm-config.yaml --upload-certs --certificate-key $(openssl rand -hex 32)关键参数说明:
--upload-certs:将证书上传至etcd,供后续join节点拉取,避免手动分发--certificate-key:32位随机密钥,用于加密证书传输,必须妥善保管--control-plane-endpoint:指向VIP而非单点IP,为高可用铺路
初始化成功后,你会得到kubeadm join命令,其中包含--certificate-key,Worker节点join时需带上此key才能获取证书。
3.4 高可用架构:三Master节点的Keepalived+HAProxy实战
单Master是生产大忌。我们采用Keepalived管理VIP(192.168.10.100),HAProxy做apiserver负载均衡,拓扑如下:
Client → VIP(192.168.10.100) → HAProxy(本机) → apiserver(localhost:6443) ↘ → apiserver(192.168.10.101:6443) → apiserver(192.168.10.102:6443)HAProxy配置(/etc/haproxy/haproxy.cfg):
global log /dev/log local0 chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners user haproxy group haproxy daemon defaults mode http timeout connect 5000 timeout client 50000 timeout server 50000 frontend k8s-apiserver bind *:6443 option tcp-check default_backend k8s-apiserver backend k8s-apiserver option tcp-check tcp-check connect port 6443 tcp-check send-binary 01010000000000000000000000000000 tcp-check expect binary 01010000000000000000000000000000 server master01 192.168.10.101:6443 check server master02 192.168.10.102:6443 check server master03 192.168.10.103:6443 checkKeepalived配置(/etc/keepalived/keepalived.conf):
vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.10.100/24 } }注意:三台Master的priority需错开(100/99/98),确保主备切换有序。HAProxy的tcp-check发送的是HTTP/2 preface字符串,比单纯端口探测更能真实反映apiserver健康状态。
3.5 CNI网络插件:Cilium部署与BPF优化的7个参数
Cilium 1.14.4是当前生产首选,部署命令:
helm install cilium cilium/cilium --version 1.14.4 \ --namespace kube-system \ --set ipam.mode=cluster-pool \ --set cluster.id=1 \ --set cluster.name=prod-cluster \ --set externalIPs.enabled=true \ --set hostServices.enabled=false \ --set nodePort.enabled=true \ --set kubeProxyReplacement=strict \ --set bpf.masquerade=true \ --set tunnel=disabled \ --set autoDirectNodeRoutes=true \ --set hubble.enabled=true \ --set hubble.metrics.enabled="{dns,drop,tcp,flow,icmp,http}" \ --set hubble.listenAddress=":4244"关键参数解读:
externalIPs.enabled=true:启用ExternalIPs功能,满足标题中热搜词需求,允许Service绑定到节点物理IPkubeProxyReplacement=strict:完全替换kube-proxy,所有Service转发由eBPF处理,延迟降低40%tunnel=disabled:关闭VXLAN隧道,直接使用host routing,需确保Pod CIDR与物理网络不冲突autoDirectNodeRoutes=true:自动为每个Node添加直连路由,避免经过网关,提升跨节点通信效率hubble.enabled=true:开启流量可观测性,Hubble UI可图形化展示Pod间通信拓扑
部署后验证:kubectl -n kube-system get pods -l k8s-app=cilium全部Running,且cilium status显示KubeProxyReplacement: Strict。
3.6 CoreDNS调优:从默认8个副本到精准扩缩的决策树
默认CoreDNS配置(10个副本)在小集群中浪费资源,在大集群中又可能成为瓶颈。我们根据集群规模动态调整:
| 节点数 | Pod数 | CoreDNS副本数 | 策略 |
|---|---|---|---|
| <50 | <200 | 2 | 避免DNS查询排队 |
| 50-200 | 200-800 | 4 | 每副本处理200QPS上限 |
| >200 | >800 | 6 | 启用autoscaler,HPA规则:CPU >70%扩容 |
配置文件修改(coredns-configmap):
apiVersion: v1 kind: ConfigMap metadata: name: coredns namespace: kube-system data: Corefile: | .:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf # 关键!指向宿主机DNS,避免循环查询 cache 30 loop reload loadbalance }注意:
forward . /etc/resolv.conf必须存在,否则CoreDNS会尝试递归查询自身,导致无限循环。我们曾因此造成DNS查询超时率达92%。
3.7 Ingress控制器:Nginx Ingress的生产级加固
Nginx Ingress Controller 1.9.5是v1.28兼容的稳定版,部署命令:
helm install ingress-nginx ingress-nginx/ingress-nginx \ --version 4.8.0 \ --namespace ingress-nginx \ --create-namespace \ --set controller.replicaCount=3 \ --set controller.service.type=NodePort \ --set controller.service.nodePorts.http=30080 \ --set controller.service.nodePorts.https=30443 \ --set controller.admissionWebhooks.enabled=false \ --set defaultBackend.enabled=true \ --set controller.metrics.enabled=true \ --set controller.podAnnotations."prometheus\.io/scrape"="true" \ --set controller.podAnnotations."prometheus\.io/port"="10254"生产加固要点:
admissionWebhooks.enabled=false:关闭Validating Webhook,避免集群证书更新时Ingress无法创建service.type=NodePort:不使用LoadBalancer(云厂商SLB成本高),NodePort配合外部LB更可控replicaCount=3:确保Ingress高可用,避免单点故障影响所有HTTP入口
验证:kubectl get svc -n ingress-nginx显示EXTERNAL-IP为<pending>是正常的,NodePort已生效。
3.8 Metrics Server:监控数据采集的精度校准
Metrics Server 0.6.4是v1.28适配版,部署命令:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml但默认配置存在两个问题:
- 证书信任:Metrics Server需访问kubelet HTTPS端口,而kubelet证书由kubeadm签发,需在Metrics Server Deployment中添加
--kubelet-insecure-tls参数(仅限内网环境) - 资源采集精度:默认1分钟采样间隔,在高并发场景下数据毛刺严重,改为30秒
args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=30s # 关键!
验证:kubectl top nodes应返回实时CPU/MEM使用率,延迟<5s。
3.9 集群验证:12项生产就绪检查清单
初始化完成后,执行以下检查(脚本化保存为check-prod-ready.sh):
| 检查项 | 命令 | 合格标准 | 失败处理 |
|---|---|---|---|
| 1. Control Plane健康 | kubectl get componentstatuses | 所有组件Status为Healthy | 检查etcd日志journalctl -u etcd |
| 2. Node Ready状态 | kubectl get nodes -o wide | STATUS=Ready,ROLES=control-plane,worker | kubectl describe node查Conditions |
| 3. DNS解析 | kubectl run dns-test --image=busybox:1.31 --restart=Never --rm -it -- nslookup kubernetes.default | 返回10.96.0.1 | 检查CoreDNS Pod日志 |
| 4. Service连通性 | kubectl expose pod dns-test --port=80 --target-port=80→curl http://<ClusterIP> | 返回404(证明Service可达) | 检查iptables规则iptables -t nat -L KUBE-SERVICES |
| 5. Ingress路由 | kubectl apply -f nginx-ingress-test.yaml→curl http://test.example.com | 返回nginx欢迎页 | 检查Ingress Controller日志 |
| 6. PersistentVolume | kubectl apply -f pv-test.yaml→kubectl get pv,pvc | STATUS=Bound | 检查StorageClass provisioner日志 |
| 7. NetworkPolicy | kubectl apply -f deny-all-policy.yaml→kubectl exec -it busybox -- ping google.com | ping失败 | 检查Cilium policy trace |
| 8. Pod日志 | kubectl logs -l app=nginx | 输出access log | 检查containerd日志轮转 |
| 9. 事件采集 | kubectl get events --sort-by=.lastTimestamp | 最近10分钟有Normal事件 | 检查kube-controller-manager日志 |
| 10. 证书有效期 | openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep "Not After" | 日期≥2034年 | kubeadm certs renew all |
| 11. etcd快照 | ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key snapshot save /tmp/etcd-snapshot.db | 文件大小>10MB | 检查etcd>apiVersion: v1 kind: ServiceAccount metadata: name: app-sa namespace: production --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-role namespace: production rules: - apiGroups: [""] resources: ["pods", "services"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-binding namespace: production subjects: - kind: ServiceAccount name: app-sa namespace: production roleRef: kind: Role name: app-role apiGroup: rbac.authorization.k8s.io PodSecurity Admission:启用v1.28内置的Pod安全准入,强制baseline策略: Cilium NetworkPolicy:禁止所有跨Namespace通信,仅允许必要端口: 3.11 备份与恢复:etcd快照的自动化与验证etcd是集群大脑,备份必须自动化且可验证:
3.12 日志与监控:EFK栈的轻量化落地不堆ELK全家桶,用Fluent Bit + Elasticsearch + Kibana极简组合:
验证: 4. 常见问题与排查技巧实录:那些文档里不会写的坑4.1 “Node NotReady”问题的三级诊断法现象: 一级诊断(网络层): 二级诊断(证书层): 三级诊断(CNI层):
4.2 “Service无法访问”问题的五段式追踪现象:Pod Running,Service创建成功,但 第一段:检查Service Endpoints 第二段:检查kube-proxy规则 第三段:检查Cilium BPF map 第四段:检查Pod网络连通性 第五段:检查NetworkPolicy 4.3 “etcd leader频繁切换”问题的根因分析现象:
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设
2026/9/26 13:08:59
麒麟系统运行Windows程序:Box64+Wine+定制Prefix实战指南1. 项目概述:在麒麟操作系统上跑Windows程序,不是“装个Wine就完事”的事我从2018年开始在国产化信创环境中做桌面应用适配,最早一批接触的就是银河麒麟V4和中标麒麟,后来全程跟进V10的生态建设。这几年给二十多家政企单位做过办公…
网站建设
2026/9/26 13:08:32
基于YALMIP的电热联合微电网优化建模与MATLAB实现做微电网优化的人基本都遇到过同一个问题,光伏和风电出力看天吃饭,电负荷和热负荷又各自波动,CHP机组、电锅炉、储能电池、蓄热罐一堆设备摆在那儿,到底让谁出力、出多少、什么时候充放,才能把一天下来的总运行成本压到…
网站建设
2026/9/26 13:08:15
7个可落地的AI Agent实战项目:突破状态管理、任务分解与人机协作瓶颈1. 这不是一场“直播带货”,而是一次AI Agent能力边界的现场测绘“今晚8点,免费解锁7个AI Agent实战项目!仅开放2小时”——这句话在最近两周高频出现在多个技术社群、知识付费渠道和开发者私域流量池里。它不像传统课程推广那样强调“系统学…
网站建设
2026/9/26 13:07:54
用 requests 爬了 Steam 畅销榜 3000 条评论后,我把反爬策略和 TaoToken 配置一起整理成了骨架/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …
网站建设
2026/9/26 13:07:04
实战迁移:从 Skill 到 MCP Server,用 TaoToken 统一 Key 打造跨平台 AI 能力集/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …
网站建设
2026/9/26 13:06:49
用A4纸草图加豆包,二十分钟零代码生成可交互网页先把丑话说在前面:这标题不是我吹的,是真事。上周我坐在电脑前想做一个活动报名页,琢磨了半天连 HTML 是啥都记不全。后来实在没辙,从打印机里抽了张 A4 纸,拿笔画了个粗糙的页面框架,拍成照片扔给豆包&… |