Uber 全球办公网络自动化实践:Ansible 如何把 5000 台设备拉回“期望状态”

Uber 全球办公网络自动化实践:Ansible 如何把 5000 台设备拉回“期望状态”

本文是对 How Ansible® Automation Powers the Uber Corporate Network at a Global Scale 的整理与翻译。

内容结构概览

这篇文章主要讲 Uber 如何在全球规模的企业办公网络中使用 Ansible 做配置管理。它不是在介绍一个简单的“自动化脚本”,而是在解释:当网络设备遍布多个大洲、多个区域、多个办公室,并且同时存在不同厂商、不同设备类型、不同操作系统时,怎样用 Ansible 把网络配置从“人工修改”变成“可版本化、可回滚、可审查、可持续收敛”的工程系统。

全文可以分为几个部分:

  1. Uber 为什么需要网络自动化:全球办公室、数千名工程师、跨云和本地基础设施、多厂商硬件、持续变更和高可用要求。
  2. Ansible 在 Uber 网络体系中的定位:Terraform 负责云资源编排,Puppet 负责机器配置管理,而 Ansible 主要用于本地网络硬件配置管理。
  3. Ansible 为什么适合网络工程:agentless、基于 SSH、YAML/Python 友好、模块化、拥有面向 Cisco、Juniper、Arista 等网络设备的集合与模块。
  4. Uber 如何组织全球办公网络 Inventory:按区域、功能、设备类型、操作系统等维度分组,并用 YAML 变量描述期望状态。
  5. “Daily Nightly Enforcement” 是什么:每天夜间自动备份、生成 Golden Config、推送配置,把人工临时修改清理掉。
  6. Ansible 如何覆盖 DHCP、BGP、VLAN、TACACS、RADIUS、密码轮换、设备上线、ZTP 等场景。
  7. 大规模网络自动化的风险和挑战:错误配置的爆炸半径、多厂商差异、2000 行配置文件、Jinja 模板复杂度、自研模块维护成本。
  8. 最后的核心启发:网络自动化真正的价值,不只是节省人工,而是让全球网络每天都能回到一个可验证的期望状态。

一、为什么 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 私有仓库。

这一步很关键。网络自动化最怕的是“改完之后发现错了,但不知道之前是什么样”。通过每天备份并放进 GitHub,Uber 可以追踪每台设备配置的变化差异,也可以保留完整历史。

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,再到 VLAN:Ansible 管的不只是简单配置

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)