K8S YAML 导入
K8S YAML 导入功能允许熟悉 K8S 的用户以自定义 Deployment 资源或 Job 资源的 YAML 配置文件的方式,实现更高自由度的自定义配置。
例如:
- 发布 Job 任务
- 使用多容器 Pod
- 调整扩缩容和滚动更新策略
- 调整容器从启动到销毁整个生命周期的行为
- 调整容器启动时采用的用户
- 为容器配置启动命令和环境变量
自定义 YAML 功能运行时遵循以下的逻辑顺序:
-
从 UI(API)获取所有 UI 可定义的配置项,包括:
- 卡型、CPU、内存;
- 镜像地址,端口列表;
- 节点数量
- 共享内存、共享存储卷、对象存储加速
-
从 UI(API)获取用户提供的 YAML;
-
根据 API 配置项,覆盖或补充用户提供的 YAML 中的对应配置项。其中有几项特别情况:
- 由于支持多容器 Pod,而 UI 上只允许填写 1 个镜像,平台实际上不会校验 YAML 中所填写的镜像链接与 UI 中实际的镜像链接是否一致。
- 主容器的 name 字段建议设置为 API 调用时 service_name 字段的值连接上”-container”,否则任务启动后将无法查看容器日志或使用 webshell。平台自动生成的模板 YAML 的 name 字段即满足这一规则,若无必要请不要修改。
- 所有 YAML 中的端口会被移除。平台只会根据 UI(API)上设置的端口列表建立服务暴露链路。值得注意的是,由于 Pod 内共享网络命名空间,因此 Pod 内的同一个端口只能被 Pod 内的一个服务所监听,并不需要担心流量到底应当发往哪个容器的问题。
- 对于 Job 任务,发布任务时通过 UI(API)设定的副本数将同时设置到 Job 任务的 completions 和 parallelism 字段。在发布任务后,completions 不可被更改,通过修改副本数(节点数)的 UI(API)可以调整 parallelism,但是必须小于等于 completions。
-
覆盖所有关于调度的配置项,例如标签选择器、污点容忍等。
-
覆盖所有可能带来安全风险的配置项,可参考 K8S 官方的Pod 安全性标准中的 Restricted 标准,我们放开了其中的“以 root 用户启动容器”限制,其余保持一致。
这里给出几个典型应用场景下的 K8S Yaml 配置文件样例
发布 Job 任务
Section titled “发布 Job 任务”创建两个 container,选择双卡 GPU、cpu 平均分配、内存:第一个 container 与第二个 container 比例为 9:1
apiVersion: batch/v1kind: Jobmetadata: creationTimestamp: null name: pispec: backoffLimit: 4 template: metadata: creationTimestamp: null spec: containers: - image: harbor.suanleme.cn/your/image1:version name: yourcontainername1 resources: limits: cpu: '28' nvidia.com/gpu: 1 memory: 90Gi requests: cpu: 1166m nvidia.com/gpu: 1 memory: 2133Mi - image: harbor.suanleme.cn/your/image2:version name: yourcontainername2 resources: limits: cpu: '4' nvidia.com/gpu: 1 memory: 90Gi requests: cpu: 2333m nvidia.com/gpu: 1 memory: 10666Mi restartPolicy: Neverstatus: {}发布多容器 Pod
Section titled “发布多容器 Pod”创建两个 container,选择双卡 4090、cpu:第一个 container 与第二个 container 比例为 7:1、内存:第一个 container 与第二个 container 比例为 9:1
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: d10161633-python-web-user-id40-4474-jajdlva2 gongjiyun.com/task-type: deploymentspec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: nvidia.com/gpu.product operator: In values: - NVIDIA-GeForce-RTX-4090 containers: - image: harbor.suanleme.cn/your/image1:version name: d1758620954106-62013-container1 resources: limits: cpu: '28' memory: 90Gi nvidia.com/gpu: '1' requests: cpu: '7' memory: 25Gi - image: harbor.suanleme.cn/your/image2:version name: d1758620954106-62013-container2 ports: - containerPort: 80 resources: limits: cpu: '4' memory: 10Gi nvidia.com/gpu: '1' requests: cpu: '7' memory: 25Gi priorityClassName: default-pc schedulerName: requested-to-capacity-ratio-custom-schedulerstatus: {}实现容器内业务的优雅退出
Section titled “实现容器内业务的优雅退出”部分业务程序处理单次请求可能需要数十分钟级别的较长时间,在服务缩容等场景中,如果不等待请求完成即退出程序,可能会对用户体验造成较大不良影响。
对于此类程序,可以在业务代码里面处理 SIGTERM 信号:
- 捕获 SIGTREM 信号
- 执行对应的清理逻辑
- 主动退出程序
并在 yaml 中配置适当的优雅退出宽限时间来实现(默认 30s,可按需延长)。也可以通过 preStop 配置以其它方式通知程序。这里给出 yaml 文件样例(此处的 preStop 命令仅作格式上的说明,无实际意义)。
...... containers: - image: harbor.suanleme.cn/repository/imagename:v1 #选用的镜像 lifecycle: #(可选)回调函数退出时执行的逻辑 preStop: exec: command: - /bin/sh - '-c' - sleep 30 name: d1749797718484-39886-container #默认生成 resources: #选卡时确定此配置,不可修改 limits: cpu: '14' memory: 63Gi nvidia.com/gpu: '1' requests: cpu: '7' memory: 32256Mi terminationGracePeriodSeconds: 200 #(关键)定义优雅退出最大时间自定义 yaml 增加环境变量和启动命令等信息
Section titled “自定义 yaml 增加环境变量和启动命令等信息”....... containers: - args: #启动参数 - serve - MiniMaxAI/MiniMax-M1-80k - '--trust-remote-code' - '--quantization' - experts_int8 - '--max_model_len' - '4096' - '--dtype' - bfloat16 - '--tensor-parallel-size' - '8' command: #启动命令 - vllm env: #环境变量 - name: HF_ENDPOINT value: https://hf-mirror.com image: harbor.suanleme.cn/xiongdw/mem-allocator:v1 name: d1750145858219-7590-container resources: limits: cpu: '56' memory: 252Gi nvidia.com/gpu: '4' requests: cpu: '28' memory: 126Gi volumeMounts: #共享内存挂载 - mountPath: /dev/shm name: shm-volume terminationGracePeriodSeconds: 200 #任务最大退出时间 volumes: - emptyDir: medium: Memory name: shm-volumestatus: {}解决容器内无法访问外部四层服务的问题
Section titled “解决容器内无法访问外部四层服务的问题”部分业务程序可能需要访问云上消息队列,而且选择了采用 IP+ 端口的四层流量方式访问。默认我们的平台仅允许七层流量,这会导致无法从消息队列中拉取任务。如果存在此问题,可考虑使用此配置。
apiVersion: apps/v1kind: Deploymentmetadata: creationTimestamp: null labels: app: d06161816-mem-allocatorv1-186-11icjyhf name: d06161816-mem-allocatorv1-186-11icjyhf namespace: wp2upu39jptxiuhkfkm0nx2bdkp9elwo-186spec: replicas: 1 selector: matchLabels: app: d06161816-mem-allocatorv1-186-11icjyhf strategy: {} template: metadata: annotations: #此项为放开四层流量的限制 sidecar.istio.io/inject: 'false' creationTimestamp: null labels: app: d06161816-mem-allocatorv1-186-11icjyhf spec:......服务零中断滚动更新
Section titled “服务零中断滚动更新”如果主动切换业务程序所在的集群,我们会并发地要求新集群拉起新实例,旧集群关闭旧实例。但是,有些时候我们需要在新实例启动后才关闭旧实例。为此,我们可以通过如下配置来让旧实例等待一段时间再退出。
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: xxxspec: replicas: 1 selector: matchLabels: app: xxx template: metadata: annotations: [proxy.istio.io/config](http://proxy.istio.io/config): | drainDuration: 4m terminationDrainDuration: 5m holdApplicationUntilProxyStarts: true labels: app: nginx spec: terminationGracePeriodSeconds: 400 # 确保 preStop 执行完成 containers: - name: nginx image: [harbor.suanleme.cn/library/nginx:v1.20](http://harbor.suanleme.cn/library/nginx:v1.20) # 可替换为你的 harbor 镜像 lifecycle: preStop: exec: command: ["sleep", "350"] ports: - containerPort: 80以 root 用户启动容器
Section titled “以 root 用户启动容器”部分业务容器可能希望以 root 身份启动,这与 K8S 的默认行为不同,可以通过自定义配置来进行设置。
...... containers: - image: harbor.suanleme.cn/repository/imagename:v1 #选用的镜像 name: d1749797718484-39886-container #默认生成 securityContext: runAsUser: 0 #此处填写用户 UID,0 标识 root,也可定义其他可用 UID runAsGroup: 0 #(可选):此处表示 root 组的 GID