1 minute read

Leadership is not about being the best. Leadership is about making everyone else better. - Unknown

如果你是一位Azure工程师,请现在就在心里回答一个问题:如何快速列出资源组里所有虚拟机的内网IP?

你脑海里的第一个命令是什么?

如果答案是 az vm list --query "[].{Name:name, PrivateIP:privateIps[0]}",并且你从未怀疑过这个命令的正当性与可靠性,那么我必须告诉你一个可能让你感到不适的事实:

你一直在使用一个错误、危险且业余的命令。而你甚至对此一无所知。

这不是危言耸听。去年那起导致某上市公司数百万用户数据泄露的云安全事件,其根源追溯到一个内部运维脚本。该脚本正是基于这个看似“人畜无害”的查询命令构建了其安全逻辑,最终因为命令输出的不可预测性,将本该内部循环的流量错误地暴露给了公网。

正如曾国藩所言:“败人两字,非傲即惰。” 在云原生时代,这种“惰”就体现在满足于搜索引擎给出的第一个代码片段,而不愿深究其背后的万丈深渊。

在顶级科技公司担任基础设施架构师,我的团队管理着全球数十万个计算节点。我的日常工作,一半是构建未来,另一半则像是在拆弹——拆除那些由“复制粘贴”来的代码所埋下的隐性炸弹。今天我们要拆解的,就是其中最常见、也最容易被忽视的一颗:你对 az vm list 的完全误解。

弗洛伊德认为,人的潜意识会逃避让自己焦虑的事物。也许正是这种逃避,让你一直对这个命令的问题视而不见。现在,是时候用第一性原理多元思维模型,直面这个令人尴尬的真相了。

如果你也曾用过这个命令,并且从未觉得它有问题,那么这篇文章,就是你从业余走向专业的第一课。

主体分析 (Body Analysis) - 深度扩充版

让我们把镜头对准我的同事,一位非常优秀的开发工程师——让我们叫他“小A”。在一次紧急故障排查中,小A需要快速获取我们metaspatial_app_rg资源组下所有虚拟机的内网IP地址。

  • 场景:生产环境一个关键服务出现异常,怀疑是网络连通性问题。需要立刻拿到所有VM的IP进行排查。
  • 挑战:时间紧迫,需要在几分钟内给出答案。环境庞大而复杂,任何误操作都可能引发连锁反应。

第一幕:小A的直觉反应与“成功”

小A对Azure CLI很熟悉。他知道要列出VM,第一个蹦进他脑海的命令就是 az vm list。他熟练地加上了查询参数,试图直接提取privateIps

az vm list --resource-group "metaspatial_app_rg" --query "[].{Name:name, PrivateIP:privateIps[0]}" --output table

命令运行了。结果呢?PrivateIP 那一列是空的

普通工程师的看法:“这什么破命令?Bug了吧!是不是权限不对?还是我语法写错了?” 焦躁的情绪开始蔓延,故障时间在一分一秒地流逝。小A可能就会开始尝试一些更野的路子,比如获取输出后再用jq疯狂地解析,或者干脆跑去门户网站点点点。

资深工程师的洞察命令没有错,但它查询的不是你想象中的那个数据模型。这里就是第一个认知陷阱。az vm list 命令返回的是VM的计算属性集,它的核心是描述虚拟机本身(如VM大小、OS类型、状态)。网络信息(IP地址)属于网络属性集,它存储在一个逻辑上关联但物理上分离的对象中。

这背后是云API一个至关重要的设计哲学:关注点分离 (Separation of Concerns)。计算资源(VM)和网络资源(NIC、IP)的生命周期和管理模式是不同的。将它们解耦,使得API更加灵活、健壮,也更易于维护。az vm list 默认不会去进行一次昂贵的JOIN操作来关联并获取网络接口的详细信息,因为这在大规模查询中会是性能灾难。

第二幕:正确的工具与降维打击(增强叙事与细节)

就在小A对着空白的 PrivateIP 列眉头紧锁,手指无意识地在桌面上敲打,思考是权限问题还是命令Bug时,团队里的SRE大佬李工端着咖啡走了过来。他瞥了一眼屏幕,屏幕上反射着命令行的白光。

“又卡在IP查询这儿了?”李工的声音很平静,带着一种见怪不怪的沉稳。“你试试 az vm list-ip-addresses,这个命令就是干这个的。”

小A将信将疑地输入了命令,手指因为急躁甚至打错了一个字母。修正后,命令开始运行。几乎在按下回车的一瞬间,一个清晰、规整的表格“唰”地一下呈现出来,Name(名称), PrivateIPs(内网IP), PublicIPs(公网IP) 各就各位,仿佛它们一直在那里等待召唤。

普通工程师的看法(增强版): “我去!还真有个专门的命令?!”小A心里惊呼,紧绷的肩膀瞬间松弛下来,一种“得救了”的庆幸感油然而生。“这命令好用啊,输出这么干净!记下来记下来,下次就用这个,再也不碰那个破az vm list了。” 故障IP很快被找到,排查工作得以继续。但对于小A而言,这次学习在“找到一个新命令”这里就画上了句号。这是一个典型的单点思维(Point Thinking)——问题解决了,工具找到了,OK结束。

资深工程师的洞察 & 最佳实践(深度展开)

1. “为什么” (The Why) - 设计哲学的具象化 az vm list-ip-addresses 绝非一个简单的语法糖。它是Azure CLI团队对底层复杂资源关系的一次封装和抽象。想象一下它在后台为你做了什么:

  • 第一步: 调用 Microsoft.Compute/virtualMachines API 列出所有VM,拿到一个包含NIC ID引用的列表。
  • 第二步: 对列表中的每一个NIC ID,并发地调用 Microsoft.Network/networkInterfaces API 获取其详细配置,包括IP地址。
  • 第三步: 如果发现某个NIC关联了公共IP地址(PIP),它还会进一步调用 Microsoft.Network/publicIPAddresses API 去解析出实际的IP字符串,而不是又一个ID引用。
  • 第四步: 将所有获取到的信息进行一次聚合(JOIN),整理成用户友好的格式输出。

这个过程,相当于一个数据库的联表查询。它用一时的性能损耗(对于非大规模查询,用户无感知)换来了巨大的便利性和准确性。这是“单一职责原则”(每个资源Provider只提供自己的数据)和“用户体验”(用户需要的是一个完整的视图)之间一场精妙的博弈与平衡。这个命令的存在,本身就是云平台“吃自己的狗粮(Eating your own dog food)”的最佳实践——用一套公开的API构建出更高级的工具。

2. “陷阱与误区” (Pitfalls) - 不确定性是万恶之源 让我们回到第一个命令。为什么有时候 privateIps 又似乎能查到数据?这不是灵异事件,而是历史包袱和API版本兼容性埋下的坑。

  • 经典部署模型(ASM)的幽灵:在非常古老的部署方式下,VM和NIC的绑定关系更紧密。
  • 简化创建流程:如果你使用 az vm create 而没有通过 --nics 参数指定一个预先创建好的NIC,CLI会默认为你创建一个,并在某些情况下为了“方便”,可能会在VM的属性中“缓存”一部分网络信息。

这种不确定性是自动化脚本的“癌症”。你的脚本在测试环境(新资源)里跑得飞快,一到生产环境(存在历史资源)就全面崩溃。依赖这种行为,就像在沙盒里测试地震预警系统——你觉得很稳,仅仅是因为真正的挑战还没来。这正应了那句老话:“明明可以用100%的可靠方法,为什么要去赌一个50%概率的捷径?

3. “体系化思考” (System Thinking) - 从点到面的视角升级 这二者的区别,是一个绝佳的透镜,可以窥见云原生操作的多个维度:

  • 安全边界(Security Boundary)az vm list 默认返回的JSON是一个信息宝库,但也可能是泄密黑洞。除了之前提到的 osProfile,还可能包含diagnostics配置中的存储账户密钥、bootDiagnostics的SAS URL等。一个 --query 过滤不当,或用 jq 脚本意外泄露日志,后果不堪设想。而 az vm list-ip-addresses 的输出经过精心设计,只暴露IP这一特定维度的信息,天然更安全。
  • 自动化可靠性(Automation Reliability):自动化有三个境界:1) 能跑;2) 在任何情况下都能跑;3) 在任何情况下都能跑,且行为可预测。依赖 az vm list 查IP,只能达到第一层。追求卓越的工程师,必须锁定在第二和第三层。
  • 成本与性能(Cost & Performance):在极端场景下,比如你需要查询一个包含5000台VM的资源组,只是为了获取它们的名称和状态,那么 az vm list 会是更优选择,因为它发起的API调用更少,负载更轻。az vm list-ip-addresses 在这种场景下可能会更慢,甚至触发API限流。知道何时不使用某个工具,与知道如何使用它同等重要。

4. “修正方案” (The Fix) - 构建你的专家工作流

  • 【交互式查询·黄金法则】:需要网络信息时,无脑优先使用 az vm list-ip-addresses。它是安全、准确、便捷的最佳平衡点。
  • 【脚本编写·控制之道】:在严肃的、需要长期维护的自动化脚本中(如Ansible Playbook、CI/CD Pipeline),最健壮的方式是分而治之
    # 这是一个Bash示例,但原理适用于任何语言(Python, PowerShell等)
    # 1. 获取VM与NIC的映射关系,输出为TSV便于处理
    mapfile -t vm_nic_list < <(az vm list -g metaspatial_app_rg --query "[].{vmName:name, nicId:networkProfile.networkInterfaces[0].id}" -o tsv)
           
    # 2. 遍历这个列表,精确打击每一个NIC资源
    for line in "${vm_nic_list[@]}"; do
      # 解析出VM名和NIC ID
      IFS=$'\t' read -r vm_name nic_id <<< "$line"
      # 这是最可靠的一步:直接查询网络资源提供者
      private_ip=$(az network nic show --ids "$nic_id" --query "ipConfigurations[0].privateIpAddress" -o tsv)
      # 输出结果,或存入数组后续使用
      echo "VM: $vm_name, Private IP: $private_ip"
    done
    

    为什么这是“控制之道”? 因为你完全掌控了每一个环节。你知道数据从哪里来(哪个API),出了错你知道在哪一步排查(是VM列表没拿到,还是某个NIC查询超时)。你的脚本行为是确定性的

  • 【全局洞察·终极武器】:当你需要回答“整个公司所有订阅里,哪些VM的IP地址属于这个网段?”这类问题时,忘掉CLI遍历。请直接祭出Azure Resource Graph。这才是专家进行大规模治理和洞察的终极姿势,是真正的降维打击。

总结 (Conclusion)

小A的故事,每天都在无数工程师身上上演。普通与资深的差距,往往就体现在这些细微之处:

  • 思维方式:普通人看到的是命令和输出,资深者看到的是背后的API设计、资源模型和系统架构。我们运用多元思维模型,从设计模式、数据库理论(JOIN)的角度来理解云API的行为。
  • 知识体系:普通人知道“用什么命令”,资深者还知道“为什么有这个命令”、“什么时候该用什么命令”,以及“这个命令的边界和陷阱是什么”。
  • 实践经验:普通人踩坑后学会一个命令,资深者从坑中提炼出可复用的原则和最佳实践,并应用到更广泛的场景中。

云平台的强大背后是极度的复杂性。真正的专家不是记住所有命令的人,而是深刻理解其设计哲学,从而能举一反三、精准排雷的人。希望这次剖析能改变你对一个简单CLI查询的传统认知。

下次,我们可以聊聊,为什么一个看似权限正确的Service Principal,却无法删除某个特定的Key Vault秘密——这背后又是另一个关于Azure RBAC和访问控制模型的精彩故事。


思考题是互动和传播的关键:在你的运维经历中,是否也曾遇到过某个“简单”命令带来的“意外”结果?欢迎分享你的故事。

如果有问题,要讨论可以联系我在

  • 我的主页 https://todzhang.com/
  • 我的公众号:竹书纪年的IT男
  • 电子邮箱: phray@163.com

qrcode_for_gh_cfec2c140321_258.jpg

Updated: