上一篇 下一篇 分享链接 返回 返回顶部

在香港服务器中,如何利用Windows Server的PowerShell DSC实现跨数据中心的自动化配置与统一管理?

发布人:Minchunlin 发布时间:2025-08-19 09:25 阅读量:720


那天是台风“打烊”的凌晨两点,香港将军澳机房的走廊里只有空调的低鸣和机柜风扇的“嗡嗡”。香港一侧的业务要在新加坡 DR 侧同构起来,应用栈要统一、补丁要统一、安全基线要统一,最要命的是——一键可回滚。我盯着 KVM 上那片蓝色的 Windows Server 登录界面,心里只有一个念头:

这活,得让 PowerShell DSC 来接管。

下面这篇,就是我如何在**香港主数据中心(HKDC)与新加坡灾备中心(SGDC)**之间,用 Windows PowerShell Desired State Configuration(DSC)搭起可审计、可回滚、跨地域容灾的自动化配置系统的全过程。你会看到真实机房里的细节、参数、坑点和我当时的取舍。

1. 背景与目标

目标:

香港与新加坡两地数百台 Windows Server 2019/2022 的统一配置(功能、角色、安全基线、IIS、日志)

跨 DC 的自动化与可回滚,对变更具备可视化合规与漂移自动纠正

低风险发布(灰度 / 金丝雀节点 / 蓝绿切换),并能断网自愈(就地缓存+重试)

为何选 DSC:

声明式:说“要什么”,而不是“怎么做”;幂等、天然适合漂移纠正

Pull 模式:中心化编译、版本化,节点自取;跨 DC 部署天然简化

合规审计:带合规上报(Compliance),与事件日志打通

2. 基础架构与硬件参数(节选)

机房 机型 CPU 内存 系统盘 数据盘 网卡 OS 备注
HKDC(将军澳) Dell R650 2×Xeon Gold 6330 256 GB 2×480G SATA SSD (RAID1) 4×1.92TB NVMe 2×10GbE Intel X710 Windows Server 2022 Datacenter iDRAC 直连 OOB
SGDC(樟宜) Dell R740xd 2×Xeon Gold 6230R 256 GB 2×480G SATA SSD (RAID1) 6×1.92TB NVMe 2×10GbE Intel X710 Windows Server 2019/2022 iDRAC 直连 OOB

网络要点:

  • HK ↔ SG 专线,RTT ~ 35–40ms(夜间测得,iperf3 与 Ping 双验证)
  • 管控网(VLAN 210)、业务网(VLAN 220)、备份网(VLAN 230)三网隔离
  • Pull Server 使用 443/HTTPS,节点使用出网 ACL 放行 443 即可

3. 方案设计(高层)

        [编译/签发站]               [HK Pull/Report]           [SG Pull/Report]
           (CI/CD)                   (IIS + DSC)                 (IIS + DSC)
               │                           │                           │
        生成 MOF/校验/模块         配置/模块/合规上报端点        配置/模块/合规上报端点
               │                           │                           │
               └───(RoboCopy/CI)───────────┼─────────(RoboCopy/CI)─────┘
                                           │
                        ┌──────────────────┴──────────────────┐
                        │                                     │
                  [HK 节点群]                           [SG 节点群]
          LCM Pull -> HK 为主 | SG 兜底        LCM Pull -> SG 为主 | HK 兜底
     (漂移纠正/合规上报/版本回滚)       (漂移纠正/合规上报/版本回滚)

 

关键选择:

  • 每个 DC 部署独立 Pull+Compliance Server,互为只读镜像(配置与模块通过 CI 同步)
  • 节点 LCM 配置双仓库(本地优先、对端为兜底)
  • 按“配置名称(Configuration Names)”拉取(而非固定 GUID),配合分层/分角色架构
  • 版本化(配置 zip + 模块 zip)+ 金丝雀 → 批量 → 蓝绿

4. 准备工作(实战 Checklist)

  • 证书:每个 Pull Server 使用机房内 CA 签发的 Server Auth 证书(CN 为 FQDN)
  • 注册密钥:C:\Program Files\WindowsPowerShell\DscService\RegistrationKeys.txt 写入 GUID
  • 模块仓:统一模块版本(如 PSDscResources / ComputerManagementDsc / NetworkingDsc / SecurityPolicyDsc / xWebAdministration)
  • DNS:hk-pull.company.local 与 sg-pull.company.local
  • 权限:文件夹 ACL 最小化;IIS 应用池使用内置账户即可(只读配置路径)
  • CI:编译配置、打包模块、推送至两地 Pull Server(RoboCopy/Artifact)

5. 在每个机房部署 Pull/Compliance Server(IIS 方式)

我们实际采用 IIS + xDscWebService 来搭 OData 端点,实践里非常稳。

(1)安装必要组件

# 以管理员身份在 Pull 机执行
Install-WindowsFeature -Name Web-Server,Web-WebServer,Web-Asp-Net45,Web-Static-Content,Web-Default-Doc,Web-Http-Errors,Web-Http-Logging,Web-Request-Monitor,Web-Stat-Compression,NET-Framework-45-Features -IncludeManagementTools

# DSC 服务特性
Install-WindowsFeature -Name DSC-Service

(2)使用 xPSDesiredStateConfiguration 搭建端点

我们在生产中固定了版本,避免资源变更带来的不确定性。(版本可按你环境替换)

# 仅示例版本,请按需固化
Install-Module -Name xPSDesiredStateConfiguration -RequiredVersion 9.1.0 -Force
Install-Module -Name xWebAdministration -RequiredVersion 3.3.0 -Force

$Thumb = (Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -like '*hk-pull.company.local*' }).Thumbprint
$RegKeyPath = 'C:\Program Files\WindowsPowerShell\DscService\RegistrationKeys.txt'
'8e0f1a7e-7c46-4e3b-8a1c-1f8c0c9a9f01' | Out-File -Encoding ascii -FilePath $RegKeyPath -Force

Configuration DscPullServer_HK {
    Import-DscResource -ModuleName xPSDesiredStateConfiguration

    Node 'HK-PULL-01' {
        WindowsFeature DSCServiceFeature { Name = 'DSC-Service'; Ensure = 'Present' }

        xDscWebService PSDSCPullServer {
            Ensure                  = 'Present'
            EndpointName            = 'PSDSCPullServer'
            Port                    = 443
            PhysicalPath            = "$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer"
            CertificateThumbPrint   = $Thumb
            ModulePath              = "$env:ProgramFiles\WindowsPowerShell\DscService\Modules"
            ConfigurationPath       = "$env:ProgramFiles\WindowsPowerShell\DscService\Configuration"
            State                   = 'Started'
            UseSecurityBestPractices = $true
            RegistrationKeyPath     = $RegKeyPath
            DependsOn               = '[WindowsFeature]DSCServiceFeature'
        }

        xDscWebService PSDSCComplianceServer {
            Ensure                  = 'Present'
            EndpointName            = 'PSDSCComplianceServer'
            Port                    = 443
            PhysicalPath            = "$env:SystemDrive\inetpub\wwwroot\PSDSCComplianceServer"
            CertificateThumbPrint   = $Thumb
            State                   = 'Started'
            UseSecurityBestPractices = $true
            RegistrationKeyPath     = $RegKeyPath
            IsComplianceServer      = $true
            DependsOn               = '[WindowsFeature]DSCServiceFeature'
        }
    }
}

DscPullServer_HK -OutputPath C:\DSC\PullHK
Start-DscConfiguration -Path C:\DSC\PullHK -Verbose -Wait -Force

在 SG 机房同理部署,改为 sg-pull.company.local 与对应证书即可。

6. 分层设计:配置“按名称”拉取(可组合)

我们把配置拆成三层,每层一个 Configuration Name,节点按角色组合拉取:

  • Base:安全基线、常用功能、系统参数
  • IISRole:IIS 及站点、日志轮转、AppPool
  • AppNode:应用包、依赖、环境变量、Windows 防火墙规则

(1)编写配置(节选)

# 基础模块(版本可按需固化)
Install-Module PSDscResources -Force
Install-Module ComputerManagementDsc -Force
Install-Module NetworkingDsc -Force
Install-Module SecurityPolicyDsc -Force
Install-Module xWebAdministration -Force

# Base 层
Configuration Base {
    Import-DscResource -ModuleName PSDscResources, ComputerManagementDsc, NetworkingDsc, SecurityPolicyDsc

    param([Parameter(Mandatory)][Hashtable]$AllNodes)

    Node $AllNodes.NodeName {

        # 时区、主机名(示例)
        Registry SetTimeZone {
            Key = 'HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation'
            ValueName = 'TimeZoneKeyName'
            ValueData = 'China Standard Time'
            Ensure = 'Present'
        }

        # 常用功能
        WindowsFeature TelnetClient { Name = 'Telnet-Client'; Ensure = 'Absent' } # 基线要求禁用
        WindowsFeature NETFramework45 { Name = 'NET-Framework-45-Features'; Ensure = 'Present' }

        # 本地管理员组
        Group LocalAdmins {
            GroupName = 'Administrators'
            Ensure    = 'Present'
            MembersToInclude = @('DOMAIN\OpsTeam')
        }

        # 安全策略示例:禁用 SMBv1
        Registry DisableSMB1 {
            Key = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'
            ValueName = 'SMB1'
            ValueData = 0
            ValueType = 'Dword'
            Ensure = 'Present'
        }
    }
}

# IIS 层
Configuration IISRole {
    Import-DscResource -ModuleName PSDscResources, xWebAdministration

    param([Hashtable]$AllNodes)

    Node $AllNodes.NodeName {
        WindowsFeature IIS { Name = 'Web-Server'; Ensure = 'Present' }
        WindowsFeature AspNet45 { Name = 'Web-Asp-Net45'; Ensure = 'Present' }

        xWebAppPool AppPool {
            Name = 'AppPool_Main'
            autoStart = $true
            managedRuntimeVersion = 'v4.0'
            state = 'Started'
            ensure = 'Present'
        }

        xWebsite Site {
            Ensure          = 'Present'
            Name            = 'MainSite'
            State           = 'Started'
            PhysicalPath    = 'C:\inetpub\MainSite'
            ApplicationPool = 'AppPool_Main'
            BindingInfo     = @(
                MSFT_xWebBindingInformation{
                    Protocol = "https"; Port = 443; CertificateStoreName = "My"; CertificateThumbprint = '<SITE_CERT_THUMB>'
                }
            )
            DependsOn       = '[WindowsFeature]IIS','[WindowsFeature]AspNet45','[xWebAppPool]AppPool'
        }
    }
}

# 应用层(示例:下发包 & 环境变量)
Configuration AppNode {
    Import-DscResource -ModuleName PSDscResources

    param([Hashtable]$AllNodes)

    Node $AllNodes.NodeName {
        File AppContent {
            Ensure = 'Present'
            Type   = 'Directory'
            SourcePath = '\\fileserver\release\MainSite\v2.3.4'
            DestinationPath = 'C:\inetpub\MainSite'
            Recurse = $true
            MatchSource = $true
        }

        Environment APP_ENV {
            Ensure = 'Present'
            Name   = 'APP_ENV'
            Value  = 'Production'
        }
    }
}

(2)ConfigurationData(支持跨 DC 差异)

$ConfigData = @{
    AllNodes = @(
        @{ NodeName='HK-APP-01'; DC='HK';  Role=@('Base','IISRole','AppNode') },
        @{ NodeName='HK-APP-02'; DC='HK';  Role=@('Base','IISRole','AppNode') },
        @{ NodeName='SG-APP-01'; DC='SG';  Role=@('Base','IISRole','AppNode') }
    )
}

(3)编译与产物放置

# 编译
Base -ConfigurationData $ConfigData -OutputPath C:\DSC\Out\Base
IISRole -ConfigurationData $ConfigData -OutputPath C:\DSC\Out\IISRole
AppNode -ConfigurationData $ConfigData -OutputPath C:\DSC\Out\AppNode

# 将下列文件放入 Pull Server:
#   配置文件:C:\Program Files\WindowsPowerShell\DscService\Configuration\*.mof
#   模块包:  C:\Program Files\WindowsPowerShell\DscService\Modules\<ModuleName>_<Version>.zip

# 生成校验文件(必须)
New-DscChecksum -Path "C:\Program Files\WindowsPowerShell\DscService\Configuration" -Force
New-DscChecksum -Path "C:\Program Files\WindowsPowerShell\DscService\Modules" -Force

注意:Configuration Names 模式要求配置文件命名与配置名一致,如 Base.mof、IISRole.mof、AppNode.mof(或 <ConfigurationName>.mof 及对应 .checksum),节点 LCM 中声明要拉取哪些配置名。

7. LCM 元配置:双仓库 + 合规上报

节点一次性注入 LCM(批量可用 Ansible/WinRM/AD GPO/SCCM 触发 PowerShell):

[DSCLocalConfigurationManager()]
Configuration LCM_DualRepo {
    param(
        [Parameter(Mandatory)][string]$HKUrl,
        [Parameter(Mandatory)][string]$SGUrl,
        [Parameter(Mandatory)][string]$HKReportUrl,
        [Parameter(Mandatory)][string]$SGReportUrl,
        [Parameter(Mandatory)][string]$RegistrationKey
    )

    Node localhost {
        Settings {
            RefreshMode = 'Pull'
            ConfigurationMode = 'ApplyAndAutoCorrect'      # 自动纠偏
            ConfigurationModeFrequencyMins = 30            # 每 30 分钟执行一致性检查
            RefreshFrequencyMins = 15                      # 每 15 分钟询问一次 Pull
            RebootNodeIfNeeded = $true
            ActionAfterReboot = 'ContinueConfiguration'
            StatusRetentionTimeInDays = 30
        }

        # 模块与配置可指向同一端点
        ResourceRepositoryWeb HKRepo {
            ServerURL = $HKUrl
            RegistrationKey = $RegistrationKey
        }
        ResourceRepositoryWeb SGRepo {
            ServerURL = $SGUrl
            RegistrationKey = $RegistrationKey
        }

        ConfigurationRepositoryWeb HKPull {
            ServerURL = $HKUrl
            RegistrationKey = $RegistrationKey
            ConfigurationNames = @('Base','IISRole','AppNode')
        }
        ConfigurationRepositoryWeb SGPull {
            ServerURL = $SGUrl
            RegistrationKey = $RegistrationKey
            ConfigurationNames = @('Base','IISRole','AppNode')
        }

        ReportServerWeb HKReport {
            ServerURL = $HKReportUrl
            RegistrationKey = $RegistrationKey
        }
        ReportServerWeb SGReport {
            ServerURL = $SGReportUrl
            RegistrationKey = $RegistrationKey
        }
    }
}

$RegKey = '8e0f1a7e-7c46-4e3b-8a1c-1f8c0c9a9f01'

LCM_DualRepo `
 -HKUrl 'https://hk-pull.company.local/PSDSCPullServer.svc' `
 -SGUrl 'https://sg-pull.company.local/PSDSCPullServer.svc' `
 -HKReportUrl 'https://hk-pull.company.local/PSDSCComplianceServer.svc' `
 -SGReportUrl 'https://sg-pull.company.local/PSDSCComplianceServer.svc' `
 -RegistrationKey $RegKey `
 -OutputPath C:\DSC\LCM

Set-DscLocalConfigurationManager -Path C:\DSC\LCM -Verbose

验证:

Get-DscLocalConfigurationManager
Update-DscConfiguration -Verbose
Get-DscConfigurationStatus

经验:双仓库能显著提升跨 DC 的韧性。香港侧失联时,节点会自动退回 SG 仓库;网络恢复后仍会按频率与优先顺序更新。

8. 批量注册与角色绑定(CSV 驱动)

我们按 CSV 驱动批量注册节点要拉取的配置名(实战里多在 CMDB/AD 中维护):

# servers.csv: Node,Configs
# HK-APP-01,"Base;IISRole;AppNode"
# HK-APP-02,"Base;IISRole;AppNode"
# SG-APP-01,"Base;IISRole;AppNode"

Import-Csv .\servers.csv | ForEach-Object {
    $names = $_.Configs -split ';'
    [DSCLocalConfigurationManager()]
    Configuration BindConfigs {
        Node $_.Node {
            ConfigurationRepositoryWeb HKPull {
                ServerURL = 'https://hk-pull.company.local/PSDSCPullServer.svc'
                RegistrationKey = '8e0f1a7e-7c46-4e3b-8a1c-1f8c0c9a9f01'
                ConfigurationNames = $names
            }
        }
    }
    $out = "C:\DSC\LCM\$($_.Node)"
    BindConfigs -OutputPath $out
    Set-DscLocalConfigurationManager -Path $out
}

9. 合规与可视化(拉通运维台账)

拉取某节点最近一次状态(OData/REST):

# 合规状态(示例,生产中请使用认证/CA)
$uri = "https://hk-pull.company.local/PSDSCComplianceServer.svc/NodeReports()?$`filter=NodeName eq 'HK-APP-01'&$`top=1"
Invoke-RestMethod -Uri $uri -UseDefaultCredentials

事件日志查错:

  • Microsoft-Windows-DSC/Operational 日志,常见事件:4100/4102/4252/4250
  • 结合 SIEM(我们把关键事件转发到集中日志),设置“配置失败率 > 3% 告警”

10. 版本化、灰度与回滚

版本化策略:

配置 Base_2024.12.1.zip / IISRole_2.5.0.zip / AppNode_2.3.4.zip,只增不改

配置生效采用 金丝雀 5% → 25% → 100%,阶段间隔 30–60 分钟

回滚:将 Configuration 目录中的目标配置名回指到上一版本的 MOF,重新 New-DscChecksum 即可;节点自动回收

控制面板(我们做了个很朴素的 PowerShell 报表脚本):

  • 统计:冲突/失败节点、平均收敛时长、失败 TopN 资源
  • 按 DC、按角色、按版本维度出表

11. 实战坑点与解决手记

证书拇指指纹不对

现象:LCM 注册时报 TLS 错

排查:Test-WSMan 成功,Invoke-RestMethod 失败;发现配置用的是旧证书

解决:统一从 Cert:\LocalMachine\My 动态抓取FQDN 匹配的 Thumbprint,写死就会踩坑

校验文件缺失

现象:Pull Server 日志提示checksum mismatch,节点一直不更新

解决:每次更新配置/模块后务必 New-DscChecksum,并确认 zip 与 mof 同名同目录

模块体积过大、跨 DC 超时

现象:首次拉取时 SG 节点下载极慢

解决:两地各有 Pull 的模块仓;IIS 打开压缩;必要时先通过软件分发预置模块

部分资源非幂等(第三方 DSC 资源写得不规范)

现象:重复应用导致配置抖动

解决:通过包装 Composite Resource 二次封装,加“状态判断”或换等价资源

Partial Configuration 顺序问题

现象:AppNode 先于 IISRole 导致站点不可用

解决:我们改用按名称拉取 + 资源依赖,或在 LCM 里显式设置 Partial 的顺序(如需)

TLS 配置不一致

现象:只在 HK 能拉取,SG 失败

解决:两地统一启用 SchUseStrongCrypto 与 TLS1.2;GPO 统一下发

WinRM/代理干扰

现象:节点只能上报不能拉取

解决:LCM 设置使用直连;确认服务器无系统代理;IIS 访问日志核对 443 命中

12. 结果对比(上线前后指标)

指标 上线前(人工脚本) 上线后(DSC)
首次环境拉起(单节点) 2–3 小时 20–30 分钟
大批量一致性修复(50 台) 1–2 天 ≤ 1 小时(并行+自动纠偏)
配置漂移率(月) ~12% <2%
变更失败率 5–8% <1.5%(金丝雀+回滚)
审计取证时间 小时级 分钟级(合规端点 + 日志)

13. 你可以直接复用的“最小可用清单”

  1. 两地 Pull/Compliance Server(IIS + xDscWebService)
  2. 固化模块版本,只增不改
  3. “按名称拉取”的分层配置(Base / Role / App)
  4. LCM:双仓库、自动纠偏、30/15 频率
  5. CI:编译 → 推送 → 校验 一条龙
  6. 变更:金丝雀 → 分批 → 蓝绿,失败即回滚
  7. 观测:DSC 合规 + 事件日志 + 外部告警

14. 结尾:风平浪静之后

台风退了,机房的风也小了。我在将军澳关上笔记本,抬头看一排蓝灯整齐的 R650,心里有点“把复杂留给系统,把确定性交给人”的小得意。

第二天早会,业务同事问:“昨晚新加坡 DR 配了多久?”

我说:“半小时。真正花时间的,是我们把每个细节都预想过。”

如果你也正好在香港运营一套 Windows 集群,或者要把配置“跨海”复制到新加坡,不妨照着这套思路和脚本走一遍。DSC 的魅力就在于:把“理想态”写下来,剩下的交给它不断把现实对齐。

附:实用命令速查

# 手工触发一次拉取与收敛
Update-DscConfiguration -Verbose

# 查看 LCM 配置
Get-DscLocalConfigurationManager

# 查看最近的收敛结果
Get-DscConfigurationStatus

# 导出当前实际状态(便于对比)
Get-DscConfiguration | Format-List *

# 事件日志查看(错误/警告)
Get-WinEvent -LogName 'Microsoft-Windows-DSC/Operational' | Select TimeCreated, Id, LevelDisplayName, Message | more
目录结构
全文