AML避坑指南:手把手教你编写规范的K8s资源清单

2026/01/12 k8s 共 4692 字,约 14 分钟

AML避坑指南:手把手教你编写规范的K8s资源清单

在Azure Machine Learning(AML)中,使用Kubernetes作为计算目标进行模型训练和部署,已成为处理复杂、大规模机器学习工作负载的流行选择。其核心在于通过Kubernetes资源清单(通常是YAML文件)来定义计算环境。一份编写规范的清单是稳定、高效运行的基础,反之,则可能引发资源争抢、调度失败、服务不稳定等一系列问题。本文将手把手带你避开常见陷阱,编写出专业的K8s资源清单。

一、 理解AML与K8s的交互模式

在开始编写之前,需要明确AML如何与你的Kubernetes集群交互。当你将K8s集群附加为AML的计算目标后,AML服务会通过其操作员(Operator)或直接在指定命名空间中,根据你提供的资源清单创建和管理Kubernetes原生资源,如PodServiceDeployment等,来执行训练任务或托管在线端点。

因此,你的清单文件必须符合Kubernetes API规范,同时也要考虑AML工作流的特定要求。

二、 资源清单基础结构与核心字段

一个典型的用于AML训练任务的Pod规格清单如下所示。我们将以此为例,拆解关键部分。

apiVersion: v1
kind: Pod # 也可以是 Deployment、Job 等
metadata:
  name: aml-training-pod # AML通常会覆盖此名称
  namespace: aml-compute # 必须与AML附加集群时指定的命名空间一致
  labels:
    app: ml-training
    aml.compute: “true” # 建议添加,便于识别
spec:
  containers:
  - name: training-container
    image: <your-training-image>
    command: [“python”, “train.py”]
    args: [“--data-path”, “/mnt/data”]
    resources:
      requests:
        memory: “8Gi”
        cpu: “2”
        nvidia.com/gpu: 1 # 申请GPU资源
      limits:
        memory: “10Gi”
        cpu: “3”
        nvidia.com/gpu: 1
    volumeMounts:
    - name: workspace-mount
      mountPath: /mnt/azureml
    - name: data-mount
      mountPath: /mnt/data
  volumes:
  - name: workspace-mount
    persistentVolumeClaim:
      claimName: azureml-fileshare-pvc # AML自动创建的PVC
  - name: data-mount
    emptyDir: {}
  nodeSelector: # 节点选择器
    accelerator: nvidia-gpu
  tolerations: # 容忍度
  - key: “sku”
    operator: “Equal”
    value: “gpu”
    effect: “NoSchedule”
  restartPolicy: OnFailure

关键字段解析与避坑点

1. resources:资源请求与限制

这是最核心也最容易出问题的部分。

  • requests: 调度依据。K8s调度器根据此值为Pod分配节点。如果集群中没有节点能满足所有容器的requests之和,Pod将处于Pending状态。
  • limits: 运行限制。容器运行时(如Docker)强制执行的上限。超过内存限制会导致容器被OOM Kill;超过CPU限制会被限制使用。

避坑指南:

  • 必须同时设置requestslimits: 只设limits不设requestsrequests默认等于limits,可能导致调度困难。只设requests不设limits,容器可能耗尽节点资源。
  • requestslimits值应合理: 对于CPU,limits可略高于requests(如requests: 2, limits: 3)。对于内存,强烈建议requests等于limits,以避免因内存波动导致的不稳定OOM Kill。例如 memory: “8Gi”
  • GPU资源: 使用 nvidia.com/gpu 这样的扩展资源。GPU通常不可超售,因此requestslimits必须相等。

2. nodeSelectortolerations:精准调度

当你的集群混合了CPU和GPU节点,或者有不同规格的节点时,需要使用它们将Pod调度到正确节点。

  • nodeSelector: 简单直接,选择拥有特定标签的节点。
  • tolerations: 与节点的taints配合使用,允许Pod被调度到带有特定污点的节点上。GPU节点通常带有NoSchedule污点。

避坑指南:

  • 确保你指定的节点标签或污点存在于目标节点上。可以通过 kubectl describe node <node-name> 查看。
  • 在AML中,如果你通过UI/CLI为计算目标指定了节点选择器,它可能会与你清单中的nodeSelector合并或冲突,需要仔细测试。

3. volumesvolumeMounts:持久化存储

机器学习任务需要处理代码、数据和模型。

  • AML工作区挂载: AML会自动创建一个名为azureml-fileshare-pvc的PVC,用于挂载你的工作区文件(如脚本、输出日志)。务必将其挂载到容器内,这是AML与容器通信、上传下载结果的通道。通常挂载到 /mnt/azureml
  • 数据挂载: 对于训练数据,可以根据来源选择azureFilenfs或像示例中临时使用的emptyDir

避坑指南:

  • 不要修改AML自动创建的PVC名称或挂载路径,除非你非常清楚后果。
  • 对于大型数据集,考虑使用高性能存储类(如managed-premium)或直接使用AML Datastore挂载。

4. imagecommand/args:容器定义

  • image: 可以使用AML环境构建的镜像,或任何可公开访问或集群内可访问的私有镜像。
  • commandargs: 会覆盖Docker镜像中定义的ENTRYPOINTCMD。在AML中,训练任务通常会由AML注入启动命令,所以在你自己的清单中定义这些时需要谨慎,避免冲突。

避坑指南:

  • 如果使用AML的Environment并指定了conda_dependencies_file,AML会构建镜像并自动处理启动命令。此时在Pod清单中通常不需要指定command/args
  • 若需自定义启动脚本,建议通过commandargs明确指定,确保可预测性。

三、 高级场景与最佳实践

1. 使用DeploymentJob而非裸Pod

对于在线端点,使用Deployment可以确保服务的多副本和高可用性。 对于训练任务,使用Job可以确保任务运行完成,并在失败时提供重试机制。

示例:一个用于模型部署的Deployment片段

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ml-model-deployment
spec:
  replicas: 2 # 两个副本
  selector:
    matchLabels:
      app: ml-model
  template: # Pod模板
    metadata:
      labels:
        app: ml-model
    spec:
      containers:
      - name: inference
        image: your-inference-image:latest
        ports:
        - containerPort: 5001
        livenessProbe: # 存活探针
          httpGet:
            path: /health
            port: 5001
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe: # 就绪探针
          httpGet:
            path: /ready
            port: 5001
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            memory: “4Gi”
            cpu: “1”
          limits:
            memory: “4Gi”
            cpu: “2”
---
apiVersion: v1
kind: Service
metadata:
  name: ml-model-service
spec:
  type: LoadBalancer # 或 ClusterIP,AML在线端点通常使用LoadBalancer
  selector:
    app: ml-model
  ports:
  - port: 80
    targetPort: 5001

2. 配置健康检查(探针)

如上面Deployment示例所示,livenessProbereadinessProbe对于在线服务至关重要。

  • livenessProbe: 检查容器是否“活着”。失败则重启容器。
  • readinessProbe: 检查容器是否“就绪”接收流量。失败则将其从Service的负载均衡池中移除。

避坑指南:

  • 一定要根据你的应用启动逻辑设置合理的initialDelaySeconds,避免应用还没启动完就被探针杀死了。
  • 探针端点应轻量,避免对主业务逻辑造成性能影响。

3. 管理敏感信息:使用Secret

永远不要在YAML文件中明文写入密码、连接字符串或API密钥。

# 1. 在K8s中创建Secret (通过kubectl)
# kubectl create secret generic my-secret --from-literal=key=value

# 2. 在Pod清单中引用
env:
- name: DATABASE_PASSWORD
  valueFrom:
    secretKeyRef:
      name: my-secret
      key: key
# 或作为卷挂载
volumeMounts:
- name: secret-volume
  mountPath: /etc/secrets
  readOnly: true
volumes:
- name: secret-volume
  secret:
    secretName: my-secret

在AML中,你也可以使用AML工作区自带的Key Vault集成,通过环境变量传递秘密。

四、 调试与验证

  1. 语法验证: 使用 kubectl apply --dry-run=client -f your_file.yaml 验证语法。
  2. AML SDK验证: 在提交训练任务前,使用AML Python SDK的KubernetesCompute配置仔细检查你的清单。
  3. 集群内调试
    • kubectl get pods -n <namespace>: 查看Pod状态。
    • kubectl describe pod <pod-name> -n <namespace>: 查看Pod详细事件,这是诊断PendingCrashLoopBackOff等问题的最重要工具。
    • kubectl logs <pod-name> -c <container-name> -n <namespace>: 查看容器日志。

总结

编写规范的K8s资源清单是成功在AML中使用Kubernetes计算目标的关键。核心要点在于:

  1. 精细定义资源: 合理设置requestslimits,特别是内存需保持相等。
  2. 明确调度要求: 正确使用nodeSelectortolerations锁定目标节点。
  3. 妥善挂载存储: 确保AML工作区卷正确挂载。
  4. 面向生产设计: 对在线服务使用Deployment并配置健康检查。
  5. 安全第一: 敏感信息务必通过Secret管理。

遵循这些指南,你将能有效避免大多数常见陷阱,构建出稳定、高效且可维护的AML on Kubernetes工作流。

文档信息

Search

    Table of Contents