1. K8s基础概念回顾与常见误区
在开始深入探讨Kubernetes(简称K8s)的进阶问题前,有必要先梳理几个核心概念。K8s作为容器编排的事实标准,其设计哲学围绕"声明式API"和"控制器模式"展开。Pod作为最小调度单元,实际上是一个逻辑主机,可以包含一个或多个紧密耦合的容器。初学者常犯的错误是将Pod等同于容器,实际上Pod提供了共享网络命名空间和存储卷的环境。
Deployment和StatefulSet的区别是面试中的高频问题。前者适合无状态应用,支持滚动更新和回滚;后者则为有状态服务提供稳定的网络标识和持久化存储。我曾见过团队将MySQL部署为Deployment导致数据丢失的案例,这就是典型的概念混淆。
另一个常见误区是对Service类型的理解。ClusterIP、NodePort和LoadBalancer不是互斥选项,而是层层递进的关系。LoadBalancer实际是在NodePort基础上集成云厂商的负载均衡器。在内网环境中,Ingress配合ClusterIP往往比直接暴露NodePort更安全。
2. 调度机制深度解析
kube-scheduler的决策过程涉及两个阶段:过滤(Predicates)和打分(Priorities)。过滤阶段会排除不符合硬性条件的节点(如资源不足),而打分阶段则通过算法计算节点得分。我们可以通过自定义调度器或扩展调度策略来满足特殊需求。
资源请求(requests)和限制(limits)的设置直接影响调度结果。requests是调度依据,而limits是运行时约束。一个常见陷阱是只设置limits而忽略requests,这会导致Pod处于Burstable QoS等级,在节点资源紧张时可能被首先驱逐。
节点亲和性(nodeAffinity)和Pod亲和性(podAffinity)提供了更精细的调度控制。我曾用podAffinity将日志收集器与业务Pod部署在同一节点,减少跨节点网络开销。反亲和性(anti-affinity)则常用于实现高可用,避免单点故障。
3. 网络模型实战问题
K8s网络必须满足两个基本要求:所有Pod可以不经过NAT相互通信,节点可以与所有Pod通信。实现这一模型的方式因CNI插件而异,Calico、Flannel和Cilium各有特点。Calico基于BGP协议适合大规模集群,而Flannel的VXLAN模式更简单但性能略低。
Service的ClusterIP是个虚拟IP,由kube-proxy通过iptables或ipvs实现负载均衡。当遇到Service无法访问时,我通常会按以下步骤排查:
- 检查Endpoint是否包含预期PodIP
- 验证kube-proxy是否生成正确规则
- 测试Pod间直接通信
- 检查网络插件日志
Ingress控制器需要特别注意版本兼容性。Nginx Ingress的注解在v1和v2版本有重大变化,我曾因此导致灰度发布功能失效。建议在YAML中明确指定IngressClass,避免默认控制器冲突。
4. 存储方案选型指南
PersistentVolume(PV)和PersistentVolumeClaim(PVC)将存储细节与应用解耦。动态供给(StorageClass)极大简化了流程,但需要注意回收策略。Delete策略会随PVC删除而销毁数据,Retain则保留PV手动清理。
本地存储(local volume)适合高性能需求但缺乏动态供给能力。使用时要通过节点亲和性确保Pod调度到正确节点。一个替代方案是OpenEBS这样的容器化存储,它能在每个节点部署存储引擎。
StatefulSet的有序部署特性对数据库类应用至关重要。配合Headless Service可以为每个Pod提供稳定的DNS记录。我曾用这种方案实现Redis集群的自动化部署,初始容器通过DNS发现同伴组建集群。
5. 安全防护最佳实践
Role-Based Access Control(RBAC)是安全基线的第一步。遵循最小权限原则,避免滥用cluster-admin。ServiceAccount也应该被赋予精确权限,特别是第三方工具使用的账户。
PodSecurityPolicy(PSP)虽然即将被PodSecurity替代,但目前仍是限制特权容器的重要手段。建议强制要求:
- 禁止特权模式(privileged: false)
- 只读根文件系统(readOnlyRootFilesystem: true)
- 丢弃所有内核能力(drop: ["ALL"])
网络策略(NetworkPolicy)实现了微隔离。默认拒绝所有流量,然后按需开放。例如只允许前端Pod访问后端服务的特定端口。Cilium还支持L7层策略,可以限制HTTP方法路径。
6. 运维排错经验分享
kubectl debug是排查问题的利器。通过临时容器共享故障Pod的命名空间,可以检查网络、文件系统等状态。相比直接登录节点,这种方式更安全且可审计。
事件监控是发现异常的窗口。结合kubectl get events -w和Prometheus警报,可以快速定位资源不足、调度失败等问题。我习惯为关键应用配置PDB(PodDisruptionBudget),防止维护操作导致服务中断。
日志收集方案需要权衡性能和成本。EFK栈(Elasticsearch+Fluentd+Kibana)适合大规模集群,但资源消耗较大。轻量级方案可以用Loki替代Elasticsearch,通过标签索引提高查询效率。
7. 版本升级与生态工具
Kubernetes每季度发布新版本,支持周期约1年。升级前务必检查API废弃通知,特别是像extensions/v1beta1这种长期废弃的API。kubeadm upgrade plan会列出需要手动迁移的工作负载。
Helm仍然是包管理的事实标准,但要注意模板中的安全上下文设置。Kustomize的声明式覆盖更适合GitOps流程。我推荐将两者结合:用Helm获取社区图表,再用Kustomize做环境定制。
Operator模式逐渐成为管理有状态应用的标准方式。编写自定义Operator时,注意控制reconcile频率,避免API服务器过载。Kubebuilder和OperatorSDK都提供了良好的脚手架。