Increment 采访了 Datadog、Braze 和 BetterUp 的工程负责人,讨论了容器工具、测试和监控,以及他们如何处理容器迁移的问题。
嘉宾介绍:
劳伦·伯纳耶(Laurent Bernaille):DataDog 高级工程师。
克里斯·罗格斯(Chris Rogus):Braze 工程总监。
布莱恩·希克森(Bryan Hickerson):BetterUp 工程经理。
Q:贵组织使用哪些容器技术和工具?
劳伦·伯纳耶:主要容器技术有 Kubernetes、containerd 和 Cilium。我们在多个云供应商上运行了数十个不同规模的 Kubernetes 集群:我们最大的集群每个都有 4000 多个节点,而且我们依赖内部开发的工具来管理和编排多个集群的部署。
克里斯·罗格斯:我们在 AWS 和 Azure 中使用 Kubernetes,运行 Ruby on Rails、Java、Go 和 Python 中的 dockerized 应用程序。Kubernetes 会将度量报告给 Datadog,将日志报告给 Papertrail,而应用程序的错误会转到 Sentry。通过使用 Terraform 定义 Kubernetes 在不同云中部署的基础设施,我们使用 Sops 进行秘密配置。
布莱恩·希克森:我们使用 Heroku,它采用了称为 dynos 的轻量级容器,用于我们的网络服务器、后台作业以及机器学习微服务的一个子集。其他机器学习微服务使用 Kubeflow。利用 Docker,我们可以将开发和测试环境与生产环境保持一致。我们使用 SolarWinds Papertrail 和 Sumo Logic。对于客户端和应用程序的错误报告,我们使用 Sentry。最后,在性能监控方面,我们使用了 Scout 和 Calibre。
Q:贵组织何时开始使用容器,以及它们如何改变开发工作流程?
劳伦·伯纳耶:从 2018 年初开始,Datadog 迁移到 Kubernetes,大约 6 个月之后,DataDog 的第一个版本就完全在 Kubernetes 上运行和生产了。其中包括无状态网络应用和有状态数据服务,如 Cassandra 和 Kafka。我们从用 Chef 管理的虚拟机中运行的应用程序迁移过来,因此这一过渡要求对开发流程进行很多更改。举例来说,我们必须将每个应用程序容器化,并提供一种可以部署到 Kubernetes 集群的解决方案,该方案最初依赖于 Spinnaker 和 Helm 图表。迁移是一个挑战。这个截止日期很有挑战性,我们将从一个没有容器、也没有工具来部署容器的环境开始。但是这样做也很有意义,因为它为我们提供了统一的打包和部署解决方案,使我们能够部署到新的云供应商和地区。
克里斯·罗格斯:大约两年前,我们开始在多云环境中使用容器。经过近一年的初步探索,最初,容器会增加一些复杂性,尤其是在配置方面,但是,当我们构建工具时,某些方面会变得更加简单。举例来说,Chef 要求更严格的权限才能对配置进行修改。把 Chef 数据包的配置改成 Sops,我们给开发者带来了更简单的自助式更改。
布莱恩·希克森:2015 年以前,我们使用基于虚拟机的开发环境,后来由于本地编译的原生依赖性带来的挑战,常常导致升级失败,从而改用容器。转换为容器之后,我们就可以做到无缝地迁移,而不会对开发工作流程造成负面影响。这也使我们的开发环境更加现代化,更接近于生产环境,并且降低了资源的密度。
Q:贵组织是否将任何遗留的应用程序迁移到容器中?挑战是什么,学到了什么?
劳伦·伯纳耶:我们大多数应用程序都是用 Go、Python 和 Java 编写的,因此在容器中运行它们并不困难。问题当然是在细节上,我们面临着一些挑战,包括在容器中管理 JVM 占用的内存。大部分应用程序都认为它们只在虚拟机上运行,这就给它们自己提出了挑战:尤其是 IO 操作(磁盘和网络访问),因为 Kubernetes 在共享 CPU 时间和内存方面效率很高。Kubernetes 提供了更少的控制来限制和隔离资源消耗,IO 方面则更为复杂。在将应用程序迁移到 Kubernetes 之后,我们注意到需要两倍的主机数量。在剖析了应用程序并分析了开销之后,我们就对 pod 配置进行了优化,从而大大减少了需要的额外主机数。
克里斯·罗格斯:实际上,我们已将所有遗留应用程序迁移到容器。将应用程序 Docker 化是相对直接的,在大多数情况下,可以更轻松地打包依赖项和部署。在此之前,DevOps 管理 EC2 实例,将应用程序复制到 Chef 并通过 Chef 运行它。应用工程师把应用程序转换成容器后,就可以更直接地控制应用程序在什么环境中运行,可以使用什么工具和库,以及如何分配资源。
困难在于将部署管道的职责从 DevOps 转移到应用工程团队,以及了解如何在 Kubernetes 而非 EC2 实例上调试应用程序。但是,所有这些都有显著的长期好处,消除了反复修改的需求,并使代码与运行环境更紧密地结合在一起。
布莱恩·希克森:利用容器进行机器学习微服务的实验。在主要应用中,我们提取了一小部分,并通过更适合的技术栈快速启动新服务。这样就可以快速迭代和实验。举例来说,我们可以用 Python 中的神经网络无缝替换 R 中的贝叶斯方法训练的模型。
当我们将服务从单体上剥离时,我们面临的一个挑战是,这些服务不再能直接访问实时应用数据。我们必须决定微服务将保留对那些数据的访问,并且知道越是接近实时的服务,就越需要访问上下文数据。
Q:如何部署和监控容器化应用?你的关键健康指标有哪些?
劳伦·伯纳耶:我们依赖 DataDog 来监控。每一个应用都负责对其监控进行配置,但是有一些关键的指标随处可见:容器的 CPU 和内存使用情况,容器状态和重启次数,以及底层节点的健康状况。起初,我们使用 Spinnaker 来部署容器化应用程序,这在早期提供了一个强大的基础,但是随着集群数量的增长和工作流程的复杂性,我们对此有所改进。当前,我们正在开发利用 Helm 和云原生应用包并由 Temporal 支持的多集群部署的内部解决方案。
克里斯·罗格斯:我们主要看内存和 CPU,标准的 Kubernetes 监控,以及特定的应用指标,比如内部队列大小和错误率。应用程序用 Helm 部署,当配置(GitHub repo 中的 YAML)发生变化时,使用内部工具通过 Jenkins 将部署配置提供给 Helm CLI。
布莱恩·希克森:当构建在主分支中通过时,我们使用 Heroku 不断地部署应用程序。通过使用 Heroku,我们还添加了日志服务——Pingdom 和 New Relic,结合了 PagerDuty 的警报,这使得我们可以调查生产系统中的问题,并在发现问题时通知我们的团队。同时,我们也使用合成和真实用户监测来发现严重的错误和性能问题。我们这个团队使用 KPI 来跟踪基础设施的趋势。服务器的正常运行时间是关键的健康指标,在 2020 年这一指标为 99.999%。
Q:贵组织是如何处理容器测试?怎样使用自动化?
劳伦·伯纳耶:我们没有对容器进行系统性测试。取而代之的是,我们在 CI 中测试应用程序,并在 staging 和 canary(金丝雀)中验证新容器版本。如果我们怀疑容器化对它有影响,我们还会临时测试容器,尤其是那些无法用代码库更改来解释的性能下降。
克里斯·罗格斯:通过 Docker Compose 运行,我们的许多应用程序都在本地开发和测试。在运行容器化应用部署的开发和 staging 环境中,我们每天也会数次运行端到端测试。我们使用 Buildkit,CI 还在 Docker 中运行测试,当应用程序代码改变时,测试会自动运行。
布莱恩·希克森:测试容器已进行了配置,以与生产环境匹配。没有直接测试容器本身,但是我们的连续测试过程可以确保应用程序在各个分支中的行为一致。
Q:贵组织如何跟上容器生态系统的转变?你如何决定何时采用一项新技术或工具?
劳伦·伯纳耶:由于我们大规模使用 Kubernetes,并且面对着生态系统刚刚开始应对的挑战,所以我们更倾向于在早期测试新技术,并在测试成功之后再加以采用。比如,当 containerd 具有容器运行时接口时,我们将其标准化,并且当 kube-proxy 在测试版中可用时,我们就将其用于 IPVS 模式,这是处于扩展性的考虑。我们最近对 pod 网络、服务负载平衡和网络策略的 Cilium 进行了标准化。
克里斯·罗格斯:我们工程师非常关心整个行业的变化。为了尝试新的方法,他们尝尝鼓足勇气做出改变,包括在我们的内部“黑客日”进行概念验证演示,以探索和衡量其他人的兴趣。他们关注 AWS 的公告,Kubernetes 的公告,以及关于新选项的技术新闻来源。遇到问题的时候,他们会寻找解决办法,想象出一个“更好的”样子。举例来说,我们已经做了很多研究,通过使用 spot 实例自动提供实例来节省成本。
布莱恩·希克森:我们依赖工程师来发现改进我们使用容器方法的机会,并且我们权衡了潜在价值和需求。举例来说,最近我们的前端和全栈工程师在使用 Docker for Mac 时遇到了文件系统性能的问题。我们的一位工程师研究了改进 Docker 的 IO 的技术,并对 Mutagen、NFS,以及本地系统和 Docker 之间共享文件进行了实验。最后,我们将 Mutagen 引入了整个团队,极大地改善了开发人员的体验。前端容器的构建时间不再会影响开发者的生产力。
Q:使用容器时,贵组织发现的最令人吃惊的是什么?
劳伦·伯纳耶:从控制平面上的可扩展性问题到低层的运行时问题和网络问题,我们都遇到过许多令人吃惊的挑战。总体而言,在采用容器方面最大的成功在于,它允许我们使用通用抽象在多个云供应商之间进行扩展和部署。
克里斯·罗格斯:构建用于 localdev 的容器需要其他额外的调试工具,这在生产环境中是不可取的。与本地调试相比,在生产环境中进行调试更困难,尤其是在托管容器的服务器上,它有一个细粒度的访问控制列表。将面向服务的架构精确地复制到容器中会让笔记本的 CPU 和内存负担过重,这会导致仍然缺少一些可靠的捷径,例如不运行“真正的” Kubernetes 集群或者相同的配置。与本地构建不同,CI 构建容器可以轻松地包含本地不存在的内容,这可能会导致难以调试或识别。
布莱恩·希克森:容器使我们能够在一个云供应商上训练新的机器学习模型,并且当我们准备将它们与我们的主要应用集成时,可以轻松地迁移到另一个云供应商上。令人惊讶的是,我们几乎没有遇到任何与容器本身相关的问题。一般情况下,任何问题都存在于比容器级别更高的抽象层次;例如,我们在部署应用程序时发现了一些错误,但这些错误并不特定于容器的使用。
原文链接:
评论