Azure Local 离线模式 Azure CLI 配置 Runbook(生产级)
适用场景:Azure Local + Azure CLI Disconnected Operations 文档定位:可直接用于生产执行的 Runbook(工程 SOP) 来源:Use Azure CLI for Disconnected Operations for Azure Local
体例说明:本 Runbook 用 3 类标签组织:
- ✔ 执行步骤(必须按顺序完成)
- ⚠ 故障模式(已知问题与排查方向)
- 💡 Best Practice(仅 production hardening,不重复官方内容)
理论推断统一收纳到末尾"🔍 Technical Analysis(Including Inferred Behavior)"------不混入执行步骤。
0. 执行前置条件(Pre-flight Checklist)
✔ 必须满足
- Azure Local appliance 已部署完成
- 已存在:
- Appliance Root CA(
applianceRoot.cer) - Local portal FQDN(例:
autonomous.cloud.private)
- Appliance Root CA(
- 已具备:
- LocalMachine 管理员权限
- 离线软件分发路径(SMB / ISO / Repo)
⚠ 风险检查(部署前签字)
|--------------------------------|--------|
| 项目 | 状态 |
| Root CA 已导入 | ⬜ |
| CLI 版本已确认 | ⬜ |
| 离线 extension 源已就绪 | ⬜ |
| Cloud config FQDN 已与 portal 一致 | ⬜ |
1. 安装 Azure CLI(统一 64-bit)
✔ 执行步骤
Step 1:从内网镜像源下载官方 64-bit MSI
Step 2:静默安装
msiexec /i AzureCLI.msi /quiet
或标准安装:
# 官方 MSI(64-bit only)
# https://aka.ms/install-azure-cli-windows
✔ 验证
az version
期望输出:
azure-cli: 2.81.0
⚠ 故障模式
|------------------------|-----------------------|---------------------|
| 问题 | 原因 | 排查 |
| az command not found | PATH 未刷新 | 重启 shell / 重新登录 |
| CLI version mismatch | 装错 MSI(32-bit / 旧版) | 重装 64-bit 官方 MSI |
| extension load fail | architecture mismatch | 32-bit 卸载,统一 64-bit |
💡 Best Practice
- 所有节点统一 64-bit CLI
- 禁止混用 32-bit CLI
- 离线环境不要
az upgrade------直接重新装新版 MSI
2. 安装 CA 信任链(企业级标准)
✔ 执行步骤
Step 1 :导入根 CA 到 OS Trust Store(唯一推荐方式)
Import-Certificate `
-FilePath "C:\AzureLocal\applianceRoot.cer" `
-CertStoreLocation Cert:\LocalMachine\Root
Step 2 :安装 pip-system-certs(让 Python 走 OS trust store)
& "C:\Program Files\Microsoft SDKs\Azure\CLI2\python.exe" `
-m pip install pip-system-certs
✔ 验证
Get-ChildItem Cert:\LocalMachine\Root |
Where-Object { $_.Subject -like "*Azure*" }
期望:看到 appliance root CA 出现在列表中。
⚠ 故障模式
|-----------------|------------------------|-------------------|
| 问题 | 影响 | 修复 |
| 未导入 CA | az login TLS failure | 重新 import |
| 仅改 cacert.pem | upgrade 后失效 | 改回 OS trust store |
| 多节点不一致 | 部署漂移 | GPO / Intune 统一分发 |
💡 Best Practice(关键)
- ✔ 唯一推荐方式:OS Trust Store + GPO / Intune 分发
- ❌ 禁止 :修改
certifi/cacert.pem
3. 配置 Azure CLI Cloud(Disconnected Cloud)
✔ 执行步骤
Step 1:加载 OperationsModule
Import-Module "<OperationsModule>\Azure.Local.DisconnectedOperations.psd1"
Step 2 :生成 cloud config(参数以 module introspection 为准)
$cloudConfig = Get-ApplianceAzCliCloudConfig `
-ExternalFqdn "autonomous.cloud.private"
⚠️ 不要硬编码 其他参数------用
Get-Help Get-ApplianceAzCliCloudConfig -Full查实际参数集。
Step 3:写入配置
$cloudConfig | Set-Content "$env:APPDATA\Azure\myCloud.json"
Step 4:应用 cloud
az cloud set --cloud-config "$env:APPDATA\Azure\myCloud.json"
az cloud show
✔ 验证
az cloud list
期望 :当前 cloud = custom disconnected cloud,endpoints 全部指向本地 FQDN。
⚠ 故障模式
|--------------------------|-------------------------|---------------------|
| 问题 | 原因 | 排查 |
| login 仍走 azure.com | cloud 未 set | 重新 az cloud set |
| endpoint resolution fail | FQDN 不匹配 portal | 比对 portal 实际 FQDN |
| JSON schema error | module version mismatch | 升级 OperationsModule |
💡 Best Practice
- Cloud config 当成不可解析配置文件------不要复制字段名当 schema
- 必须纳入 CMDB / Git version control------多节点共享同一份
- 每次升级 OperationsModule 后重新生成 cloud config
4. 登录验证(Disconnected Login)
✔ 执行步骤
az login --use-device-code
浏览器打开显示的 URL,在本地 portal 输入 device code 完成认证。
✔ 验证
az account show
期望:返回包含本地 subscription 的 JSON。
⚠ 故障模式
|--------------------------------|---------------------|----------------------------------------|
| 问题 | 原因 | 排查 |
| device code fail | portal endpoint 不可达 | Test-NetConnection <portal FQDN> 443 |
| login redirect to public cloud | cloud config error | 重新跑 §3 |
5. 安装 Azure CLI Extensions(离线模式)
✔ 执行步骤
❗ 不允许直接 online install(离线下会失败)
Step 1:在能联网的镜像机上下载
az extension add -n aksarc
az extension add -n stack-hci-vm
az extension add -n customlocation
Step 2:复制 extension 目录到内网分发路径
%USERPROFILE%\.azure\cliextensions\
Step 3:在离线节点安装
az extension add --source <local-path>
✔ 验证
az extension list
期望 :列出 3 个 extension,状态为 Installed。
⚠ 故障模式
|---------------------|-----------------|-------------------------------------|
| 问题 | 原因 | 排查 |
| extension not found | repo missing | 检查分发路径 |
| version conflict | CLI 不兼容 | 升级 / 降级 CLI |
| module load fail | corrupted cache | az extension remove -n <name> 后重装 |
💡 Best Practice
- 不写死版本号------extension 版本会随 Azure Local release train 变化
- 内网镜像机每月同步一次最新 extension 索引
6. CLI 升级(离线模式)
❗ 关键约束
az upgrade 在离线环境不可直接使用 ------会拉 https://aka.ms/... 失败。
✔ 正确流程
Step 1:从内网 mirror repo 下载新版 MSI
Step 2:静默升级安装
msiexec /i AzureCLI.msi /quiet
Step 3:重启 shell,重新加载
✔ 验证
az version
期望 :azure-cli 字段显式显示新版本号(不是缓存旧值------这是"假升级"陷阱)。
⚠ 故障模式
|-------------------|---------------|--------------------------------|
| 问题 | 原因 | 排查 |
| upgrade no effect | cached CLI | 重启 shell / where.exe az 确认路径 |
| extension broken | version drift | 重新装匹配版本的 extension |
7. 健康检查(Post-Install Validation Gate)
✔ 必须全部通过
az version
az cloud show
az account show
az extension list
✔ 成功标准
|-----------|-------------------------------------|
| 项目 | 条件 |
| CLI | 2.81.0(或当前文档版本) |
| cloud | custom disconnected cloud |
| login | az account show 返回本地 subscription |
| extension | 全部 Installed |
4 项检查全部通过 才能认为 CLI 配置完成------任一失败不能进入下一阶段。
8. Failure Recovery(恢复路径)
❌ Cloud misconfiguration
az cloud set --name AzureCloud
# 重新生成 cloud config(参考 §3)
❌ CA failure
# 删除错误 cert
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { ... } | Remove-Item
# 重新 import
Import-Certificate -FilePath "C:\AzureLocal\applianceRoot.cer" -CertStoreLocation Cert:\LocalMachine\Root
❌ Extension corruption
az extension remove -n <name>
# 重新 copy 离线包
az extension add --source <local-path>
❌ CLI 假升级(缓存旧版)
where.exe az
# 确认实际加载的 CLI 路径
# 删除旧 MSI 残留,重装新版
9. 最终架构总结(理解层)
User CLI
↓
Azure CLI Runtime (Python)
↓
Cloud Config (custom endpoint)
↓
OS Trust Store (CA chain)
↓
Azure Local Control Plane
一句话总结 :这套 Runbook 的本质是 把 Azure CLI 从"云 CLI"变成"本地控制平面客户端"。
🔍 Technical Analysis(Including Inferred Behavior)
本节是 Runbook 推理依据的存档------所有"为什么这么做"都在这里。不混入执行步骤。
A. CLI 与架构选择
A.1 为什么统一 64-bit
官方从未说 Azure Local 禁止 32-bit,但也不支持 32-bit 作为推荐路径。
32-bit 不是 hard failure ,而是 unsupported + untested:
- 32-bit Azure CLI 实际可装、可运行
- 但不在 Microsoft 测试矩阵内
- 可能引入兼容性 / 内存 / extension 加载问题
企业部署原则:按 supported 路径走,不赌 untested 边缘场景。
A.2 32-bit 实际风险(不是技术禁止)
- Python 32-bit 内存上限(典型 2 GB)------ 大型 ARM 调用可能 OOM
- Extension 兼容性矩阵窄
- 32-bit MSI 不是 Microsoft 在 Azure Local 场景的推荐路径
结论 :技术上不"禁止",但工程上不推荐------Runbook 不应该把"unsupported"包装成"禁止"。
B. CA 信任链
B.1 pip-system-certs 的真实作用范围
pip-system-certs只影响 Pythonrequests库的 HTTP 调用。关键点:
- Python-based extension → 受影响 ✔
- Go / .NET / native binary extension → 不受影响 ❌
- WinHTTP / Schannel 路径 → 不受影响 ❌
因此 OS trust store +
pip-system-certs是增强信任 ,不是完全替代 trust chain ------但已经是最稳妥的方案。
B.2 完整 CA 信任链路(企业部署应全部覆盖)
|---------------------------------------|---------------------------------------|
| 信任层 | 是否受 pip-system-certs 影响 |
| OS trust store(LocalMachine\Root) | OS 层 + 多数 native TLS |
| Python requests 信任 | ✔(通过 pip-system-certs) |
| CLI extension 内部 native TLS | ❌(自行保证) |
| Embedded tools(K8s client、Arc bridge) | ❌(走各自 trust chain) |
| 浏览器(用于本地 portal) | 系统级,OS trust store 已覆盖 |
缺失任一环节都可能导致部分功能 SSL 失败。
B.3 为什么禁止改 cacert.pem
|------------------|------------------------------------|
| 风险 | 说明 |
| az upgrade 覆盖 | CLI 升级时 cacert.pem 被重置 |
| pip upgrade 重置 | 任何包管理操作都可能 drift |
| 配置漂移 | 多节点场景下很快不一致 |
| 审计风险 | 标为 enterprise security baseline 偏离 |
C. Extension 与 Versioning
C.1 Extension 版本是 release-train 绑定
stack-hci-vm/aksarc/customlocation强依赖 Azure Arc / Azure Local release train- 经常月更甚至周更
- 不存在 "跨文档统一推荐版本"
- VM 文档与 AKS 文档给的版本经常不一致------优先以最新文档为准
C.2 Extension 解析源(implementation-dependent)
⚠️ extension resolution 取决于 configured source------不是固定机制:
可能是以下之一(或组合):
- Azure endpoint(
az extension add默认)
- Arc resource provider feed
- local cache(离线环境)
- custom repo(内网镜像)
不要在文档中固化 "Appliance 内置 extension 索引"这种说法------它不是稳定公开机制。
C.3 Get-ApplianceAzCliCloudConfig 的版本漂移
官方没说"参数会变化"------但 OperationsModule 是 Microsoft 持续更新的组件。
真实风险:
- 字段命名 / 必需参数可能随版本调整
- 输出 JSON schema 可能更新
- 甚至 function itself may be replaced across module versions(更激进的版本变化)
应对:
- 不要把生成的 JSON 当成"稳定 API"
- 每次升级 OperationsModule 后重新跑
Get-Help
D. CLI 升级与"假升级"风险
D.1 Air-gapped 下 az upgrade 的陷阱
- Air-gapped 模式下
az upgrade拉https://aka.ms/...会失败
- 部分 CLI 工具会静默 fallback 到本地缓存版本
- 表面看
az version没变------实际你以为升级了,但没有验证 :升级后
az version必须显式显示新版本号,否则视为升级失败。
D.2 正确的离线升级路径
|--------|----------------------------------|
| 步骤 | 操作 |
| 1 | 内网 mirror repo 下载新版 MSI |
| 2 | msiexec /i AzureCLI.msi /quiet |
| 3 | 重启 shell |
| 4 | where.exe az 确认路径 |
| 5 | az version 显式验证 |
E. Cloud Config 的实际语义
- Azure Local disconnected environment 确实需要 custom cloud definition
- endpoint override 指向本地 portal 的 ingress FQDN
- 这是离线场景的核心 ------没有这一步,
az login会去找management.azure.com然后失败
F. 跨版本兼容性
官方没给出"完整兼容矩阵"------但可以从 release train 推断:
|---------------------------|-------------------------|
| 组件 | 升级顺序 |
| Azure Local release notes | 起点 |
| Appliance build | 配套 |
| OperationsModule | 配套 |
| CLI | 与 OperationsModule 兼容 |
| extension | 绑定到 CLI + release train |
生产升级顺序:
- 升级前:看 Azure Local release notes
- CLI → 2. extension → 3. OperationsModule → 4. Appliance
- 逐项验证------不要跨大版本
G. 为什么离线下 az login --use-device-code 是关键
--use-device-code不要求本地有浏览器- 用户在任何能访问 local portal 的机器上输入 code 即可
- 这正是离线场景的登录模式 ------
az login走 local portal,认证回调走 device code
H. 文档未明确的边界(汇总)
|-------------------------------------|-----------------------------------|
| 文档没说 | Runbook 推断 |
| 是否能装 32-bit | unsupported + untested,按 64-bit 走 |
| cacert.pem 修改的后果 | drift / 升级丢失 / 审计风险,禁止 |
| extension source 机制 | implementation-dependent,看内网配置 |
| Get-ApplianceAzCliCloudConfig 稳定性 | 每次升级重新跑 Get-Help |
| az upgrade 离线行为 | 静默 fallback,必须显式验证 |