将旧版.NET和Windows应用程序迁移到 Azure Kubernetes 服务 (AKS) - 分步指南

本指南演示如何评估、规划和执行旧版 .NET Framework 和 Windows Internet Information Services (IIS) 应用程序的迁移,并将其迁移到 Azure Kubernetes 服务 (AKS)。 它专注于可用于大多数Microsoft商店的两个实用途径:

  • 容器化现有的 .NET Framework (IIS) 应用,并在 AKS 中的Windows节点池上运行它。
  • 将应用程序重构(或移植)到 .NET 8 和 Linux 容器,以便利用更小的镜像、更广泛的开源工具链以及成本更低的节点类型。

在此过程中,可以找到就绪情况清单、Windows节点池配置指南、AKS 上的工作示例(AKS 上的 VM → Windows 容器),以及Azure DevOps CI/CD 管道模板。

就绪情况评估 - .NET框架和Windows应用程序清单

在开始之前,请执行重点准备情况评估。 目标是识别会影响你是按现状在 Windows 上将该应用容器化,还是将其重构到 Linux/.NET 8 的阻碍因素。

  • IIS 依赖项

    • 应用是否需要完整的 IIS,包括模块、ASP.NET 集成、URL 重写规则或 ISAPI 筛选器?
    • 应用是否使用自定义 IIS 模块或本机 ISAPI 扩展?
    • 是否可以将配置移动到 web.config 容器映像中或将其嵌入其中?
  • Windows 身份验证和标识

    • 应用是否依赖于Windows集成身份验证(Kerberos 或 NTLM)?
    • 是否使用 Windows AD 域加入、计算机帐户或不受约束的委派?
    • 请注意:在妥善管理凭据的情况下,Windows 身份验证在 Windows 容器中更容易支持,但容器化的 Windows 应用无法像 VM 那样加入域。 替代方法包括Windows组托管服务帐户(GMSA)、托管标识、Microsoft Entra ID或反向代理模式。
  • 本地代码、COM 互操作和 32 位组件

    • 该应用是否调用与特定 Windows Server 版本或位数绑定的 COM 对象或本机 DLL?
      • 如果是这样,请验证这些 COM 对象是否可以在Windows Server核心容器映像中运行(不支持每个旧驱动程序或组件)。
  • 注册表和本地计算机状态

    • 应用程序是读取或写入计算机级注册表项还是依赖于本地计算机状态(HKLM)?
    • 将计算机特定的状态移动到配置或存储(Azure 文件存储、Blob 或外部 DB)。
  • 文件系统和会话状态

    • 应用是否使用文件上传、本地临时文件或进程内会话状态?
    • 规划如何将状态外部化(Azure Cache for Redis、SQL、Blob 存储或共享 SMB/Azure Files)。
  • 网络和端口

    • 需要哪些端口? 应用是否打开 UDP 套接字、使用随机临时端口或需要静态 IP?
    • Kubernetes 服务和负载均衡器会更改网络假设。 相应地规划服务/入口和运行状况探测。
  • 依赖于仅限 Windows 的服务

    • 重新审视打印后台处理程序、计划任务(任务计划程序)、Windows 服务或性能计数器。 有时可以将服务打包到容器中或重新构建它们。
  • 许可和第三方约束

    • 检查与计算机标识或硬件有联系的任何应用程序许可。 基于容器的许可可能需要供应商协调。

如果上述很多项都是阻碍因素,而且难以更改(例如 COM 互操作、较重的原生依赖、无法外置的 Windows 身份验证),那么选择 Windows 容器这一路径更为现实。 如果可以远离计算机级依赖项,并且应用主要使用托管代码,请考虑重构为 Linux 上的 .NET 8,以便长期可维护性并降低成本。

两个迁移路径 - 决策指南

路径 A - 在Windows节点池上容器化.NET框架(直接迁移)

  • 何时选择:

    • IIS 使用量大、依赖原生 COM,或者用于代码重写的预算或时间有限。
    • 需要最少的功能更改,并且想要快速关闭 VM。
  • 优点:

    • 最小代码更改;保留现有应用的行为。
    • 与全面重构相比,可更快投入生产。
  • 缺点:

    • Windows容器映像更大,资源成本更高。
    • 某些 Azure 和 Kubernetes 功能在 Windows 上存在限制,例如某些 CSI 驱动程序过去在 Windows 上的行为曾发生变化。
    • 与 Linux 容器相比,生态系统和可移植性更少。

路径 B — 重构到 .NET 8 和 Linux 节点池(现代化)

  • 何时选择:

    • 应用逻辑主要是托管代码,只需付出合理的工作量即可迁移到 .NET 8。
    • 需要更低的运营成本、较小的映像和更广泛的工具支持。
  • 优点:

    • 较小的图像、更好的密度、更快的启动、更多的社区工具和示例。
    • 更容易采用边车、多架构镜像以及开源 Ingress 和可观测性堆栈。
  • 缺点:

    • 需要开发人员时间来移植、测试和验证行为(IIS 功能需要更换)。
    • 某些仅限 Windows 的原生功能需要重新设计。

决策矩阵 (高级)

  • 如果必须保留 IIS 模块,Windows就地身份验证、COM 或本机依赖项,请选择Windows容器。
  • 如果应用程序主要是托管代码,或者想要现代化和优化成本,则移植到 .NET 8 和 Linux 容器。

Azure Migrate:应用容器化——面向 ASP.NET 应用的分步指南(目标为 AKS)

Azure Migrate提供用于发现的工具,并在某些流中提供容器化帮助。 以下部分中的步骤概述了一个实际流程:发现→生成容器映像→推送到 ACR →部署到 AKS。

  1. 发现和盘点

    1. 在承载你的 ASP.NET 应用的虚拟机上执行发现操作(使用 Azure Migrate 设备或你现有的任何清点工具)。
    2. 捕获已安装的 .NET 版本、IIS 模块、原生依赖项、读取和写入的注册表项以及网络端口。
  2. 创建容器化计划

    1. 选择基础映像:对于 .NET Framework/ASP.NET,请使用基于 Windows Server Core ASP.NET 基础映像(请参阅以下部分中的 Dockerfile 示例)。
    2. 决定如何处理配置:将机密迁移到 Azure 密钥保管库 或 Kubernetes Secrets 中,并将 appSettings 迁移到环境变量或 ConfigMap 中。
  3. 生成Windows容器映像(本地证明)

    1. 创建 Dockerfile,用于安装和配置 IIS、复制应用并公开所需的端口(通常为 80/443)。
    2. 在本地构建并运行(或在 Windows 构建代理上构建并运行),以验证应用程序能够启动并提供页面。
  4. 推送到 Azure 容器注册表(ACR)

    1. 创建 ACR 或重复使用现有注册表。
    2. 在 Windows 构建主机或带有 Windows 构建代理的 Azure Pipelines 中标记并推送映像(docker push)。
  5. 准备 AKS 群集

    1. 使用 Linux 系统节点池创建 AKS 群集,以便控制平面工作负载和入口,并为 IIS 应用添加Windows节点池(请参阅节点池设置的下一部分)。
    2. 确保配置了网络策略、容器映像的策略和基于角色的访问。
  6. 将清单部署到 AKS

    1. 创建 Kubernetes 对象:部署(nodeSelector: windows)、服务(ClusterIPLoadBalancer)以及任何 ConfigMap 或机密。
    2. 使用运行在 Linux 节点池上的基于 Linux 的 Ingress 控制器 (nginx) 为 Windows 工作负载提供前端入口,或者使用 LoadBalancer 服务将其公开。
  7. 配置运行状况探测和日志记录

    1. 配置命中应用服务的 HTTP 终结点的实时性和就绪情况探测。
    2. 将日志接入 Azure Monitor(容器洞察)或集中式日志解决方案。
  8. 验证并切换

    1. 运行功能测试、性能测试,以及验证会话和行为。
    2. 逐步切换流量(采用蓝绿或金丝雀方式)并进行监控。

备注

  • 生成Windows容器映像需要Windows生成代理或运行程序。 无法在 Linux 主机上生成Windows映像。
  • 确保映像 OS 版本(Windows Server核心版)与 AKS 中的Windows节点 OS 版本匹配或兼容。

工作示例 - 使用 Azure DevOps CI/CD 将旧版 IIS/.NET 框架应用从 VM 迁移到 AKS Windows 容器

本工作示例演示如何使用 Windows 容器将托管在 Windows Server VM 上的单个 IIS/.NET Framework 4.8 应用移动到 AKS。 其中演示了 Dockerfile、Kubernetes 清单文件以及一个简单的 Azure DevOps 管道。

假设:

  • 你有一个 Azure 订阅、一个包含至少一个 Windows 节点池的 AKS 群集,以及一个 Azure 容器注册表(ACR)。
  • 你有一个Azure DevOps项目,其服务连接到Azure和 ACR(或者服务连接可以推送到 ACR)。
  • 应用在 .NET Framework 4.8 上运行,并使用标准 web.config。
  1. ASP.NET 的 Dockerfile(.NET Framework 4.8)— Windows Server Core 基础映像

    # Use an official ASP.NET image for .NET Framework on Windows Server Core
    FROM mcr.azk8s.cn/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019
    
    # Optional: install additional Windows features or native dependencies here
    # RUN powershell -NoProfile -Command Install-WindowsFeature Web-Server, ...
    
    WORKDIR /inetpub/wwwroot
    
    # Remove default site files and copy your app
    RUN powershell -NoProfile -Command Remove-Item -Recurse -Force C:\inetpub\wwwroot\*
    COPY . C:\inetpub\wwwroot
    
    # Expose HTTP port
    EXPOSE 80
    
    # Default entry is IIS (already configured by base image)
    

    Notes:

    • 在Windows生成代理(Azure DevOps自承载Windows代理或Microsoft托管windows-latest)上生成此映像。
    • 如果应用依赖于本机安装程序或 COM 组件,请添加 RUN 步骤以在映像生成期间安装这些组件。
  2. Kubernetes Manifest

    部署(windows-app-deployment.yml)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: legacy-iis-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: legacy-iis-app
      template:
        metadata:
          labels:
            app: legacy-iis-app
        spec:
          nodeSelector:
            "kubernetes.io/os": windows
          containers:
          - name: legacy-iis-app
            image: <ACR_NAME>.azurecr.cn/legacy-iis-app:$(TAG)
            ports:
            - containerPort: 80
            livenessProbe:
              httpGet:
                path: /healthz
                port: 80
              initialDelaySeconds: 30
              periodSeconds: 20
            readinessProbe:
              httpGet:
                path: /
                port: 80
              initialDelaySeconds: 10
              periodSeconds: 10
    

    服务(windows-app-service.yml)

    apiVersion: v1
    kind: Service
    metadata:
      name: legacy-iis-lb
    spec:
      type: LoadBalancer
      selector:
        app: legacy-iis-app
      ports:
      - protocol: TCP
        port: 80
        targetPort: 80
    

    Notes:

    • 或者,将 Linux 托管的入口控制器置于此服务前面(建议用于高级路由、TLS 和 WAF 功能)。 对于简单的平移迁移,LoadBalancer 类型的 Service 将对外暴露该应用。
  3. Azure DevOps 管道(azure-pipelines.yml)

    trigger:
    - main
    
    variables:
      imageName: legacy-iis-app
      acrName: <ACR_NAME>
      kubernetesNamespace: default
      tag: $(Build.BuildId)
    
    pool:
      vmImage: 'windows-latest'
    
    steps:
    - task: Checkout@1
    
    - task: Docker@2
      displayName: Build and push Windows image to ACR
      inputs:
        containerRegistry: '<YourACRServiceConnection>' # service connection name
        repository: '$(acrName).azurecr.cn/$(imageName)'
        command: buildAndPush
        Dockerfile: '**/Dockerfile'
        tags: |
          $(tag)
    
    - task: AzureCLI@2
      displayName: 'kubectl apply manifests'
      inputs:
        azureSubscription: '<YourAzureServiceConnection>'
        scriptType: bash
        scriptLocation: inlineScript
        inlineScript: |
          az aks get-credentials --resource-group <AKS_RESOURCE_GROUP> --name <AKS_CLUSTER_NAME> --overwrite-existing
          kubectl set image deployment/legacy-iis-app legacy-iis-app $(acrName).azurecr.cn/$(imageName):$(tag) --namespace $(kubernetesNamespace) || kubectl apply -f k8s/
    

    管道说明:

    • 使用Windows主机生成Windows容器映像。
    • Docker@2 buildAndPush 需要能够构建 Windows 映像的 Docker 主机——如果 Microsoft 托管代理不支持所需功能,请考虑使用自托管 Windows 代理。
    • Azure CLI步骤对 AKS 进行身份验证并更新部署映像(或在首次运行时应用清单)。
  4. AKS 群集和节点池创建(示例 CLI) -1。 使用 Linux 控制平面和Windows节点池创建 AKS 群集(az cli 示例):

    # Create cluster with Linux node pool (default)
    az aks create \
       --resource-group my-rg \
       --name my-aks-cluster \
       --kubernetes-version <kubernetes-version> \
       --node-count 2 \
       --enable-managed-identity \
       --generate-ssh-keys
    
    # Add a Windows node pool
    az aks nodepool add \
       --resource-group my-rg \
       --cluster-name my-aks-cluster \
       --os-type Windows \
       --os-sku Windows2025 \
       --enable-fips-image \
       --name npwin \
       --node-count 2 \
       --node-vm-size Standard_D4s_v5 \
       --kubernetes-version <kubernetes-version>
    

    Notes:

    • 请使用 AKS 文档获取与当前 Azure CLI 和 AKS 版本完全对应的 az 命令。
    • 确保 AKS Kubernetes 版本支持所选Windows节点池版本。
  5. 部署和验证

    1. 推送镜像;部署清单文件;等待 Pod 被调度到 Windows 节点上。
    2. 使用 kubectl get pods -o wide 进行验证,以确认节点操作系统及其发行版。
    3. 通过Azure Monitor运行功能冒烟测试和监视日志。

常见陷阱和故障排除

  • 在 Linux 上生成Windows映像:无法在 Linux 主机上生成Windows容器- 使用Windows生成代理。
  • OS 镜像不匹配:如果容器基础镜像的操作系统与节点操作系统版本不匹配,Pod 可能会因镜像错误而无法启动。 在映像和节点之间对齐LTSC2019与LTSC2022。
  • 不支持的 CSI 驱动程序或卷插件:并非所有 CSI 驱动程序都支持 Windows 平台。 验证持久卷要求和驱动程序兼容性。
  • 健康探测失败:基于 IIS 的应用有时启动时间较长;请使用适当的 initialDelaySeconds 和 timeoutSeconds 配置存活/就绪探测。
  • Windows 身份验证的复杂性:集成 Windows 身份验证通常需要重新调整;请考虑在应用前端部署一个处理身份验证的反向代理,或者在可能的情况下改用 Microsoft Entra ID 身份验证。
  • 防火墙和 NSG 规则:确保出站/入站规则和 AKS 网络设置允许 ACR 拉取、Azure Monitor引入以及任何后端依赖项。
  • 日志记录和事件收集:配置Windows事件日志和 IIS 日志的集合;验证代理兼容性。

何时重新构建而不是容器化

容器化会保留应用行为,但不会自动实现基本代码的现代化。 如果出现以下情况,请考虑进行重构:

  • 想要采用微服务、新式托管模式或跨平台兼容性。
  • 你需要降低成本并提高密度。
  • 应用需要对容器中的功能进行大量更改(同步文件系统使用、计算机级注册表写入等)。 此时,请投资移植到 .NET 8 和 Linux,从而获得更长期的灵活性。

后续步骤

  • 对所有候选应用程序进行就绪情况评估,并将其分类为“在 Windows 上容器化”、“重构为 .NET 8”或“停用/替换”。
  • 为了快速获胜,请先容器化风险最低的应用,并将它们部署到具有Windows节点池的非生产 AKS 群集。
  • 为了推进现代化改造,请创建迁移待办事项列表,逐步将各项功能迁移到 .NET 8,设计无状态服务,并将状态迁移到托管服务。
  • 集成 CI/CD 和 DevOps 实践(例如 AKS 群集和节点池的 IaC,以及 Windows 映像的管道构建)。
  • 请参阅 AKS Windows 节点指南和 ASP.NET 容器化文档:

本指南旨在作为将旧版.NET/Windows应用程序迁移到 AKS 的实用路线图。 对于大型或高度有状态的应用程序,请通过彻底测试规划迭代迁移,如果具有专用 COM/本机依赖项或复杂的Windows身份验证要求,请考虑吸引迁移合作伙伴。