ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Agent在Kubernetes中的调度与工作区编排实战

Agent在Kubernetes中的调度与工作区编排实战 1. 从“ax”这个标题说起一个被低估的Agent调度与工作区编排命题第一次看到“ax”这个标题很多人会以为是某个命令行工具的缩写或者某个内部代号。但把热搜词摊开来看——ax调度、agent、kubernetes、workspace、gateway——这几个词凑在一起指向的其实是一个非常具体、也非常现实的问题当多个AI Agent需要在Kubernetes集群里跑起来并且每个Agent都要有自己独立的工作区workspace、独立的网关入口gateway、独立的调度策略时这套东西到底该怎么搭。我自己在过去一年里前后搭过三套不同规模的Agent运行环境从单机Docker Compose到K8s多节点集群都踩过。最直观的感受是Agent这个东西和传统的无状态服务完全不是一回事。传统微服务你扩个副本请求打到哪个Pod都无所谓但Agent不行它带着上下文、带着工作区文件、带着会话状态甚至带着一个正在执行的工具调用链。你把它随便调度到另一个节点工作区没跟过去整个任务就断了。所以“ax”这个标题背后我理解的核心命题是Agent Kubernetes Workspace Gateway 这四件事怎么捏合成一个能跑、能扩、能排查的系统。热搜词里那些“502 bad gateway”、“workspace requires the virtual machine platform”、“setting up workspace loading packages卡住”、“agent execution terminated due to error”全都是这套系统在真实落地时会撞上的墙。这篇文章适合谁看如果你正在做Agent开发或者准备把Agent从本地脚本搬到集群上跑又或者你已经被gateway配置和workspace初始化折腾得够呛那下面的内容应该能帮你省掉不少试错时间。我会从整体设计思路讲起然后拆解核心细节再给出一套可复现的实操流程最后把常见问题和排查技巧整理成速查表。不堆概念只讲我实际搭过、跑过、修过的东西。2. 整体设计与思路拆解为什么Agent调度不能照搬微服务那套2.1 Agent的本质是“有状态的长任务”不是“无状态的短请求”传统Web服务的设计假设是请求进来处理返回结束。Pod可以随时被杀掉重建因为状态存在数据库或缓存里。但Agent的工作模式完全不同。一个Agent执行任务时它可能在本地workspace里读写文件、维护一个多轮对话的上下文、调用外部工具并等待返回、甚至在一个长链路上分步骤执行几十分钟。这就意味着Agent Pod是有状态的。你不能随便把它调度到另一个节点因为它的workspace数据在那个节点上。你也不能随便重启它因为重启意味着上下文丢失、任务中断。热搜词里那个“agent execution terminated due to error”和“couldnt complete the workspace policy acknowledgment”本质上都是状态管理没做好导致的。我的设计思路是把Agent的运行状态分成三层来管。状态类型存储位置生命周期调度影响会话上下文内存 外部存储任务级决定Pod能否迁移工作区文件PVC持久卷长期决定Pod必须绑定节点工具调用链内存 日志请求级决定超时和重试策略这个分层决定了后面的所有设计选择。上下文可以序列化到外部存储那Pod迁移时就能恢复工作区文件放在PVC上那Pod就必须和PVC在同一个可用区工具调用链如果超时就需要gateway层做重试和熔断。2.2 为什么选Kubernetes而不是Docker Compose很多人一开始用Docker Compose跑Agent单机没问题但一旦要跑多个Agent、要隔离资源、要做滚动更新Compose就力不从心了。Kubernetes的优势在于资源隔离每个Agent可以限制CPU和内存防止一个Agent跑飞了把整台机器拖垮。调度策略可以把Agent调度到有GPU的节点、有特定存储的节点、或者指定亲和性的节点。服务发现Agent之间的调用可以通过Service名称直接访问不用硬编码IP。自愈能力Pod挂了自动重启节点挂了自动迁移前提是状态管理做对了。但K8s也带来了复杂度。热搜词里“kubernetes入门指南”、“kubernetes详解”、“kubernetes device plugin”这些词频繁出现说明很多人是在边学边用。我的建议是如果你只是跑一两个Agent做实验Docker Compose足够了但如果你要做多Agent协作、要做生产级部署K8s是绕不过去的。2.3 Gateway在Agent架构里的角色不只是反向代理热搜词里“gateway配置”、“springcloud gateway”、“vercel ai gateway”、“502 bad gateway”出现频率极高。这说明Gateway是大家最容易出问题的地方。在Agent架构里Gateway承担的角色比传统API Gateway要多路由转发把外部请求路由到对应的Agent实例。协议转换Agent可能用WebSocket、gRPC、HTTP流式响应Gateway需要做适配。认证鉴权Agent的API Key管理、访问控制。限流熔断防止某个Agent被大量请求打挂。会话粘性同一个会话的请求要打到同一个Agent实例上否则上下文就丢了。最后一点特别关键。传统Gateway做负载均衡是轮询或随机但Agent需要会话粘性Session Affinity。如果同一个用户的请求第一次打到Pod A第二次打到Pod BPod B没有Pod A的上下文任务就断了。这就是为什么很多人在配置Gateway时会遇到“502 bad gateway”或者“unexpected status 502 bad gateway: unknown error”——不是Gateway本身挂了而是它把请求转发到了一个没有对应会话状态的Pod上。我的做法是在Gateway层用一致性哈希做会话粘性key用session_id。这样同一个会话的请求总是打到同一个Pod。如果那个Pod挂了就需要从外部存储恢复上下文然后重新绑定。2.4 Workspace的设计为什么它是最容易被忽视的坑热搜词里“claudes workspace requires the virtual machine platform on windows”、“setting up workspace: loading packages...卡住”、“couldnt complete the workspace policy acknowledgment”这些全是workspace相关的问题。Workspace在Agent架构里本质上是Agent的“工作台”。它包含临时文件Agent执行任务时生成的文件。依赖包Agent运行需要的Python包、Node包等。配置文件Agent的配置、工具配置。缓存模型缓存、工具调用缓存。问题在于workspace的初始化往往很慢。如果每次Pod启动都要重新安装依赖、重新下载模型那启动时间可能是几分钟甚至十几分钟。热搜词里“setting up workspace: loading packages...卡住”就是这个原因。我的解决方案是把workspace做成预构建的镜像层 PVC持久化。基础依赖打在镜像里Pod启动时直接可用用户数据放在PVC里Pod重启不丢失。这样启动时间可以从几分钟降到几秒。3. 核心细节解析与实操要点Agent调度、Workspace初始化、Gateway配置3.1 Agent调度策略怎么让Pod落到正确的节点上Kubernetes默认的调度器是看资源够不够但Agent调度需要考虑更多因素。我通常用以下几种策略组合节点亲和性Node Affinity如果Agent需要GPU就通过nodeSelector或affinity把它调度到有GPU的节点。如果Agent需要特定的存储类型比如SSD也可以用affinity限制。Pod亲和性Pod Affinity如果多个Agent需要共享同一个workspace PVC那它们必须调度到同一个节点。这时候用podAffinity让它们互相靠近。污点和容忍Taint and Toleration给专用节点打上污点只有特定的Agent才能容忍并调度上去。这样可以做资源隔离比如把生产Agent和测试Agent分开。拓扑分布约束Topology Spread Constraints如果Agent需要高可用可以用这个约束让Pod分散到不同可用区。但注意如果Agent是有状态的分散到不同可用区可能带来存储延迟问题。下面是一个实际的调度配置示例apiVersion: apps/v1 kind: Deployment metadata: name: ax-agent spec: replicas: 3 selector: matchLabels: app: ax-agent template: metadata: labels: app: ax-agent spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-type operator: In values: - agent-worker podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: ax-agent topologyKey: kubernetes.io/hostname containers: - name: agent image: ax-agent:latest resources: requests: memory: 2Gi cpu: 1000m limits: memory: 4Gi cpu: 2000m volumeMounts: - name: workspace mountPath: /workspace volumes: - name: workspace persistentVolumeClaim: claimName: ax-agent-workspace这个配置做了三件事把Agent调度到标记为agent-worker的节点上尽量让同一个Agent的多个副本分散到不同节点给每个Agent挂载一个PVC作为workspace。注意podAntiAffinity用preferred而不是required是因为如果节点不够required会导致Pod一直Pending。preferred是尽量分散但不强求。3.2 Workspace初始化从几分钟到几秒的优化过程Workspace初始化慢通常是因为以下几个原因依赖包安装每次启动都pip install或npm install。模型下载每次启动都从远程拉模型。文件同步从远程存储同步大量文件。权限检查workspace policy acknowledgment之类的检查。我的优化思路是分层处理第一层基础镜像预装。把Python、Node、常用工具、常用依赖包全部打在基础镜像里。这样Pod启动时不需要再安装这些。第二层PVC持久化。把workspace目录挂载到PVC上用户数据、模型缓存、临时文件都放在这里。Pod重启时PVC还在不需要重新下载。第三层Init Container预热。用一个Init Container在Agent启动前做检查比如检查PVC是否挂载成功、检查依赖是否完整、检查配置文件是否存在。如果检查不通过Init Container会失败Pod不会启动这样能避免Agent启动到一半才发现问题。initContainers: - name: workspace-init image: ax-agent-init:latest command: - /bin/sh - -c - | echo Checking workspace... if [ ! -d /workspace/config ]; then echo Workspace config missing, initializing... mkdir -p /workspace/config cp /defaults/config/* /workspace/config/ fi if [ ! -f /workspace/.initialized ]; then echo First time init, installing dependencies... pip install -r /workspace/requirements.txt touch /workspace/.initialized fi echo Workspace ready. volumeMounts: - name: workspace mountPath: /workspace这个Init Container做了三件事检查配置目录是否存在不存在就从默认配置复制检查是否第一次初始化是的话安装依赖最后打上初始化标记。这样后续Pod启动时如果PVC里已经有初始化标记就直接跳过安装步骤。实操心得Init Container的超时时间要设够。默认是无限等待但如果你的依赖安装需要10分钟最好设置一个合理的activeDeadlineSeconds避免卡死。3.3 Gateway配置会话粘性、超时、重试的正确打开方式Gateway是Agent架构里最容易出问题的一环。热搜词里“502 bad gateway”、“unexpected status 502 bad gateway: unknown error”、“cc switch local proxy failed”这些基本都是Gateway配置不当导致的。我用过Spring Cloud Gateway、Nginx Ingress、Traefik也试过Vercel AI Gateway。各有优劣但核心配置逻辑是相通的。会话粘性配置以Nginx Ingress为例可以用cookie做会话粘性。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ax-agent-ingress annotations: nginx.ingress.kubernetes.io/affinity: cookie nginx.ingress.kubernetes.io/session-cookie-name: ax-session nginx.ingress.kubernetes.io/session-cookie-max-age: 3600 nginx.ingress.kubernetes.io/session-cookie-path: / nginx.ingress.kubernetes.io/proxy-read-timeout: 300 nginx.ingress.kubernetes.io/proxy-send-timeout: 300 nginx.ingress.kubernetes.io/proxy-connect-timeout: 60 spec: rules: - host: agent.example.com http: paths: - path: / pathType: Prefix backend: service: name: ax-agent-service port: number: 8080这里的关键配置是affinity: cookie它让同一个会话的请求总是打到同一个Pod。proxy-read-timeout设成300秒是因为Agent的任务可能跑很久默认的60秒不够用。超时和重试Agent的任务执行时间不确定有的几秒有的几分钟。Gateway的超时设置要匹配Agent的最长执行时间。如果设太短任务还没完成连接就断了客户端会收到502。如果设太长连接资源会被占满。我的经验值是proxy-read-timeout设成Agent任务P99执行时间的1.5倍。比如你的Agent任务99%在200秒内完成那就设300秒。重试策略要小心。Agent的任务通常不是幂等的重试可能导致重复执行。所以我的做法是只在连接建立阶段重试不在请求处理阶段重试。nginx.ingress.kubernetes.io/proxy-next-upstream: error timeout nginx.ingress.kubernetes.io/proxy-next-upstream-tries: 2这个配置表示只在连接错误或超时时重试最多重试2次。注意不要设成“non_idempotent”否则POST请求也会被重试可能导致Agent重复执行任务。502排查思路502 Bad Gateway的本质是Gateway无法从上游拿到有效响应。在Agent场景下常见原因有502原因排查方法解决方案Pod没启动kubectl get pods看状态检查Init Container日志Pod启动了但端口不对kubectl exec进Pod curl localhost检查Agent监听端口会话粘性失效看Gateway日志转发到了哪个Pod检查cookie配置超时太短看Gateway错误日志调大proxy-read-timeoutPod OOM被杀kubectl describe pod看Events调大内存限制3.4 Agent执行终止的常见原因与预防热搜词里“agent execution terminated due to error”是一个很泛的错误可能的原因很多。我整理了几种最常见的情况上下文超限Agent的上下文窗口是有限的如果对话轮次太多或者工具返回内容太长上下文会溢出。这时候Agent要么报错终止要么开始丢历史消息。预防方法是做上下文压缩把早期对话摘要化或者用外部存储保存完整历史只把最近几轮放进上下文。工具调用失败Agent调用外部工具时如果工具返回错误或超时Agent可能终止。预防方法是给工具调用加超时和重试并且在Agent层做错误处理让Agent知道工具失败了可以尝试其他方案。资源不足Agent跑着跑着内存不够被OOM Kill了。预防方法是设置合理的内存限制并且监控Agent的内存使用趋势。如果发现内存持续增长可能是内存泄漏需要排查代码。网络问题Agent需要调用外部API如果网络不通或DNS解析失败Agent会终止。预防方法是给Agent配置合理的网络策略并且做健康检查。4. 实操过程与核心环节实现从零搭一套Agent运行环境4.1 环境准备与基础镜像构建假设你有一个K8s集群单节点Minikube也可以我们要部署一个Agent它需要Python环境、需要访问外部API、需要持久化workspace。第一步是构建基础镜像。不要用官方的python镜像直接跑因为每次启动都要装依赖。我通常分两层构建# 基础层预装常用依赖 FROM python:3.11-slim AS base RUN apt-get update apt-get install -y \ curl \ git \ rm -rf /var/lib/apt/lists/* RUN pip install --no-cache-dir \ requests \ fastapi \ uvicorn \ pydantic # 应用层拷贝Agent代码 FROM base AS app WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8080 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8080]这样构建出来的镜像基础依赖已经在base层了应用层只需要装Agent特有的依赖。如果Agent代码更新只需要重新构建app层base层可以复用。实操心得requirements.txt里的依赖要锁版本。Agent项目依赖多不锁版本的话今天能跑明天可能就挂了。用pip freeze requirements.txt生成锁定版本。4.2 PVC创建与Workspace挂载Agent的workspace需要持久化所以要先创建PVC。apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ax-agent-workspace spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: standard注意accessModes。ReadWriteOnce表示只能被一个节点挂载读写。如果你的Agent需要多个Pod共享workspace要用ReadWriteMany但很多存储类不支持ReadWriteMany。我的建议是尽量让一个Agent对应一个PVC不要共享。然后Deployment里挂载这个PVCvolumeMounts: - name: workspace mountPath: /workspace volumes: - name: workspace persistentVolumeClaim: claimName: ax-agent-workspacePod启动后/workspace目录就是持久化的。Agent在里面写文件Pod重启后文件还在。4.3 Gateway路由配置与验证Gateway的配置取决于你用的是什么。如果是Nginx Ingress用上面的Ingress配置。如果是Spring Cloud Gateway配置类似spring: cloud: gateway: routes: - id: ax-agent uri: http://ax-agent-service:8080 predicates: - Path/api/agent/** filters: - StripPrefix2 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20配置完成后要验证几件事路由是否生效curl一下Gateway的地址看能不能转发到Agent。会话粘性是否生效连续发几个请求看是不是打到同一个Pod。可以看Agent日志里的Pod名称。超时是否合理发一个长任务看Gateway会不会提前断开。限流是否生效快速发大量请求看是否被限流。验证会话粘性的一个技巧在Agent的响应里带上Pod名称然后连续请求几次看Pod名称是否一致。import os from fastapi import FastAPI app FastAPI() app.get(/health) def health(): return { status: ok, pod: os.environ.get(HOSTNAME, unknown) }这样每次请求都能看到是哪个Pod响应的。4.4 Agent执行流程的完整链路一个完整的Agent执行链路是这样的客户端发请求到Gateway。Gateway根据会话粘性转发到对应的Agent Pod。Agent Pod从workspace加载上下文和配置。Agent调用LLM或其他工具。Agent把结果写回workspace。Agent返回响应给Gateway。Gateway返回给客户端。这个链路里任何一个环节出问题都会导致任务失败。我的做法是在每个环节加日志和监控Gateway层记录请求ID、转发目标Pod、响应时间、状态码。Agent层记录任务ID、执行步骤、工具调用、错误信息。Workspace层记录文件读写、依赖加载、初始化状态。这样出问题时可以通过请求ID把整个链路串起来排查。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 Workspace初始化卡住的排查“setting up workspace: loading packages...卡住”这个问题我遇到过好几次。原因通常有三种网络问题Pod在安装依赖时访问不了外部源。排查方法是进Pod里curl一下源地址。如果网络不通需要检查NetworkPolicy或DNS配置。依赖冲突requirements.txt里有版本冲突pip在解析依赖时卡住。排查方法是看pip的详细日志加-v参数。解决方法是锁定版本或者用pip-tools做依赖解析。存储性能问题PVC的IOPS太低安装依赖时读写慢。排查方法是看PVC的存储类如果是网络存储IOPS可能只有几百安装大量小文件时会很慢。解决方法是换本地SSD存储或者把依赖预装在镜像里。实操心得Init Container里加一个超时比如activeDeadlineSeconds: 600。如果10分钟还没初始化完就让Pod失败然后看日志排查。不要让Init Container无限等待否则Pod会一直卡在Init状态。5.2 502 Bad Gateway的快速定位502是Gateway层最常见的错误。我的排查顺序是看Gateway日志确认请求转发到了哪个上游上游返回了什么。看Pod状态kubectl get pods确认Pod是Running还是CrashLoopBackOff。看Pod日志kubectl logs确认Agent有没有收到请求有没有报错。看Servicekubectl get endpoints确认Service有没有正确的Endpoints。看网络kubectl exec进Podcurl一下自己的端口确认Agent在监听。如果Pod是Running但502通常是端口不对或者Agent没启动完。如果Pod是CrashLoopBackOff看日志找崩溃原因。5.3 Agent执行终止的排查清单现象可能原因排查方法解决方案任务执行到一半终止上下文超限看Agent日志有没有context length错误做上下文压缩或截断工具调用后终止工具返回错误看工具调用日志加错误处理和重试运行一段时间后终止OOMkubectl describe pod看Events调大内存限制随机终止节点问题看节点状态和系统日志迁移Pod或修复节点启动就终止配置错误看启动日志检查环境变量和配置文件5.4 Gateway配置的常见误区误区一超时设太短。默认60秒但Agent任务可能跑几分钟。设太短会导致任务还没完成连接就断了。误区二重试策略太激进。Agent任务通常不幂等重试会导致重复执行。只在连接阶段重试不要在请求处理阶段重试。误区三忽略会话粘性。没有会话粘性同一个会话的请求打到不同Pod上下文丢失任务失败。误区四限流太严。Agent任务本身耗时较长限流太严会导致正常请求被拒。根据实际QPS设置合理的限流阈值。误区五没有健康检查。Gateway需要知道Agent是否健康否则会把请求转发到挂掉的Pod。配置readinessProbe和livenessProbe。readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 5 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30 periodSeconds: 10readinessProbe决定Pod是否加入Service的EndpointslivenessProbe决定Pod是否需要重启。两个都要配但initialDelaySeconds要设够给Agent启动留时间。5.5 Kubernetes层面的坑PVC挂载失败如果PVC和Pod不在同一个可用区挂载会失败。排查方法是看Pod的Events会有“volume node affinity conflict”之类的错误。解决方法是让PVC和Pod在同一个可用区或者用支持跨可用区的存储类。资源限制太紧Agent启动时需要一定内存如果limit设太小Pod会OOM。建议requests和limits之间留一定余量比如requests 2Gilimits 4Gi。节点选择器太严如果nodeSelector指定了不存在的标签Pod会一直Pending。排查方法是看Pod Events会有“no nodes available”之类的错误。网络策略阻断如果集群启用了NetworkPolicy默认可能拒绝所有入站和出站流量。需要显式允许Agent的入站和出站。apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ax-agent-policy spec: podSelector: matchLabels: app: ax-agent policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: gateway ports: - protocol: TCP port: 8080 egress: - to: - podSelector: {} ports: - protocol: TCP port: 443这个策略允许Gateway访问Agent的8080端口允许Agent访问外部HTTPS服务。6. 工具选型与架构演进从单机到集群的平滑过渡6.1 不同阶段的工具选型建议不是所有场景都需要K8s。我根据规模把Agent部署分成三个阶段阶段一单机实验。用Docker Compose一个Agent容器加一个Gateway容器。workspace用本地目录挂载。适合个人开发和小规模测试。阶段二小规模生产。用K8s单节点或双节点Agent用Deployment部署workspace用PVC。Gateway用Nginx Ingress。适合团队内部使用。阶段三大规模生产。用K8s多节点集群Agent用StatefulSet部署因为有状态workspace用分布式存储。Gateway用Spring Cloud Gateway或Traefik配合Redis做会话粘性。适合对外服务。StatefulSet和Deployment的区别在于StatefulSet给每个Pod一个稳定的网络标识和存储。对于Agent来说如果每个Agent实例需要独立的workspaceStatefulSet更合适。apiVersion: apps/v1 kind: StatefulSet metadata: name: ax-agent spec: serviceName: ax-agent-headless replicas: 3 selector: matchLabels: app: ax-agent template: metadata: labels: app: ax-agent spec: containers: - name: agent image: ax-agent:latest volumeMounts: - name: workspace mountPath: /workspace volumeClaimTemplates: - metadata: name: workspace spec: accessModes: [ReadWriteOnce] resources: requests: storage: 10GivolumeClaimTemplates会为每个Pod自动创建一个PVC命名规则是workspace-ax-agent-0、workspace-ax-agent-1以此类推。这样每个Agent实例有独立的workspace互不干扰。6.2 Agent记忆与状态管理的演进热搜词里“agent记忆”、“a-memguard: a proactive defense framework for llm-based agent memory”这些指向的是Agent的记忆管理问题。Agent的记忆分短期记忆和长期记忆。短期记忆是当前会话的上下文放在内存里。长期记忆是跨会话的知识放在外部存储里。我的做法是短期记忆用Redis或内存缓存设置TTL。会话结束后自动过期。长期记忆用向量数据库如Milvus、Qdrant存储支持语义检索。工作区文件用PVC存储Pod重启不丢失。这样分层的好处是每层可以用不同的存储方案成本和性能都能优化。短期记忆要求低延迟用内存长期记忆要求高容量用磁盘工作区文件要求持久化用PVC。6.3 安全与权限控制Agent的安全问题不容忽视。热搜词里“agent安全”、“kubernetes 未授权访问漏洞”这些提醒我们要做好权限控制。最小权限原则Agent的ServiceAccount只给必要的权限。不要用default ServiceAccount也不要用cluster-admin。apiVersion: v1 kind: ServiceAccount metadata: name: ax-agent-sa --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: ax-agent-role rules: - apiGroups: [] resources: [configmaps] verbs: [get, list] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: ax-agent-rolebinding subjects: - kind: ServiceAccount name: ax-agent-sa roleRef: kind: Role name: ax-agent-role apiGroup: rbac.authorization.k8s.io这个配置只允许Agent读取ConfigMap不能创建、删除、修改任何资源。网络隔离用NetworkPolicy限制Agent的网络访问。只允许必要的入站和出站流量。密钥管理API Key、数据库密码等敏感信息用Secret存储不要硬编码在镜像或配置文件里。apiVersion: v1 kind: Secret metadata: name: ax-agent-secrets type: Opaque data: api-key: base64-encoded-value然后在Deployment里用envFrom或volumeMounts引用Secret。实操心得Secret默认是base64编码不是加密。如果集群有多人使用建议启用Secret加密或使用外部密钥管理服务。7. 监控与可观测性让Agent的运行状态透明化7.1 关键监控指标Agent运行环境需要监控的指标分几类基础设施层节点CPU、内存、磁盘、网络。用Node Exporter Prometheus Grafana。K8s层Pod状态、重启次数、资源使用。用kube-state-metrics。Agent层任务成功率、执行时间、工具调用次数、错误率。用自定义指标通过Prometheus客户端暴露。Gateway层请求量、响应时间、状态码分布、会话粘性命中率。用Nginx Ingress的metrics或Spring Cloud Gateway的metrics。7.2 日志收集与链路追踪Agent的日志分散在多个Pod里排查问题时不方便。我的做法是用Fluentd或Filebeat收集日志发送到Elasticsearch或Loki然后用Kibana或Grafana查询。链路追踪用OpenTelemetry。在Gateway层生成Trace ID透传到Agent层Agent层再透传到工具调用层。这样可以通过Trace ID把整个链路串起来。from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter trace.set_tracer_provider(TracerProvider()) tracer trace.get_tracer(__name__) exporter OTLPSpanExporter(endpointhttp://otel-collector:4317) trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(exporter)) app.post(/task) def run_task(task_id: str): with tracer.start_as_current_span(run_task) as span: span.set_attribute(task_id, task_id) # Agent执行逻辑 return {status: ok}这样每个任务都会生成一个Span可以在Jaeger或Tempo里查看执行链路。7.3 告警配置告警要设得合理太多会麻木太少会漏报。我的告警清单告警项阈值处理方式Pod重启次数5分钟内3次检查日志排查崩溃原因任务失败率5分钟内10%检查Agent日志和工具调用Gateway 502率5分钟内5%检查Pod状态和会话粘性PVC使用率80%清理workspace或扩容节点内存使用率90%扩容节点或调整资源限制告警通道用钉钉、飞书或邮件根据团队习惯选择。8. 一些踩坑后的个人体会这套Agent运行环境我前后搭了三次每次都有新的坑。第一次是workspace没做持久化Pod一重启数据全丢第二次是Gateway没做会话粘性同一个会话的请求打到不同Pod上下文对不上第三次是资源限制设太紧Agent跑着跑着就OOM。现在回头看最核心的经验就几条workspace一定要持久化Gateway一定要做会话粘性资源限制一定要留余量日志和监控一定要提前做。这四条做到了大部分问题都能快速定位和解决。还有一个容易被忽视的点是Agent的优雅退出。Pod被删除时K8s会发SIGTERM信号然后等一段时间默认30秒再发SIGKILL。如果Agent正在执行任务收到SIGTERM后应该停止接受新请求完成当前任务然后退出。如果直接被杀掉任务就中断了。import signal import sys def graceful_shutdown(signum, frame): print(Received SIGTERM, shutting down gracefully...) # 停止接受新请求 # 等待当前任务完成 # 保存状态到workspace sys.exit(0) signal.signal(signal.SIGTERM, graceful_shutdown)然后在Deployment里设置terminationGracePeriodSeconds给Agent足够的退出时间。spec: template: spec: terminationGracePeriodSeconds: 120 containers: - name: agent # ...这样Pod被删除时Agent有120秒的时间完成当前任务并保存状态。最后再分享一个小技巧在Agent的workspace里放一个README文件记录这个workspace的用途、配置、依赖版本。这样即使换了人维护也能快速了解workspace的情况。我吃过这个亏接手一个Agent环境时workspace里一堆文件不知道哪些是重要的哪些是临时的排查问题花了很久。后来我养成了习惯每个workspace都放一个README记录关键信息。这个习惯帮我省了很多时间。
返回列表