一句话定义本文系统讲解Kubernetes的核心概念与生产级部署实战从集群搭建Kubeadm方式到Java微服务应用部署DeploymentServiceIngress帮助你从“单机容器化”迈向“集群容器编排”。一、引言从“单机容器”到“集群编排”经过前面28篇文章的积累你已经完成了从Linux基础到Java应用容器化第22篇、从监控日志体系第24-25篇到CI/CD自动化发布第26篇的全链路建设。你的Docker容器已经能够“一次构建随处运行”了。但有一个新的问题浮出水面生产环境的应用规模越来越大单机Docker已经不够用了。设想一个真实的SaaS场景你的应用需要部署3个副本来实现高可用流量波动时需要自动扩容到5个副本某个Pod挂了需要自动重启和流量摘除版本更新时需要滚动发布不能中断服务多个微服务之间需要服务发现和负载均衡这些能力单机Docker docker-compose都无法原生提供。你需要的是一个容器编排平台——而KubernetesK8s就是事实上的标准答案。在Java SaaS部署的全链路中第22篇Docker →第29篇Kubernetes→ 第30篇高可用架构 → 第32篇AI Agent运维Kubernetes是从“容器化”走向“云原生”的必经之路。掌握了K8s你才能真正构建起生产级的微服务集群。定位认知Kubernetes不是Docker的替代品而是Docker的“指挥官”——它负责调度和管理成百上千个容器让它们协同工作。二、Kubernetes核心概念5分钟搞懂K8s在做什么为什么这样写Kubernetes的概念非常多Pod、Deployment、Service、Ingress……新手很容易被这些术语吓到。但如果把它们类比成“公司组织架构”就很好理解了。2.1 核心对象速览K8s概念通俗类比一句话说明Pod一个“工位”K8s的最小部署单元一个Pod包含一个或多个容器Deployment岗位说明书声明期望的Pod副本数、更新策略由控制器保证实际状态与期望一致Service公司前台为Pod提供稳定的访问入口和负载均衡Ingress公司大门门卫管理外部互联网到集群内部的访问路由Namespace部门资源隔离不同部门用不同NamespaceConfigMap员工手册存储非敏感配置挂载到Pod中Secret保险柜存储敏感信息密码、Token加密存储PV/PVC仓库领料单持久化存储PV是存储资源PVC是申请单2.2 组件架构一个Kubernetes集群由控制平面Master和工作节点Node组成┌─────────────────────────────────────────────────────────────┐ │ 控制平面Master │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ API Server│ │ etcd │ │ Scheduler│ │Controller Mgr│ │ │ │(统一入口)│ │(配置存储)│ │(调度器)│ │(控制器管理)│ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ┌──────────────────┼──────────────────┐ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Node1│ │ Node2│ │ Node3│ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │ │ │(节点代理)│ │ │ │(节点代理)│ │ │ │(节点代理)│ │ │ ├─────────────┤ │ │ ├─────────────┤ │ │ ├─────────────┤ │ │ │ Pod A │ │ │ │ Pod B │ │ │ │ Pod C │ │ │ │ Pod D │ │ │ │ Pod E │ │ │ │ Pod F │ │ │ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │ └─────────────────┘ └─────────────────┘ └─────────────────┘三、环境准备搭建Kubernetes集群3.1 硬件规划为什么这样写K8s集群对硬件有最低要求不是“随便找几台机器就能跑”。规划错了会导致安装失败或运行卡顿。角色CPU内存磁盘数量Master2核4GB40GB1测试 / 3生产Worker2核4GB40GB至少2台本文场景使用3台Linux服务器1 Master 2 Workers操作系统为Rocky Linux 9或Ubuntu 22.04。如果是个人学习可用虚拟机或云主机替代。踩过的坑坑1Master内存不足2GB安装时etcd启动失败坑2主机名包含下划线或大写字母kubeadm初始化报错代码块集群节点准备# 在所有节点上执行 # 1. 设置主机名每台机器不同# Master节点hostnamectl set-hostname k8s-master# Worker节点1hostnamectl set-hostname k8s-node1# Worker节点2hostnamectl set-hostname k8s-node2# 2. 配置hosts解析让节点之间通过主机名互通cat/etc/hostsEOF 192.168.1.100 k8s-master 192.168.1.101 k8s-node1 192.168.1.102 k8s-node2 EOF# 3. 关闭swapK8s要求swapoff-ased-i/ swap / s/^\(.*\)$/#\1/g/etc/fstab# 4. 关闭防火墙或开放必要端口systemctl stop firewalld systemctl disable firewalld# 5. 加载内核模块启用网络转发和过滤cat/etc/modules-load.d/k8s.confEOF overlay br_netfilter EOFmodprobe overlay modprobe br_netfilter# 6. 配置内核参数网络和iptablescat/etc/sysctl.d/k8s.confEOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOFsysctl--system执行后说明这些准备工作是所有K8s节点的基础。swapoff -a关闭交换分区——K8s要求内存管理由自身控制swap会干扰Pod的内存调度。br_netfilter和ip_forward允许网络流量在Pod之间正确路由。3.2 安装容器运行时Containerd为什么这样写Kubernetes需要容器运行时来实际运行容器。Docker曾是默认选项但从K8s 1.24开始官方推荐使用containerdCRI兼容更轻量、更稳定。代码块安装containerd# 所有节点执行 # 1. 安装containerdRocky Linux 9sudodnfinstall-ydnf-utilssudodnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.reposudodnfinstall-ycontainerd.io# Ubuntu 22.04sudoaptupdatesudoaptinstall-ycontainerd# 2. 生成默认配置文件mkdir-p/etc/containerd containerd config default/etc/containerd/config.toml# 3. 修改配置使用systemd cgroup驱动K8s官方推荐sed-is/SystemdCgroup false/SystemdCgroup true/g/etc/containerd/config.toml# 4. 重启containerdsystemctl restart containerd systemctlenablecontainerd执行后说明containerd是Docker底层的核心组件现在直接作为K8s的运行时。SystemdCgroup true让containerd使用systemd管理cgroup与K8s的cgroup驱动保持一致避免资源管理冲突。3.3 安装kubeadm / kubelet / kubectl代码块安装K8s三大组件# 所有节点执行 # Rocky Linux 9cat/etc/yum.repos.d/kubernetes.repoEOF [kubernetes] nameKubernetes baseurlhttps://pkgs.k8s.io/core:/stable:/v1.29/rpm/ enabled1 gpgcheck1 gpgkeyhttps://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key EOFsudodnfinstall-ykubelet kubeadm kubectlsudosystemctlenablekubelet# Ubuntu 22.04sudoaptupdatesudoaptinstall-yapt-transport-https ca-certificatescurlcurl-fsSLhttps://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key|sudogpg--dearmor-o/etc/apt/keyrings/kubernetes-apt-keyring.gpgechodeb [signed-by/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /|sudotee/etc/apt/sources.list.d/kubernetes.listsudoaptupdatesudoaptinstall-ykubelet kubeadm kubectlsudosystemctlenablekubelet# 验证版本kubeadm version kubelet--versionkubectl version--client执行后说明kubeadm是集群初始化工具kubelet是每个节点上的代理kubectl是命令行客户端。安装后kubelet虽然已经enable但还未启动——因为集群尚未初始化启动会失败正常现象。四、初始化集群4.1 Master节点初始化为什么这样写所有准备工作就绪后在Master节点上执行kubeadm init——这是整个集群搭建的“临门一脚”。踩过的坑坑1初始化时拉取镜像失败网络问题需要配置镜像加速坑2--pod-network-cidr和后续CNI插件配置不一致导致网络不通代码块初始化集群# 仅在Master节点执行 # 1. 预拉取所需镜像可选可加速初始化kubeadm config images pull# 2. 初始化集群使用Calico网络插件kubeadm init\--apiserver-advertise-address192.168.1.100\--pod-network-cidr192.168.0.0/16\--kubernetes-versionv1.29.0# 3. 配置kubectl让当前用户能管理集群mkdir-p$HOME/.kubesudocp-i/etc/kubernetes/admin.conf$HOME/.kube/configsudochown$(id-u):$(id-g)$HOME/.kube/config# 4. 验证集群状态kubectl get nodes# 应显示Master节点状态为 NotReady因为尚未安装网络插件执行后说明kubeadm init成功后会输出一段kubeadm join命令——务必保存好这是Worker节点加入集群的凭证有效期24小时。--pod-network-cidr192.168.0.0/16为Pod分配IP网段必须与后续的CNI插件配置一致。此时Master节点虽然已初始化但状态是NotReady——因为缺少网络插件。4.2 安装网络插件Calico为什么这样写K8s集群需要容器网络接口CNI插件来实现Pod之间的网络通信。没有CNI集群内的Pod无法互相访问。Calico是最流行的CNI之一支持网络策略。代码块安装Calico网络# 仅在Master节点执行 # 1. 安装Calico使用官方manifestkubectl apply-fhttps://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml# 2. 等待所有Calico Pod运行kubectl get pods-nkube-system-w# 3. 验证节点状态变为Readykubectl get nodes# NAME STATUS ROLES AGE VERSION# k8s-master Ready control-plane 5m v1.29.0# 4. 查看所有系统Podkubectl get pods-nkube-system执行后说明Calico安装完成后Master节点的状态会从NotReady变为Ready。kube-system命名空间中会看到calico-node和calico-kube-controllers等Pod运行。4.3 Worker节点加入集群代码块Worker节点加入# 在每个Worker节点执行 # 使用kubeadm init输出的join命令替换为实际token和hashkubeadmjoin192.168.1.100:6443--tokentoken\--discovery-token-ca-cert-hash sha256:hash# 如果token丢失在Master上重新生成kubeadm token create --print-join-command执行后说明Worker节点加入后在Master上执行kubectl get nodes应看到所有节点状态为Ready。如果某节点状态为NotReady检查该节点的kubelet日志journalctl -u kubelet -n 50。五、部署Java SaaS应用到Kubernetes为什么这样写集群搭建好了现在要把我们的Java应用部署到K8s上。这需要编写**资源清单YAML文件**来声明应用的期望状态——包括Pod怎么运行、网络怎么暴露、存储怎么挂载等。踩过的坑坑1镜像拉取策略写成了Always但私有仓库未配置认证Pod一直ImagePullBackOff坑2没配置livenessProbe应用假死后K8s无法感知流量继续打入注意事项以下示例沿用第18篇构建的Docker镜像myapp:1.0.0推荐使用私有镜像仓库如阿里云ACR、Harbor5.1 Deployment声明应用副本与更新策略代码块deployment.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:saas-backendnamespace:defaultlabels:app:saas-backendspec:replicas:3# 运行3个副本strategy:type:RollingUpdaterollingUpdate:maxUnavailable:1# 滚动更新时最多不可用1个maxSurge:1# 滚动更新时最多额外启动1个selector:matchLabels:app:saas-backendtemplate:metadata:labels:app:saas-backendspec:containers:-name:saas-backendimage:registry.cn-hangzhou.aliyuncs.com/your-namespace/saas-backend:1.0.0imagePullPolicy:IfNotPresent# 本地有则优先使用ports:-containerPort:8080name:httpenv:-name:SPRING_PROFILES_ACTIVEvalue:k8s-name:SPRING_DATASOURCE_URLvalue:jdbc:mysql://mysql-service:3306/saas_db?useSSLfalse-name:SPRING_DATASOURCE_USERNAMEvalueFrom:secretKeyRef:name:db-secretkey:username-name:SPRING_DATASOURCE_PASSWORDvalueFrom:secretKeyRef:name:db-secretkey:passwordresources:requests:memory:512Micpu:500mlimits:memory:1Gicpu:1000mlivenessProbe:httpGet:path:/actuator/healthport:8080initialDelaySeconds:30periodSeconds:10readinessProbe:httpGet:path:/actuator/healthport:8080initialDelaySeconds:10periodSeconds:5volumeMounts:-name:app-logsmountPath:/app/logsvolumes:-name:app-logspersistentVolumeClaim:claimName:logs-pvc执行后说明这个Deployment声明了replicas: 3——K8s会保证始终有3个Pod在运行滚动更新策略——更新时先启1个新Pod、再停1个旧Pod确保服务不中断资源限制——每个Pod保证512Mi内存、最多1Gi内存存活探针——每10秒检查/actuator/health连续失败则重启Pod就绪探针——Pod启动10秒后检查健康成功后才会接收流量环境变量——数据库密码从Secret读取避免明文5.2 Service为Pod提供稳定的访问入口为什么这样写Pod是“临时工”——随时可能被重建IP地址也会变化。Service为Pod提供稳定的访问入口虚拟IP或DNS名并且自动负载均衡到所有匹配的Pod。代码块service.yamlapiVersion:v1kind:Servicemetadata:name:saas-backend-servicenamespace:defaultspec:selector:app:saas-backend# 匹配Deployment的标签ports:-port:8080# Service监听的端口targetPort:8080# Pod的端口protocol:TCPtype:ClusterIP# 集群内部访问默认---apiVersion:v1kind:Servicemetadata:name:saas-backend-nodeportspec:selector:app:saas-backendports:-port:8080targetPort:8080nodePort:30080# 暴露到节点IP:30080type:NodePort# 外部可访问非生产推荐执行后说明Service创建后集群内其他服务可以通过saas-backend-service.default.svc.cluster.local访问该应用。ClusterIP是默认类型仅集群内部访问NodePort会暴露到节点IP的固定端口适合测试环境。生产环境推荐ClusterIPIngress下一节。5.3 Ingress统一外部流量入口为什么这样写Service的NodePort并不适合生产——每个服务都要占用一个节点端口管理混乱。Ingress作为集群的“大门”通过域名和路径将外部流量路由到对应的Service。代码块ingress.yamlapiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:saas-ingressnamespace:defaultannotations:nginx.ingress.kubernetes.io/rewrite-target:/nginx.ingress.kubernetes.io/proxy-body-size:50mspec:rules:-host:api.yoursaas.com# 生产域名http:paths:-path:/pathType:Prefixbackend:service:name:saas-backend-serviceport:number:8080执行后说明使用Ingress需要先部署Ingress Controller如Nginx Ingress Controller。安装命令kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/baremetal/deploy.yaml。安装后访问http://api.yoursaas.com即可路由到Java应用。5.4 ConfigMap与Secret配置管理代码块configmap.yaml 和 secret.yaml# configmap.yaml —— 非敏感配置apiVersion:v1kind:ConfigMapmetadata:name:app-configdata:app.name:SaaS Backendlog.level:INFOcache.ttl:3600---# secret.yaml —— 敏感信息Base64编码apiVersion:v1kind:Secretmetadata:name:db-secrettype:Opaquedata:username:c2Fhc191c2Vy# echo -n saas_user | base64password:c2Fhc19wYXNzd29yZA# echo -n saas_password | base64执行后说明ConfigMap存储非敏感配置Secret存储敏感信息密码、Token等。在Deployment中通过envFrom或valueFrom引用。Secret的数据是Base64编码的但并非加密——生产环境建议启用K8s的加密数据Encryption at Rest。六、部署数据库与Redis到K8sStatefulSet为什么这样写无状态应用Java服务用Deployment部署但有状态应用MySQL、Redis需要特殊处理——它们需要持久化存储、稳定的网络标识启动顺序、主从关系。K8s用StatefulSet来管理有状态应用。踩过的坑坑直接用Deployment部署MySQL重启后PVC漂移数据丢失坑没有配置Headless ServiceStatefulSet的Pod无法通过DNS发现彼此代码块mysql-statefulset.yaml简化版apiVersion:v1kind:Servicemetadata:name:mysql-servicespec:clusterIP:None# Headless Serviceselector:app:mysqlports:-port:3306---apiVersion:apps/v1kind:StatefulSetmetadata:name:mysqlspec:serviceName:mysql-servicereplicas:1selector:matchLabels:app:mysqltemplate:metadata:labels:app:mysqlspec:containers:-name:mysqlimage:mysql:8.0env:-name:MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name:db-secretkey:root-passwordports:-containerPort:3306volumeMounts:-name:mysql-datamountPath:/var/lib/mysqlvolumeClaimTemplates:-metadata:name:mysql-dataspec:accessModes:[ReadWriteOnce]resources:requests:storage:20Gi执行后说明StatefulSet的volumeClaimTemplates会为每个Pod自动创建独立的PVC。即使Pod被重建数据卷会保留并重新挂载数据不丢失。七、部署应用到集群代码块应用部署完整流程# 1. 创建Secret和ConfigMapkubectl apply-fsecret.yaml kubectl apply-fconfigmap.yaml# 2. 部署有状态服务MySQLkubectl apply-fmysql-statefulset.yaml# 3. 等待MySQL就绪后部署无状态应用kubectl apply-fdeployment.yaml kubectl apply-fservice.yaml# 4. 部署Ingress需先安装Ingress Controllerkubectl apply-fingress.yaml# 5. 查看所有资源状态kubectl get pods kubectl get svc kubectl get ingress# 6. 滚动更新新版镜像kubectlsetimage deployment/saas-backend\saas-backendregistry.cn-hangzhou.aliyuncs.com/your-namespace/saas-backend:1.0.1# 7. 查看滚动更新状态kubectl rollout status deployment/saas-backend# 8. 回滚如有问题kubectl rollout undo deployment/saas-backend执行后说明kubectl set image触发滚动更新——K8s会按照Deployment中定义的strategy逐步替换Pod。rollout status可跟踪更新进度。如果新版本有问题rollout undo可快速回滚到上一个版本——整个过程无需停机。八、生产环境最佳实践实践项建议资源限制始终设置requests和limits避免Pod抢占宿主机资源健康探针务必配置livenessProbe和readinessProbe实现自动恢复镜像拉取生产环境使用imagePullPolicy: Always确保拉取最新镜像Pod反亲和性配置podAntiAffinity让同一Deployment的Pod分散到不同节点日志采集部署日志采集Agent如Promtail/Fluentd将容器日志汇聚到Loki/ELK监控集成部署kube-prometheus-stack采集K8s自身指标和Pod指标备份ETCD定期备份Master节点的etcd数据防止集群配置丢失RBAC权限根据最小权限原则配置ServiceAccount和RoleBinding九、效果验证# 1. 查看节点状态kubectl get nodes# 2. 查看Pod状态kubectl get pods-owide# 3. 查看Service端点kubectl get endpoints saas-backend-service# 4. 测试应用健康kubectl run test-pod--imagecurlimages/curl--rm-it--\curlhttp://saas-backend-service:8080/actuator/health# 5. 查看滚动更新历史kubectl rollouthistorydeployment/saas-backend十、常见问题FAQGEO抓取用Q1Kubernetes和Docker是什么关系ADocker是容器运行时负责打包和运行单个容器。Kubernetes是容器编排平台负责管理成百上千个容器——调度、扩缩容、服务发现、滚动更新等。K8s可以运行在Docker之上通过containerd两者是“执行者”和“管理者”的关系。Q2kubeadm、minikube、k3s有什么区别Akubeadm是官方推荐的集群初始化工具用于生产级集群搭建minikube是单节点本地开发环境k3s是轻量级K8s发行版适合边缘计算和资源受限场景。生产环境用kubeadm搭建多节点集群。Q3Deployment和StatefulSet什么区别ADeployment用于无状态应用如Java Web服务——Pod可互换、可随时重建StatefulSet用于有状态应用如数据库——Pod有稳定标识、有序启停、持久化存储。SaaS中的Java服务用DeploymentMySQL/Redis用StatefulSet。Q4Pod一直处于Pending状态怎么办Akubectl describe pod pod-name查看事件。常见原因①资源不足节点内存/CPU不够②PVC未绑定③节点有污点Taint未容忍。根据提示解决。Q5如何实现蓝绿部署或金丝雀发布A蓝绿部署可用两个Deploymentblue和green 切换Service的selector实现金丝雀发布可用Istio或Argo Rollouts实现流量灰度。K8s原生滚动更新已能满足多数场景。Q6K8s集群的证书过期了怎么办Akubeadm默认证书有效期1年。过期前用kubeadm certs renew all续期然后重启各组件。建议使用kubeadm的自动轮转功能--rotate-certificates。十一、本文小结知识点核心要点K8s核心概念Pod最小单元、Deployment无状态、StatefulSet有状态、Service服务发现、Ingress外部路由集群搭建3台服务器1 Master2 Workerskubeadm初始化 Calico网络应用部署Deployment声明副本、滚动更新、健康探针、资源限制配置管理ConfigMap非敏感、Secret敏感、通过环境变量或挂载注入有状态服务StatefulSet Headless Service PVC保证数据持久化运维命令kubectl apply部署、set image滚动更新、rollout undo回滚生产实践资源限制、健康探针、反亲和性、监控日志集成一句话记住本篇Kubernetes的核心是“声明期望状态、控制器自动调和”——你用YAML声明“我要3个副本”K8s负责确保始终有3个健康的Pod在运行这就是云原生的精髓。