Kubernetes 开源9年,但我们已经有了 8 年的踩坑血泪史
内容提要
这篇文章分享了作者在使用Kubernetes过程中的经验教训,包括早期决策、自托管集群的经历和集群崩溃的教训。作者还提供了关于Kubernetes的安全性、可观察性和最佳实践的建议。
延伸解读
自托管与托管服务的权衡
文章提到,团队早期在 AWS 上自托管 Kubernetes,但遭遇了集群崩溃,后来迁移到 Azure Kubernetes Service (AKS) 后,发现托管解决方案更高效,且与 Azure 服务集成更方便。对于小团队而言,自托管需要持续的关注和维护,增加了工作量,而托管服务可以节省控制平面节点的费用,并利用云提供商的基础设施。因此,在资源有限的情况下,托管服务可能是更优选择。
证书管理:不容忽视的细节
作者经历了两次因证书过期导致的集群崩溃,第一次是因为根 CA、etcd 和 API 服务器证书过期,第二次是因为 kube-aws 的 bug 导致 etcd 证书过期时间被设置为默认一年。这提醒我们,必须熟悉 Kubernetes 内部证书及其过期日期,并建立监控和更新机制,避免因证书问题导致集群不可用。
灾难恢复与密钥备份的必要性
第一次集群崩溃后,团队不得不从头重建集群,但发现并非所有服务和配置都存储在 git 中,导致恢复过程艰难。因此,制定灾难恢复计划并定期测试至关重要,同时要备份和存储密钥,因为集群消失时密钥也会丢失。文章建议使用 shell 脚本或 Terraform 等工具来自动化集群重建过程。
安全与可观察性的实践建议
在安全方面,Kubernetes 默认没有过度限制,需要实施最小权限原则、只读根文件系统、禁用权限升级等措施,并使用 Azure Policy 和 Gatekeeper 确保容器安全。在可观察性方面,监控资源使用、设置告警到 Slack、整合日志并部署跟踪 ID 策略(如 OpenTelemetry)是关键,团队花了 2-3 年才做好日志整合,早期实施可节省大量时间。
Q&A
Urb-it 为什么早期就决定使用 Kubernetes?
Urb-it 早期决定使用 Kubernetes 作为云原生战略的基石,主要是为了应对快速增长的预期,利用容器编排功能为应用程序带来更动态、弹性和高效的环境,并且 Kubernetes 非常适合他们的微服务架构。
Urb-it 从自托管 Kubernetes 迁移到 AKS 的原因是什么?
迁移到 AKS 是因为托管解决方案比自托管更高效,且与 Azure 服务集成更方便。他们已经在使用 Azure Service Bus、Azure SQL Server 等服务,迁移后可以更轻松地集合使用这些服务,并利用 Azure 的主干网络基础设施,省去与离开/进入外部网络和 VNET 相关的成本。此外,许多工程师熟悉 Azure 生态系统,且 AKS 初始设置不必为控制平面节点付费。
Urb-it 经历的两次集群崩溃的原因分别是什么?
第一次集群崩溃是由于根 CA 证书、etcd 证书、API 服务器证书都过期,导致集群停止工作、无法管理。第二次集群崩溃同样是由于证书问题:在从第一次崩溃重建集群时,使用的 kube-aws 版本存在 bug,没有将 etcd 证书的过期时间设置为提供的过期日期,而是使用了一年默认值,导致一年后证书过期。
Urb-it 在 Kubernetes 安全性方面采取了哪些措施?
他们投入大量时间加强访问控制,为 Pod 和容器实施最小权限原则;设置只读根文件系统,禁用服务帐户令牌自动挂载,禁用权限升级,删除不必要的功能;使用 Azure Policy 和 Gatekeeper 确保没有部署不安全的容器;利用基于角色的访问控制(RBAC)增强安全性和访问管理;使用 Azure Defender 和 Azure Defender for Containers 扫描容器漏洞。
Urb-it 如何确保 Kubernetes 集群的可观察性?
他们持续跟踪内存、CPU 等资源使用情况以观测集群性能;将所有告警定向到 Slack 频道;将所有日志整合到一处,并部署强大的跟踪 ID 策略(如 OpenTelemetry)。他们开始使用 Loggly 和 FluentD 做集中式日志记录,后来转向 Elastic 和 Kibana(ELK 堆栈)。
Urb-it 在成本优化方面有哪些经验?
他们发现使用更少但更大的节点类型有益,因为 AKS 会根据节点类型保留大约 10-30% 的可用内存用于内部服务。选择具有高效 IO 性能的节点类型,并确保节点磁盘/缓存大小至少与配置的总节点磁盘大小相同。此外,保留关键实例一两年可以节省大量成本,与现收现付相比可节省 50-60%。
Urb-it 在灾难恢复方面有什么建议?
他们强调一定要提前做好准备方案,以便在需要时重新创建集群。可以使用 shell 脚本、Terraform 或 Crossplane 等工具。他们由于团队带宽有限,选择存储和使用 shell 脚本。无论选择哪种方法,务必不时测试流程,确保可以在需要时重新创建集群。此外,要制定备份和存储密钥的策略,因为如果集群消失,所有密钥也会消失。
Urb-it 如何处理 Kubernetes 和 Helm 的版本更新?
他们总是等待几个月才升级到最新版本,等其他人先遇到新版本的问题。但即使第一时间更新,由于 Kubernetes 和 Helm 的新版本总会有变化,他们还是会面临许多耗时的配置文件和图表重写工作。为了减少工作量,他们采用了集中管理 Helm 图表的方法,使用“一个图表搞定一切”的方法。