容器级亲和性实现:DaemonSet中部分容器按需部署至指定节点
可行实现方案
核心思路是让DaemonSet把Pod部署到所有节点,同时通过容器启动逻辑控制:容器a正常启动运行,容器b仅在满足标签/条件的节点上启动业务,不满足条件时进入休眠(避免容器退出导致Pod反复重启)。
方案1:容器启动时直接判断节点标签
不需要额外的init容器,直接在容器b的启动命令里检查当前节点是否有目标标签,符合条件就跑业务,不符合就休眠。
示例DaemonSet配置片段:
apiVersion: apps/v1 kind: DaemonSet metadata: name: mixed-daemonset spec: selector: matchLabels: app: mixed-app template: metadata: labels: app: mixed-app spec: containers: - name: a image: your-a-image:latest # 这里写容器a的正常配置,比如端口、资源限制等 - name: b image: your-b-image:latest # 用shell脚本判断节点标签,比如检查节点是否有"special-node=true"标签 command: ["/bin/sh", "-c"] args: - | # 通过环境变量获取当前节点名称 NODE_NAME=$(echo $NODE_NAME) # 调用K8s API查询节点标签,需要镜像里有curl和jq LABEL_VALUE=$(curl -sS --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ https://kubernetes.default.svc/api/v1/nodes/$NODE_NAME | jq -r '.metadata.labels."special-node"') if [ "$LABEL_VALUE" = "true" ]; then # 符合条件,启动容器b的业务命令 /usr/local/bin/start-b-service else # 不符合条件,无限休眠,不占用核心资源 sleep infinity fi env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName # 给休眠的容器b设置最小资源限制,避免浪费 resources: requests: cpu: "10m" memory: "10Mi" limits: cpu: "100m" memory: "100Mi"
如果你的容器镜像里没有curl和jq,可以换用带kubectl的镜像(比如bitnami/kubectl:latest),把判断逻辑改成:
if kubectl get node $NODE_NAME --no-headers -o custom-columns=:.metadata.labels.special-node | grep -q "true"; then /usr/local/bin/start-b-service else sleep infinity fi
方案2:用Init容器提前做节点检查
先通过一个Init容器判断节点是否符合条件,在共享空目录里创建标记文件,容器b启动时读取这个标记,决定是否跑业务。这种方式把判断逻辑和业务容器解耦,更清晰。
示例配置片段:
apiVersion: apps/v1 kind: DaemonSet metadata: name: mixed-daemonset spec: selector: matchLabels: app: mixed-app template: metadata: labels: app: mixed-app spec: # 定义共享卷,用来传递标记文件 volumes: - name: node-check emptyDir: {} # Init容器:检查节点标签,生成标记文件 initContainers: - name: check-node image: busybox:latest command: ["/bin/sh", "-c"] args: - | NODE_NAME=$(cat /etc/hostname) # 用wget调用K8s API,busybox自带wget wget --ca-certificate=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ --header="Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ -O - https://kubernetes.default.svc/api/v1/nodes/$NODE_NAME | grep -q '"special-node": "true"' \ && touch /check/run-b || touch /check/skip-b volumeMounts: - name: node-check mountPath: /check containers: - name: a image: your-a-image:latest # 容器a的正常配置 - name: b image: your-b-image:latest command: ["/bin/sh", "-c"] args: - | if [ -f /check/run-b ]; then /usr/local/bin/start-b-service else sleep infinity fi volumeMounts: - name: node-check mountPath: /check resources: requests: cpu: "10m" memory: "10Mi" limits: cpu: "100m" memory: "100Mi"
关键注意点
- 容器b不要直接退出,否则Pod会因为容器异常终止而重启,造成资源浪费。用
sleep infinity让它保持运行但不干活是最优选择。 - 要确保容器镜像里包含所需的工具(curl、jq、kubectl等),或者选择自带这些工具的基础镜像(比如alpine、bitnami的镜像)。
内容的提问来源于stack exchange,提问作者Fermat's Little Student
相关产品推荐
相关产品推荐

