Uber 全球办公网络自动化实践:Ansible 如何把 5000 台设备拉回“期望状态” 📅 2026/7/7 2:03:09 本文是对 How Ansible® Automation Powers the Uber Corporate Network at a Global Scale 的整理与翻译。内容结构概览这篇文章主要讲 Uber 如何在全球规模的企业办公网络中使用 Ansible 做配置管理。它不是在介绍一个简单的“自动化脚本”而是在解释当网络设备遍布多个大洲、多个区域、多个办公室并且同时存在不同厂商、不同设备类型、不同操作系统时怎样用 Ansible 把网络配置从“人工修改”变成“可版本化、可回滚、可审查、可持续收敛”的工程系统。全文可以分为几个部分Uber 为什么需要网络自动化全球办公室、数千名工程师、跨云和本地基础设施、多厂商硬件、持续变更和高可用要求。Ansible 在 Uber 网络体系中的定位Terraform 负责云资源编排Puppet 负责机器配置管理而 Ansible 主要用于本地网络硬件配置管理。Ansible 为什么适合网络工程agentless、基于 SSH、YAML/Python 友好、模块化、拥有面向 Cisco、Juniper、Arista 等网络设备的集合与模块。Uber 如何组织全球办公网络 Inventory按区域、功能、设备类型、操作系统等维度分组并用 YAML 变量描述期望状态。“Daily Nightly Enforcement” 是什么每天夜间自动备份、生成 Golden Config、推送配置把人工临时修改清理掉。Ansible 如何覆盖 DHCP、BGP、VLAN、TACACS、RADIUS、密码轮换、设备上线、ZTP 等场景。大规模网络自动化的风险和挑战错误配置的爆炸半径、多厂商差异、2000 行配置文件、Jinja 模板复杂度、自研模块维护成本。最后的核心启发网络自动化真正的价值不只是节省人工而是让全球网络每天都能回到一个可验证的期望状态。一、为什么 Uber 需要网络自动化企业网络最基本的要求是稳定。办公室里的工程师、运维人员、客服、业务团队每天都依赖网络访问内部系统、云服务、代码仓库、办公工具以及各种生产环境相关平台。对 Uber 这样全球化规模的公司来说企业网络不仅要连得上还要持续保持可用、可靠、低延迟并且能支持每天不断发生的变更。Uber 的办公室分布在亚洲、非洲、北美、南美、欧洲、澳大利亚及大洋洲等多个大洲每天有大量工程师访问公司网络。这样的网络不是几台交换机、几条链路就能概括的。它涉及云端资源、本地机房、办公室网络、VPN、网关、防火墙、接入交换机、无线控制器、DHCP、BGP、VLAN、TACACS、RADIUS以及不同厂商的网络硬件。当网络规模足够大时故障和变更都会变成日常事件。链路会出问题设备会需要替换办公室会扩容新的 VLAN 会被创建路由偏好会被调整密码需要定期轮换某些设备配置需要临时修复。手工操作在小规模环境下还能勉强维持但在全球规模下手工变更迟早会带来三个问题第一变更不可追踪。某个工程师凌晨临时改了一个设备配置如果没有被记录进系统后面的人很难知道这个配置为什么存在。第二配置不可恢复。设备坏了、配置丢了、需要替换时如果没有可靠的配置快照和期望状态就只能靠人工回忆或临时拼凑。第三状态会漂移。所谓状态漂移就是生产设备上的真实配置和代码仓库里记录的期望配置越来越不一致。久而久之网络系统会变成一堆没人敢碰的“历史包袱”。所以Uber 需要的不只是自动执行命令而是一套能让全球企业网络持续回到“期望状态”的系统。Ansible 在这里扮演的就是这个角色。二、Ansible 在 Uber 基础设施体系中的位置基础设施自动化这个词很大里面其实包含不同层面的事情。Uber 在文章里特别区分了两个概念基础设施供应和配置管理。基础设施供应更多是创建资源。比如创建虚拟机、创建网络资源、创建云端基础设施。Uber 使用 Terraform 作为云资源编排的主要工具。配置管理关注的是已经存在的机器、设备或系统应该处于什么状态。比如安装软件版本、配置用户、管理文件、设置网络设备参数、调整接口配置等。Puppet 和 Ansible 都属于这个方向。Uber 在某些机器配置管理上使用 Puppet而这篇文章重点讲的是Uber 如何使用 Ansible 管理本地网络硬件。换句话说Terraform 更像是“把资源创建出来”Puppet 和 Ansible 更像是“把已有资源配置成我们想要的样子”。对于 Uber Corpnet也就是 Uber 的企业办公网络来说Ansible 主要用来管理本地网络设备的配置状态。这里的网络设备不只是普通交换机。它包括通用交换机、外部网关、防火墙、VPN 相关设备、核心网关、接入点、无线控制器、WAN 网关、控制台服务器等。不同办公室可能使用不同型号的硬件不同区域可能有不同网络策略大办公室和小办公室需要的路由器、交换机、防火墙规格也不一样。Ansible 要解决的就是在这种复杂环境下统一配置逻辑。三、为什么是 Ansible简单、无 Agent、适合网络工程Ansible 最早由 Michael DeHaan 在 2012 年创建。它起初是为了解决同时管理多台 Web 服务器的痛点。后来 Ansible 快速发展成为一个非常活跃的开源项目并逐渐被 Red Hat 主导。随着后续版本演进Ansible 从一个相对单体的项目拆分出 Ansible Collections让不同厂商和社区可以围绕各自领域开发模块并通过包管理方式分发。Ansible 和 Puppet、Chef 这样的工具相比一个很大的特点是简单。它不要求被管理节点安装长期运行的 agent也就是说它是 agentless 的。只要有一台 Ansible Controller 能通过 SSH 访问目标设备或服务器就可以把配置推送过去。对网络工程师来说这一点很重要因为很多网络设备并不适合安装额外 daemon也不一定允许像普通 Linux 服务器那样改造运行环境。Ansible 另一个优势是学习成本相对低。它大量使用 YAML 来描述任务和变量也可以利用 Python 生态扩展模块。相比要求掌握特定 DSL 或 Ruby 语法的工具Ansible 对已经熟悉 YAML、Python、命令行和网络设备配置的工程师更友好。更关键的是Ansible 逐渐发展出了丰富的网络设备支持。Juniper、Cisco、Arista 等厂商相关的模块和 Collection让 Ansible 不再只是 Linux 服务器配置工具而是可以编排网络设备。Uber 选择 Ansible很大程度上就是看中了它在网络设备管理上的模块化、社区生态、易部署和跨厂商能力。这也是本文很重要的背景Uber 不是为了赶时髦才用 Ansible而是因为它刚好符合大规模企业网络配置管理的需求。四、从“设备清单”到“期望状态”Inventory 是核心很多人理解 Ansible 时容易把重点放在 playbook 上。playbook 确实重要因为它描述了要执行什么任务。但在 Uber 这种规模下更关键的是 inventory也就是设备清单和变量体系。Uber 的 Corpnet 网络覆盖五个全球区域包含约 5000 台设备。设备类型和厂商差异很大。比如印度某个办公室可能使用一种交换机而墨西哥办公室可能没有这种型号阿姆斯特丹或旧金山这样的大办公室可能需要某些小办公室完全不需要的路由器数据中心设备和办公室网络设备又完全不同数据中心更强调高吞吐、leaf-spine 这样的专用拓扑而办公室网络更偏向用户接入、本地连通和办公体验。在这种情况下如果每台设备都用一份完全独立的配置文件来管理系统很快就会失控。Uber 的做法是把 Corpnet 设备注册进 Ansible Inventory并按照区域、功能、操作系统、设备类型等维度分组。每个组由 YAML 文件定义同时携带该组对应的配置变量。这些变量描述的不是某个厂商命令行里的最终语法而是网络应该达到的理想状态。比如某个区域优先使用哪些 DHCP 服务器某类设备应该有哪些 trunk 接口配置某些路由器应该有哪些 IP route某个办公室是否需要本地 DHCP 冗余某些 BGP community 或 ASN 应该如何设置。然后设备根据自己所属的多个组继承变量。比如一台设备可能同时属于“APAC 区域”“接入交换机”“某个办公室”“某个厂商操作系统”这些组。Ansible 最后会把这些变量组合起来渲染成设备操作系统真正能识别的配置语法。这个设计的价值在于它把配置逻辑和厂商语法解耦了。也就是说网络工程师可以先用相对抽象的变量描述网络意图而不是一开始就陷进某个厂商的 CLI 细节里。具体如何变成 Cisco、Juniper 或 Arista 的配置命令则交给模板和渲染逻辑处理。五、人工临时变更会被夜间覆盖把漂移当成技术债在真实网络运维里完全禁止手工变更并不现实。线上出现问题时工程师可能需要临时登录设备做调整比如修改一条路由、调整某个接口、恢复某个策略。问题不在于“有没有手工变更”而在于这些手工变更是否被纳入系统记录。Uber 的原则很明确任何没有同步回 Ansible Inventory 的手工设备变更都会在夜间被覆盖掉。这些未追踪的人工调整被视为技术债。这背后的思路很工程化。生产设备上的配置不应该长期偏离代码和 inventory 描述的状态。如果某个临时修改是正确的就应该把它写回 Inventory 或模板让它成为新的期望状态如果它只是救火时的临时措施就应该在问题结束后被清理掉。这就是自动化系统的一个核心作用它不是只负责部署新配置也负责清理未经记录的漂移状态。每天夜间把设备重新收敛到期望配置可以保证第二天办公室开门时网络处于一个可预期、可审查、可恢复的状态。很多团队做自动化时只想到“用脚本批量改配置”但 Uber 这里更重要的是“配置收敛”。批量执行只是手段持续回到期望状态才是目标。六、Daily Nightly Enforcement每天夜间执行的三步流程Uber 把这套每天夜间执行的配置收敛流程称为 Daily Nightly Enforcement。它由一系列 Ansible playbook 组成核心目标是备份当前配置、生成期望配置、推送期望配置并在失败时触发告警。整个流程可以拆成三步Backup、Config Generation、Nightly Push。1. Backup先备份再修改在做任何配置变更之前Uber 会先对目标区域的设备执行完整备份。这个步骤由一个 Ansible playbook 管理。playbook 会访问所有相关设备保存它们当前正在运行的配置也就是 running configuration然后把备份文件推送到 GitHub 私有仓库。这一步很关键。网络自动化最怕的是“改完之后发现错了但不知道之前是什么样”。通过每天备份并放进 GitHubUber 可以追踪每台设备配置的变化差异也可以保留完整历史。GitHub 在这里不只是代码仓库也充当配置历史记录系统。每次设备配置发生变化都可以通过 diff 看到变化内容。多个工程师同时工作时也能通过版本历史理解配置为什么变化。2. Config Generation生成 Golden Config第二步是生成配置。另一个 Ansible playbook 会从每台设备收集 facts然后根据 host data 和 inventory 变量渲染出目标厂商设备所需的配置文件。这里会用到 Jinja 模板。Inventory 中的 group 和变量会被注入到 Jinja template 里最终根据设备操作系统生成具体配置。不同厂商、不同设备类型可能有不同模板因为它们的配置语法并不一样。生成出来的目标配置被称为 Golden Config也就是“黄金配置”或“标准期望配置”。这些 Golden Config 每 24 小时生成一次。生成配置后Uber 还会通过一个自定义的 Config Ansible Role 对配置文件做处理包括隐藏敏感数据、格式化内容并准备把它们存储到 GitHub。这样做有两个好处一是避免敏感信息泄露到配置仓库中二是减少无意义格式差异让配置 diff 更干净。3. Nightly Push把期望配置推回设备当 Golden Config 准备好后最后一个 playbook 会把它推送到目标设备上。如果备份或 Golden Config 生成过程中出现错误对应设备的 enforcement 会停止并向外部系统发送告警。这点很重要。自动化不是“无论如何都推”。一旦前置步骤失败继续推送可能会扩大故障范围。Uber 的流程是备份失败或生成失败就停止该设备的后续强制收敛并让告警系统介入。推送时同一个自定义 Config Role 会以相反方向处理配置把适合存储的 Golden Config 转换成适合下发到设备的格式然后执行配置强制收敛。这套流程可以简单理解为Inventory / 变量 | v Jinja 模板渲染 | v Golden Config | v 备份当前配置 - 推送目标配置 - 失败告警真正重要的是这不是偶尔运行的脚本而是每天运行的工程流程。每天都会重新备份、重新生成、重新推送确保设备配置不会长期偏离期望状态。七、GitHub 在配置管理中的作用Uber 把 Ansible playbook、inventory 和网络配置文件分别放在不同仓库中管理。这样做的好处是职责清晰自动化逻辑、设备清单、实际配置产物可以分别演进。配置文件进入 GitHub 以后就获得了软件工程里常见的能力版本历史、代码审查、diff、工作流检查、格式校验、多人协作。对于网络配置来说这些能力非常有价值。传统网络运维里设备配置经常只存在于设备本身。谁改了、什么时候改了、为什么改了很难查。把配置纳入 GitHub 后网络状态就开始接近“基础设施即代码”的管理方式。Uber 还利用 GitHub workflow 检查配置标准和格式。无论是生成出来的配置文件还是工程师维护的 Ansible 代码都可以通过自动化检查降低低级错误。这一点对普通团队也很有启发网络配置不应该只是设备上的文本它应该像代码一样被版本化、被审查、被测试、被自动生成。八、从 DHCP 到 BGP再到 VLANAnsible 管的不只是简单配置Daily Nightly Enforcement 覆盖了 Uber Corpnet 的多种核心配置。首先是区域级偏好。不同区域可以根据距离和网络延迟设置不同的偏好变量。例如 BGP communities、ASN、TACACS、RADIUS、DHCP server list 等。每 24 小时这些变量都会在对应设备上解析并下发。如果有需要也可以手动触发。其次是办公室级别的特殊需求。有些办公室需要本地 DHCP server 做冗余有些位置的所有路由器需要本地路径偏好有些设备类型需要统一 VLAN 管理。通过 Ansible Inventory只需要改一个 YAML 文件就可以把配置部署到全球所有 Corpnet 交换机也可以只针对某个区域或某个办公室下发。这就体现出自动化的威力配置的作用范围可以很大也可以很精准。你可以做全局标准化也可以做局部覆盖。除了每天夜间强制收敛Uber 还用 Ansible 构建一些辅助工作流。比如密码轮换这种任务如果人工做会很繁琐而且容易漏设备。通过 Ansible playbook可以把密码轮换变成自动化流程。再结合监控系统如果中间出现失败可以立即告警并在必要时停止后续 enforcement。另一个重要场景是新增设备入网。Uber 使用已经配置好的 DHCP server 结合配置生成流程实现更顺滑的 ZTP也就是 Zero Touch Provisioning。设备上线后可以自动获得必要信息再通过配置生成和下发流程完成初始化减少网络工程师手动登录设备配置的工作量。文章里还有一个很有代表性的例子访问控制列表。理想情况下一份 access list 可以用一个 YAML 文件定义然后根据不同厂商设备渲染成不同语法并在多个设备上统一执行。这就是网络可编程性的真正价值不是简单地把命令复制到多台设备上而是让网络意图和厂商语法分离。九、多厂商环境下模板设计是关键大规模网络自动化最难的地方之一是多厂商差异。在理想情况下Inventory 是网络无关的也就是说它描述的是业务和网络意图而不是某个厂商的命令。但现实中每个厂商都有自己的配置语法、命令结构、设备能力和边界条件。如果模板设计不好就会出现大量只服务于某个厂商语法的变量最后把 Inventory 变成一堆重复字段。Uber 提到良好的软件架构非常重要。Ansible 代码需要围绕单一变量来源来组织。比如同一份 access list如果生成流程设计得好就可以同时渲染成 Juniper 和 Cisco 设备需要的配置。这样网络工程师维护的是一份逻辑配置而不是两份甚至多份厂商配置。这其实是基础设施代码化中的经典问题抽象应该放在哪里如果抽象太薄所有厂商差异都暴露给上层变量Inventory 会非常混乱如果抽象太厚模板逻辑会变得过于复杂调试困难。Uber 的做法是利用 Jinja 模板和自定义 role把厂商差异封装在配置生成过程里让 Inventory 尽可能保持意图层面的表达。这对很多团队很有借鉴意义。做网络自动化时不要一开始就把设备命令硬编码进 playbook。更好的方式是先设计数据模型区域、办公室、设备类型、接口、VLAN、路由、认证服务器、DHCP 列表、ACL这些对象应该如何表达然后再考虑如何渲染到不同厂商设备。十、自动化的风险错误会被快速放大自动化不是只有好处。规模越大自动化错误的破坏力也越大。Uber 文章里明确提到自动化的风险在于任何错误都可能产生不可预测的爆炸半径。比如密码轮换、访问控制列表修改甚至一个简单 VLAN 配置都可能影响全球数百台甚至数千台物理设备。一旦错误配置被自动化推到大量设备上后果可能比人工误操作更严重。所以大规模网络自动化必须非常谨慎。它需要备份、配置生成、格式化、敏感信息处理、失败中断、外部告警、GitHub diff、workflow 校验以及足够可靠的测试环境。尤其是网络设备和普通服务不同。服务部署失败很多时候可以通过回滚版本解决网络配置出错可能直接导致工程师无法访问设备甚至远程管理链路也断掉。如果配置错误发生在世界另一端的办公室恢复成本会非常高。这也是为什么 Uber 的流程里先备份、再生成、再推送并且在前置步骤失败时停止 enforcement。网络自动化不是越激进越好而是要在效率和安全之间找到平衡。十一、2000 行配置文件格式化和清理也很重要网络设备配置文件通常很长。Uber 提到这些配置文件很容易达到 2000 行而且一个错误字符就可能破坏 parser。在这种情况下配置文件管理本身就成了工程问题。空格、tab、空行、格式差异都可能让 Git diff 变得难以阅读也可能造成无意义提交。为了解决这些问题Uber 在 Jinja 模板旁边配套了 formatter用来删除不需要的空格或 tab避免空提交并减少工程师手工检查变更的时间。这看似是小事但在大规模配置仓库里非常关键。如果仓库里有几千台设备的备份和生成配置每份配置几千行那么排查某个异常行为就可能变成在海量文本里找针。格式化、规范化、自动清理旧配置和 legacy host都是保持仓库可维护性的必要工作。Uber 还提到需要有每日任务清理遗留主机和无用配置。否则配置仓库会越来越臃肿自动化系统本身也会逐渐变成新的技术债。这点很容易被忽视。很多团队做自动化时只关注“能不能生成配置”但真正长期运行后配置产物、历史备份、旧设备、废弃变量、模板分支都会不断堆积。如果没有清理机制自动化系统会越来越难维护。十二、公共 Ansible Collection 不总是够用Ansible 的生态很强但并不意味着所有需求都能直接用公共 Collection 解决。Uber 提到有时公开的 Ansible Collection 并不完全适合他们的需求。可能是某个操作流程过于特殊也可能是公共模块太复杂、嵌套太深和他们想要的行为不匹配。还有些 Jinja 模板需要额外逻辑才能根据 Inventory 渲染出特定厂商语法。在这些情况下Uber 会开发自己的 Ansible 模块和 Python 模块。这带来了新的成本需要工程时间需要控制设备来测试功能需要长期维护 Ansible 代码。自研模块不是写完就结束它会随着设备固件版本、厂商 API、网络架构变化而持续演进。更麻烦的是并不是所有厂商设备都能被 Ansible 管理。有些硬件可能只能通过厂商 portal 或其他系统配置。这就要求 Uber 同时编排 Ansible 代码和其他网络管理平台确保它们之间的配置保持同步。这说明大规模企业网络自动化很少是“一个工具解决所有问题”。Ansible 是核心但它仍然需要和 Terraform、Puppet、GitHub、监控告警系统、厂商 portal、内部工具一起协作。十三、从这篇文章能学到什么这篇文章的重点不是“Ansible 很好用”这么简单而是展示了一种大型基础设施自动化的思路。第一自动化的目标不是省几条命令而是建立期望状态。Uber 的网络设备每天都会通过 Ansible 回到 inventory 和 Golden Config 描述的状态。这样设备上的真实配置不会长期漂移。第二配置必须版本化。备份配置、生成配置、Ansible playbook、Inventory 都进入 GitHub才能让网络变更像代码一样可审查、可追踪、可回滚。第三抽象层要设计好。Inventory 应该尽量描述网络意图而不是堆满某个厂商的语法细节。厂商差异应该通过模板、role、模块来处理。第四自动化一定要有护栏。先备份、再生成、再推送失败就停止异常就告警。越是大规模系统越不能无脑批量执行。第五自动化系统本身也需要维护。Jinja 模板、formatter、自定义模块、旧设备清理、配置仓库整理、workflow 检查都是长期稳定运行的一部分。第六网络自动化最终服务的是组织效率。Uber 的全球办公室每天都需要稳定网络数千名工程师依赖它工作。Ansible 的价值不只是让网络工程师少敲命令而是让整个企业网络每天早上都以稳定、更新、可预期的状态迎接用户。十四、总结Uber 的这篇文章把 Ansible 放在了一个非常真实的生产环境里全球办公室、五个区域、约 5000 台设备、多厂商硬件、复杂配置、每日变更、持续告警、GitHub 版本化、Golden Config 生成和夜间强制收敛。这套系统的核心不是某一个 playbook也不是某一个模块而是一整套工程化流程用 Inventory 描述期望状态 用 Jinja 模板生成厂商配置 用 GitHub 记录备份和 Golden Config 用 Ansible playbook 执行备份、生成和推送 用告警系统阻止失败继续扩大 用每日任务清理漂移和技术债。很多公司在网络运维上还停留在“登录设备、手工修改、复制命令、人工记录”的阶段。这个方式在小规模时还能运转但一旦规模扩大就会暴露出配置漂移、变更不可追踪、故障恢复困难、多人协作混乱等问题。Uber 的实践说明网络也可以像软件一样管理。配置可以代码化变更可以审查状态可以收敛历史可以回溯设备可以自动上线密码轮换可以自动执行跨厂商配置也可以通过抽象和模板统一表达。当然自动化不是没有代价。它需要好的架构设计需要测试环境需要格式化工具需要自定义模块需要持续维护也需要非常谨慎地控制爆炸半径。但对于 Uber 这种全球规模的企业网络来说这些投入是必要的。最终Ansible 在 Uber Corpnet 里的角色可以概括成一句话它把一个庞大、多样、持续变化的全球办公网络变成了一个可以被描述、生成、审查、推送和持续修正的系统。参考来源Uber Engineering 原文介绍了 Ansible 在 Uber Corpnet 中的定位、约 5000 台设备规模、Daily Nightly Enforcement 三步流程以及多厂商网络配置管理中的挑战。(Uber)