一、核心配置结构说明containerd 2.x 对镜像仓库配置进行了结构化优化，所有相关配置均集中在 /etc/containerd/certs.d/ 目录下，遵循 "一仓库一目录" 的配置原则：每个镜像仓库（registry）对应一个独立目录，目录名需与仓库域名（或 IP 地址）完全一致每个目录下必须包含一个 hosts.toml 文件，用于定义仓库连接参数hosts.toml 核心配置项：仓库服务地址（server）、操作权限（capabilities）、认证信息（auth）、证书验证开关（skip\_verify）二、分步配置实战1. 版本确认首先通过以下命令验证 containerd 版本是否为 2.x 系列：\\\[root@k8s-master ~]# containerd --version containerd containerd.io v2.2.0 1c4457e00facac03ce1d75f7b6777a7a851e5c412. 创建配置目录根据 Harbor 仓库地址创建对应的配置目录，目录名需与仓库域名（或 IP）严格匹配（示例中 Harbor 仓库地址为 harbor.liyb.com）：mkdir -p /etc/containerd/certs.d/harbor.liyb.com注意：若仓库未使用域名（直接通过 IP 访问），可直接以 IP 地址作为目录名（如 /etc/containerd/certs.d/192.168.1.100）3. 编写 hosts.toml 配置文件创建并编辑 hosts.toml 文件，配置仓库连接参数：vi /etc/containerd/certs.d/harbor.liyb.com/hosts.toml添加如下配置内容：server = "https://harbor.liyb.com" \\\[host."https://harbor.liyb.com"] capabilities = \\\["pull", "resolve", "push"] # 支持的操作：拉取、解析、推送 skip\\\_verify = true # 自签名证书时启用（跳过证书验证） \\\[host."https://harbor.liyb.com".auth] username = "admin" # Harbor 登录用户名 password = "Harbor12345" # Harbor 登录密码配置说明：若使用企业级可信证书，无需设置 skip\\\_verify = true，只需将 CA 证书文件放置到对应配置目录（如 /etc/containerd/certs.d/harbor.liyb.com/）即可权限配置可根据实际需求调整，例如仅需拉取镜像时可改为 capabilities = \\\["pull", "resolve"]4. 确认主配置文件路径检查 containerd 主配置文件 /etc/containerd/config.toml 中是否正确指定了仓库配置路径，确保以下配置项存在且无误：toml# /etc/containerd/config.toml \\\[plugins."io.containerd.grpc.v1.cri".registry] config\\\_path = "/etc/containerd/certs.d" # 仓库配置目录路径（默认已启用）注意：containerd 2.x 默认启用该配置，但生产环境部署时务必手动校验，避免路径配置错误导致配置失效三、配置验证方法1. 使用 nerdctl 验证（推荐）通过 nerdctl 工具拉取 Harbor 仓库镜像，验证配置是否生效：nerdctl pull harbor.liyb.com/prod/nginx:1.27成功输出示例：plaintextharbor.liyb.com/prod/nginx:1.27: manifest-sha256:114dff0fc8ee3d0200c3a12c60e3e2b79d0920dd953175ecb78a0b157425b25e: done config-sha256:1e5f3c5b981a9f91ca91cf13ce87c2eedfc7a083f4f279552084dd08fc477512: done elapsed: 0.1 s total: 0.0 B (0.0 B/s)2. Kubernetes 节点验证在 Kubernetes 节点上通过 crictl 工具拉取镜像（适用于 K8s 集群环境）：crictl pull harbor.liyb.com/prod/nginx:1.27关键注意点：镜像名称必须显式包含 Harbor 仓库地址（完整格式：仓库地址 / 项目名 / 镜像名：标签），否则会导致 K8s Pod 拉取镜像失败四、高频踩坑与解决方案
当 Andrew Harmel-Law 邀请演讲者参加 QCon 伦敦大会时，他首先想到的是：“让 Diana 和 Cat 一起登台！”这完全是出于一种顽皮的冲动。 Cat Morris 是一位产品经理。Diana Montalion 是一位系统架构师。我们都专门从事软件系统和平台开发。我们都把对方视为我们所有痛苦的根源。不是个人层面的，我们从未一起工作过，但我们都认为对方所代表的角色是问题所在。 但我们也致力于改善我们的工作方式。如果我们能够消除我们之间存在的摩擦……那对每个人来说都是一件好事，对吧？ 首先，我们对参与的每一个重大项目做了建模分析。我们发现，每一个项目的结局都像泰坦尼克号一样：撞上了冰山。 我们发现了以下这些改变职业生涯的真相： 我们的工作有很多重合的地方。我们需要彼此。合作会带来更好的结果。我们思考问题的方式不同但互补。我们要解决的不是技术问题。技术挑战不难解决。困难之处在于消除摩擦。 摩擦是阻碍变革的无形暗流。摩擦并非孤立存在的，而是一个系统性问题，其来源是人、团队与技术之间的关系。解决之道不在于 Kubernetes、云计算或人工智能，而在于改变我们的思维模式、沟通方式和组织架构。 本文描述了在每一个项目中都会反复出现的六种摩擦： 反直觉行为拒绝改变效率与控制产品与技术角色之间相互指责线性管道思维交付能力不足 每一种摩擦都让我们忙于重写相同的代码库或重绘相同的组织结构图。摩擦导致很多无益于我们避开冰山的工作浪费。这篇文章将帮助你弄清楚如何应对这些问题。 反直觉行为 我们怪错了对象。因此，我们做错了事情。 反直觉行为，由系统科学家 Jay Forrester 定义，是指复杂的社会和管理系统倾向于用让问题变得更糟糕的解决方案来应对问题。例如，为一个处于后期的项目增派更多的工程师，加快项目进度。 面对系统性挑战时，我们人类会倾向于指责他人。遗憾的是，我们怪错了对象。我们责怪工程团队工作效率低下，或者断定是因为团队太小，却未能意识到甘特图不过是虚构的简化模型，它过度简化了复杂的动态过程。 “任何系统的输出结果都是其内在设计的必然产物‌。”——W. Edwards Deming 当我们改变一个系统的运作方式时，我们也需要改变塑造系统的底层模式、结构和心智模型。例如，不是在本已臃肿的数据库上放上 GraphQL 就能称之为图，而是需要重新构建我们思考数据的方式。我们需要创建异步事件，而不是把什么都塞进管道，我们需要创建反馈循环，让我们能及时知道数据在跨系统移动时出现了异常。 这可以解释为什么工程师们会工作到很晚。他们一边忙着给猪涂口红，一边又要完成甘特图上没有预料到的工作。 解决之道：理解系统 反直觉行为具有引力，会将我们吸入其中，卷入漩涡。至少，我们的感受是这样：感觉像是在行动，在前进，而实际情况是，我们就像烘干机里的衣物，在原地打转。自始至终，我们都是从同一个狭小的视角凝视问题。 解决方法是暂时停下来，找准方向再行动。 首先是确定核心领域。系统的目标是什么？对于联邦快递来说，是快速递送包裹。很可能，你所经历的反直觉行为，源于人们的说法一致但前进方向不同。 每个参与的人都清楚变革与核心领域的关系吗？怎么才能加快包裹递送而不产生负面影响？系统本身如何导致了问题的产生？当前的流程和模式会产生什么样的心态？系统中的关系如何强化了这些模式？有什么你没有看到的变革需求吗？开始绘制这些模式，确定你的核心领域，所需的变革自然便会显现。 拒绝改变 每个试图变革的组织都有这样一些人：守门人、地牢主、自封的 10 倍速工程师，他们对组织非常了解，并且拥有一个魔法词：不。 他们说，“我们已经尝试过迁移。我们已经尝试过平台迁移或重构。我们已经尝试过重组。都行不通。别费心了。”他们掌握着生产环境或管道或某个关键系统的控制权，你没法忽视他们。 对此，人们很容易把责任归咎于那人的固执性格。但他展现的行为模式，正是长期的奖励与强化所形成的。通过管理遗留系统的复杂性，他已成为不可或缺的存在。要改变他，必须改变整个组织的思维方式，否则，又会冒出另一个类似的角色取而代之。仅靠技术手段无法从根本上解决问题。 拒绝改变是会传染的。当那个人关闭了好奇心，其他人也会转向固定思维模式。人们首先做的是怀疑而不是实验。组织无法在规避风险和尝试新事物之间找到平衡。变革陷入了停滞。 “变革之所以困难，是因为人们高估了他们所拥有的东西的价值，低估了他们放弃这些东西可能获得的价值。” ——《会飞的水牛：卓越腾飞，学会让员工引领》（Belasco 和 Stayer，1999 年） 解决之道：解雇那个人 好吧，这可能有点极端。你可能无法解雇他们，但你可以限制他们的影响。你不是他们的导师、母亲或心理医生。不要陷入那种角色。 把他们装进盒子里。给他们一个静态领域，让他们可以保留自己的脚本和遗留代码，而你去改变系统的其余部分。用“是”的力量去平衡他们“不”的力量。 是的，这并不意味着认同所有观点。这意味着探索可能性。将对话引向可以向前推进的方向。找到愿意做出改变的人，并帮助他们解决自己的问题，而不是等待守门人为他们开锁。 效率与控制 效率带来安全感。控制带来责任感。二者结合，便形成了现代组织中最诱人的反模式：效率与控制。 当它们占据主导地位时，我们关注的焦点便会缩小到产出：发布特性、关闭工单、满足截止日期。工作以速度来衡量，而不是价值。组织最小化互动和反思，坚信速度等于进步。 但在复杂的系统中，只讲效率会使系统变得脆弱。你按时交付了错误的东西。你得到了与蓝图相匹配的结果，但忽略了变化的环境。你得到了短期的解决方案，而那最终会成为未来的障碍。 我们制定了一个有预算有时间表的路线图，而唯一的上下文是一堆令人困惑的架构。 要求我们增加控制，但又理不清头绪。效率不过是掩盖混乱的遮羞布。其结果是一场组织作秀：Jira 工单、自信满满的时间表，以及追踪一切却唯独忽略意义的指标。 截止日期不可更改。功能已锁定。缺的是什么呢？一个明确的目标和协同一致的成果，同时又留有空间，允许在学习过程中进行调整。包裹配送时间没有改善，客户体验也未见提升。 解决之道：设计知识流 让团队注重效能而非过度追求效率。如何确保时间、精力和注意力都用在塑造真正重要的成果上？用协同取代控制：建立能让正确信息在正确时间传递给正确人员的工作机制，让信息跨越边界自由流动，无需高管做微观管理。 思考你目前正在开展的项目。你是在度量产出还是成果？截止日期是反映了现实还是一厢情愿的想法？如何改善信息流，而不是构建一个工厂式的交付过程？做工作与交付价值不是一回事；改善知识流能让你更快地获得价值。 产品 vs. 技术 Andrew 让我们聚在一起，因为我们有类似的挫败感。我们都面临着用 Kubernetes 解决系统性问题的压力。当然，我们做不到。我们也因为反直觉行为，养成了互相指责对方角色的习惯。 工程团队不喜欢产品经理给他们施加压力，要求他们在一个紧迫的时间表内完成特性交付。他们不明白，他们正在做的改变怎么能提高代码质量。基础设施、架构和 DevSecOps 人员则抱怨说，他们需要的改进从未被优先考虑。 产品团队不喜欢工程师表现出的抵触和消极态度。他们不明白，为什么一些简单的事情需要那么长时间来构建。他们抱怨说，过度工程化浪费了大量的会议时间，而那些时间本来可以用在寻找前进的方法上。 在许多组织中，产品和工程是相互隔离的孤岛。双方对效率与控制的定义截然不同，成了两股相互对立的势力。产品部门只需将需求抛过隔离墙，便坐等可运行的代码返回；而工程部门则被要求加快编码速度，无暇顾及系统设计。 即使这两个角色坐在一起，他们相互冲突的方法和控制欲也会加剧摩擦。 解决之道：向学习驱动型转变 Carol Dweck 博士描述了两种心态：固定型和成长型。 固定型心态认为，擅长某事就意味着那件事应该很容易做到。如果某事很难，则说明你缺乏天赋。在这种模式下，人们会回避挑战，将反馈视为批评，将他人的成功视为威胁。其结果是团队很脆弱，他们要保护自己的地盘，而不是一起学习。 成长型心态认为，能力可以通过实践、反馈和坚持来提升。你不能只是做 Netflix 所做的事。在这种模式下，人们欢迎挑战，将努力视为精通之道，将挫折当作改进的数据基础。其结果是个人和团队都更有韧性，他们会适应而不是抵触。 当每个人，无论什么角色，都采用成长型思维时，他们就会一起学习。同理心是一项关键能力。它不同于单纯的同情，而是从多个角度理解情境的能力——对用户和代码的影响；产品团队与技术团队之间的流程和协作模式所导致的顽固问题。 为了共同做出有影响力的决策，我们需要成长型思维，借鉴他人的经验来丰富我们的世界观，并引导自己获得更深刻的洞察力。 线性管道思维 还记得过去软件中某个地方有 Bug 的日子吗？修复一行代码就能解决问题。现在，在微服务和分布式系统构成的复杂世界中，Bug 通常存在于各部分之间的关联关系中。系统架构的艺术和科学在于设计和编排。 每天，我们都会经历摩擦，因为我们在一个异步世界中交付线性管道。或许我们称其为平台，但真正的平台是精心设计的不同技术与流程之间的关联体系。它们能用不同的方式响应不同时间发生的各类事件。平台的各部分相互协同，达成单个组件无法独立实现的成果。这种现象被称为涌现（emergence）。 面向涌现的设计需要综合多方视角，理解如何调整整个系统以实现包裹快速配送，而又不破坏异步关系。 综合意味着不能单打独斗。你需要其他人贡献他们的专业知识，并将这些专业知识与你的知识整合在一起。当我们无法构建能整合组织知识与经验的实践体系时……我们就无法设计（或调试）平台。于是我们交付了一条管道，而所有人都将它的缺陷归咎于不充分。 解决之道：构建关系 与其用线性思维处理异步情境，不如退一步思考以下问题： 在你的系统中，关系如何产生效果？系统各部分之间如何通过关系实现它们不直接做的事情？信息如何在技术系统中流动？痛点和瓶颈在哪里，以及如何优化关系以消除这些阻碍？ 如果你的组织不支持这项工作，就组建一个秘密小组。无论身处何种角色，都要将多元视角融入建议的更改方案中。确保信息在人员之间顺畅流动，从而实现服务之间的无缝衔接。 当具有不同观点的团队（如架构师 Diana 和产品经理 Cat）共同构建这些模式时，一切都会变得更加轻松。与其他团队交流，观察用户使用系统的过程，向基础设施团队了解他们的痛点，并将这些洞察融入解决方案之中。 交付能力不足 我们以为我们专注于目标，而实际上我们是在专注于需求。目标是一个可衡量的成果，比如，提高包裹递送速度。如果我们提高了系统的能力，我们就实现了目标，而不是简单地添加另外一项功能。 对于内部平台团队而言，一个可能的例子是：团队被告知需将软件部署管道从 Jenkins 迁移至 CircleCI。这明确告知了操作步骤，却未说明迁移背后的原因。 这里的隐藏目标是将开发者的管道维护工作量减少百分之五十。没有这些信息，团队可能会迁移了软件交付管道却没有达到预期的结果。他们也可能有一些想法，不需要昂贵的管道迁移就能实现目标。 部署变更的能力早就已经存在。在这种情况下，交付流程会频繁出现各种断层。对于如何部署变更，每个人都有不同的想法。如果关注点是改变工具，那么这些想法将导致无尽的摩擦。 解决之道：专注于目标 制定有意义的目标，并整合实现目标的各种方案。描述需要交付的具体且可衡量的效益或成果。确保目标紧密契合核心领域，即加速包裹配送。系统的所有功能都应该服务于这个目标。每次部署变更时，我们（期望）都在提升系统履行职责的能力。聚焦目标能确保每位贡献者都理解自身工作的价值。 去尝试 现在，你可能感到不知所措。“我做不到这一切！我的工作已经很忙了！”这是真的。 幸运的是，你不需要全都做。选一件事来做就行。一个可以减少摩擦的小变革，可以是你最感兴趣的事情，也可以是给你的日常生活造成最大摩擦的事情。 系统就是这样工作的……小变革可以扩展为大改进。摩擦在细节中，解决之道也在细节中。原文链接：https://www.infoq.com/articles/friction-fix/
作者：互联网容器团队-Chen Han、AI 研发团队 - Liu Dong Yang在大规模GPU容器集群与模型训练场景，面临稳定性和资源利用率等多重挑战。本文展示vivo GPU平台的总体架构，介绍容器平台在大规模GPU容器集群稳定性建设措施，以及探索多种GPU容器降本提效的解决方案。分享AI工程训练平台大规模训练稳定性建设，及GPU利用率提升实践经验。本文为2025年 vivo 开发者大会互联网技术专场分享内容之一，在微信公众号"vivo互联网技术"对话框回复【2025VDC】获取 2025VDC 互联网技术会场议题相关资料。1分钟看图掌握核心观点👇图1 VS 图2，您更倾向于哪张图来辅助理解全文呢？欢迎在评论区留言一、GPU平台架构vivo的GPU平台由物理层、容器平台层与AI工程层三方面构成。由多种GPU服务器和分布式存储以及高性能网络等基础设施，构成了可靠的物理层。容器平台层的GPU容器能力，主要包含了资源管理、编排调度、GPU虚拟化与多容器网络这四个方面。其中资源管理，表现为多种架构资源池的部署与管理能力。编排调度能力，由GPU弹性伸缩、训推潮汐部署以及多种卡调度策略组成。自研的GPU虚拟化囊括了业界主流的MIG虚拟化、内核层虚拟化以及CUDA层虚拟化三种技术。由传统的Underlay网络以及SRIOV的RDMA直通网络，组成了丰富的容器网络架构。容器平台提供了开放的API接口，为AI工程层的训练和推理平台，提供了坚实的算力底座。通过训练和推理平台，支撑公司内的智能计算业务。二、GPU容器能力实践GPU容器能力实践分为两个模块，首先是大规模容器集群稳定性建设，其次是GPU容器提效降本方案。先了解下容器平台在大规模容器集群场景，如何进行稳定性建设的。2.1 大规模容器集群稳定性集群稳定性是一切的基石。当集群规模大时，任务多，调度频繁，导致核心组件负载激增，极易发生集群崩溃。随着节点规模扩大，运维复杂度呈指数级增长，日常运维工作繁重，发现问题不及时。同时故障处理也面临严峻挑战，故障中涉及的复杂场景多，故障处理的难度大。稳定性建设需要解决上述问题。为了解决高频调度导致的核心组件高负载问题，我们针对Apiserver、etcd、CoreDNS，这3个核心组件进行了架构和性能优化，具体的方案如图所示。通过这些优化手段提升了组件性能，并且降低了组件负载，有利于大规模集群的平稳运行。为了减轻集群运维负担，我们重点建设了自动化节点管理方案。把重复性的运维事项自动化。同时我们还完善了监控告警体系，开发了自动化巡检功能，使运维人员能够及时发现集群问题，快速介入，处理潜在风险，保障集群能够长久稳定运行。故障处理是集群稳定的兜底措施，我们针对多个核心组件都做了，各类故障处理预案。结合可能存在的故障特点，构造故障场景，进行故障恢复演练，确保故障发生时，能够第一时间找到合理的解决方案，准确的处理问题。通过上述的措施，在集群稳定性方面取得了不错的效果，首先日常的集群可用性稳定保持在99.99%水平，其次平台的年度故障复盘数相较于上一年下降60%。核心组件方面的优化也达到了不错效果，其中Apiserver的CPU负载下降70%，etcd提交延迟，从秒级缩短到毫秒级，CoreDNS的毛刺现象消失了，并且负载量下降了90%左右。2.2 GPU容器提效降本实践容器平台的核心竞争力之一就是助力业务提效降本，我们从不同业务维度，对GPU容器提效降本方案进行了探索。首先在单卡维度，通过自研GPU虚拟化方案，使多个容器，互不干扰的共享一张卡资源。其次是在单服务维度，使业务能够自动应对，负载变化的GPU弹性扩缩容方案。在多服务维度，能够让推理服务和训练服务，分时复用整机资源的，训推潮汐部署方案。最后是在多机多卡的分布式场景中，让GPU容器搭配RDMA网络，来解决跨节点通信的瓶颈问题。2.2.1 单卡共享-GPU虚拟化如何让一张卡同时运行多个容器又不互相干扰，就涉及到GPU虚拟化技术。GPU虚拟化一直是AI云原生领域的热门话题之一，各大云厂商都有成熟的解决方案售卖。vivo容器平台的自研GPU虚拟化方案，主要为了解决业务的三大痛点，首先是部分推理业务负载偏低，无法有效用满整卡资源，需要通过共享部署方式，减少资源总量，降低业务成本，提升利用率。其次是不同业务共享同一张卡时，对于安全性以及隔离性的要求各不相同，就需要使用不同的GPU虚拟化技术来满足不同业务诉求。最后在Dev开发机场景，用户使用频率偏低，需要通过显存超售，来提升资源复用率，但显存超售后又需要避免某个用户将显存耗尽，导致OOM错误影响同卡的其他用户。自研GPU虚拟化方案包含MIG虚拟化、内核层虚拟化、CUDA层虚拟化这三种技术。结合业务场景，提供了丰富的卡调度策略，例如尽量聚集的Binpack策略、尽量分散的Spread策略，每个卡只有一个实例的CardOnlyOne策略，以及自定义节点和卡分配关系的CustomTopo策略。通过自研模块与组件，接入Kubernetes体系，对外提供统一调度能力。首先，MIG虚拟化技术，是基于Nvidia硬件提供的，切块组合能力，能够按规则把计算单元和显存单元进行组合，组成MIG实例挂载到容器内，提供完全独立的运行环境。MIG方案的优点是拥有Nvidia官方支持，可以集成到自研体系中。由于是在硬件层面实现的算力和显存限制，所以隔离性和安全性最好。缺点就是仅支持Ampere及以后架构的部分卡，而且限定了切分比例。主要应用场景是对算力隔离有强需求的线上业务。内核层虚拟化技术，是通过自研内核模块，创建虚拟字符设备替换原有的Nvidia字符设备，在内核态拦截IOCTL请求后，实现的算力和显存限制。优点是上层应用无感。并且内核态拥有良好的安全性。缺点是当前无开源方案，开发难度大，而且算力隔离的并不充分。主要应用场景是常规线上业务。CUDA层虚拟化技术的原理：使用拦截库替换Nvidia Driver的原始库，建立拦截库与原始库的，API函数映射关系，从而拦截调用函数，实现算力和显存的限制。优点是有开源方案，使用起来比较灵活。并且可以基于Nvidia提供的统一内存模型，开发显存超售能力。能够在显存不足时，使用内存替代，虽然处理速度下降，但是能够有效避免，显存OOM导致用户程序报错。缺点是用户态导致安全性不足，并且算力隔离能力偏弱，主要应用场景是Dev开发机场景。将自研的内核层虚拟化方案与业界方案，进行了自测性能对比，如图所示，可以看到自研方案在性能上，已经达到业界先进水平。业务使用该方案，与独占整卡部署相比较，平均单卡虚拟化率300%左右，就是把1张物理卡当3张卡使用，同时整机GPU利用率提升了30%+，成本优化超过50%。2.2.2 服务提效-GPU弹性扩缩容在单服务维度，如何帮助业务自动管理大量的GPU容器是提效的关键。我们引入了GPU弹性扩缩容方案。首先弹性扩缩容能力，能够快速响应负载变化，自动调节实例数量，减少人工干预次数，有利于业务在突发场景的平稳运行。其次是业务方在生产环境部署后，非生产环境的实例通常会闲置，这会浪费稀缺的GPU资源。最后由于Kubernetes原生，并不支持GPU维度的弹性扩缩容，需要寻找合适的方案来满足业务诉求。如图所示，我们是基于开源的KEDA框架，自研了GPU-Scaler组件，使用Prometheus中存储，来自DCGM-Exporter的GPU指标，汇聚为扩缩容事件，用于触发KEDA框架，调整实例个数，以此实现了GPU弹性扩缩容能力。由于KEDA框架支持将Workload实例数缩容到0，所以在非生产环境部署的GPU业务，默认开启无负载时，自动缩容到零的功能，以此自动回收，长期闲置的GPU资源。最终的使用效果，线上业务资源不足类告警，下降了80%，单业务平均减少约每周1小时的，扩缩容工作量，有效降低了GPU业务的运维成本。2.2.3 多服务降本-训推潮汐部署在多服务维度，训练服务的资源短缺问题，与推理服务，低峰时段资源空闲问题，相对突出。考虑让训练业务利用推理的空闲资源，即训推潮汐部署方案。首先推理和训练业务都需要稳定的运行环境。而且推理业务潮汐特征明显，夜晚负载低，资源空闲多，导致平均利用率偏低。并且多机多卡训练任务，需要整机资源，且资源需求日益增长，采购新设备，难且慢，导致训练资源缺口明显。训推潮汐部署就是整机资源分时复用的逻辑，如图所示，推理业务在白天高负载时，稳定运行，在夜晚低峰时段，自动腾挪出空闲整机资源，借给训练业务使用。在清晨时段，训练业务结束，把整机资源还给推理业务，如此达到分时复用的效果。如图所示。推理业务在部署前，需要评估保底负载容量。在部署时填入维持业务稳定的最少Pod数量。基于OpenKruise组件的，WorkloadSpread功能，管理不同的Subset，分别在稳定池和潮汐池中按需部署。同时配置CronHPA，定时缩容，自动调整副本数，到稳定Pod数量，优先删除潮汐池中的Pod。以此达到把潮汐池的节点整机腾空的效果。其中我们还针对Workload的缩容优先级进行了优化。当缩容发生时，结合Pod和节点的拓扑关系，把所在节点实例数少的Pod优先缩容，达到更快的腾空效果。通过上述方案，训推潮汐部署的降本效果明显，使推理业务，成本下降30%，同时整机GPU利用率提升20%多，有效缓解了训练资源短缺问题。2.2.4 多机多卡提效-容器RDMA高性能网络当前分布式训练和推理业务，对算力和显存的需求巨大，单节点资源不足，需要使用多机多卡资源，那么网络通信容易成为性能瓶颈。RDMA技术允许GPU直接访问支持RDMA设备中的数据，无需经过主机CPU或内存，实现跨节点的零拷贝数据传输，有效减少了CPU开销和网络延迟。所以从多机多卡维度，使用RDMA技术是网络提效的有效措施。从容器平台角度，GPU容器更加需要结合RDMA技术，提供简单高效的解决方案，方便业务使用。如图所示，RDMA容器有两个网卡，一个是使用Calico-CNI插件，通过veth创建的eth0网卡，对应的是Underlay网络。另一个是使用Sriov-CNI插件，通过VF创建的eth1网卡，对应的RoCE_v2或IB协议网络。我们引入了Multus-CNI组件，能够在单容器创建时，按需调用多种CNI插件。同时我们选择使用Spiderpool组件管理IP池，以及进行IP分配和路由策略配置。通过上述组件，在Kubernetes体系中实现了RDMA容器的全生命周期管理能力。基于容器RDMA能力，在大规模训练和推理场景，业务能够提速20%到30%之间，提升效果明显。三、AI工程训练平台实践3.1 训练平台整体架构VTraining训练平台是由vivo AI计算平台团队打造的一站式大模型训练方案，它面向算法工程师，提供模型开发、模型训练和海量样本存储等能力。VTraining底层是基于vivo容器平台、及高性能计算、网络、存储等基础设施之上构建，通过提供模型开发、模型训练、资产管理等能力，支撑公司的大模型训练业务。像vivo手机的蓝心小V、相册等核心产品的大模型训练，都是在VTraining平台进行迭代的。3.2 大规模训练稳定性实践3.2.1 稳定性背景稳定性问题是大规模训练的痛点。任务在大规模的同步训练过程中需要依赖计算、网络、存储、容器调度等复杂的基础设施环境，任何环节出问题都会导致任务中断，问题定位、恢复困难。例如知名头部公司千亿参数大模型的大规模训练任务，平均每3小时触发一次意外中断。3.2.2 稳定性实践-高频故障专项治理其中一个问题，是GPU集群投入使用初期机器故障率会很高，训练任务会经常被中断。为了降低机器故障率，我们进行了高频故障专项治理。首先对GPU集群进行了大规模测试诊断、然后进行高频故障统计和修复，把有问题的软硬件进行维修、替换、升级或修复。3.2.3 稳定性实践-故障处置流程完善另一个问题，是任务故障就是不可避免的，所以为了缩短任务中断时间，尽快恢复任务运行，我们对故障处置流程进行了重点建设完善。**训练前，**我们会针对GPU机器、网络通信等环境进行大规模检测，剔除异常节点、慢节点等问题节点，降低故障风险。**训练中，**会开启自动化容错机制，以便能及时发现基础设施或任务异常，快速进行故障定位和故障容错，自动隔离故障、自动重启恢复任务运行。**训练后，**对新问题进行搜集分析，完善异常特征库，增强问题诊断能力，以便后续遇到类似的故障可以快速容错。3.2.4 稳定性实践-效果与总结通过减少基础设施高频故障、完善任务故障处置流程两大措施，我们取得了良好效果：机器每天故障率由原来的百分之二下降到千分之一；千卡任务有效训练时长由原来的60%提升到99%，达到了行业一流水平。同时我们也积累了相关的稳定性经验：GPU集群由不稳定到稳定，需要一个软硬件磨合过程。因为不同的软硬件环境会触发不同的稳定性问题。大规模训练前，尽量剔除历史故障率高的机器。我们发现稳定的机器一般会一直很稳定，而故障率高的机器即使修复后出问题的概率也比较大。提升任务有效训练时长，需结合基础设施、训练框架、平台容错机制综合优化。例如秒级监控告警能力、checkpoint持久化策略等等都需要进行持续深入的优化。3.3 GPU利用率提升实践3.3.1 GPU利用率提升-业务背景及问题GPU是稀缺资源，但是差异化的业务场景下GPU难以高效利用，利用率提升困难。比如GPU场景常见业务形态：有训练任务、推理业务、数据生产、开发调试等等类型。他们各有特点：训练任务虽然GPU利用率高，但是偶尔也会出现碎片化空闲资源，比如算法同学偶尔会将任务停下来排查问题，调下参数之类的操作，任务并不是一直不间断地在跑的。推理业务有很明显的潮汐特性，白天流量高峰期GPU利用率高、到了夜间流量低峰期利用率会比较低。数据生产任务属于离线任务，GPU利用率高、资源需求大、但难申请到资源；开发调试任务的话GPU利用率低并且要长期占用资源，导致GPU利用率长期低下。所以不同的业务形态有不同的利用率特点，接下来介绍下我们的GPU利用率提升措施。3.3.2 利用率提升措施一：低优任务对于训练任务场景，偶现的碎片化空闲资源，我们 通过低优数据生产任务进行充分利用。如图所示，我们通过低优数据生产任务调度，复用训练场景偶现的碎片化资源，当正常任务需要资源时，可随时抢占低优资源，不会影响正常训练任务的调度。3.3.3 利用率提升措施二：训推潮汐部署对于推理业务场景，在夜间流量低峰期可以释放大量GPU资源，我们通过训推潮汐部署给离线业务复用。如图所示，通过训推潮汐部署机制，我们将夜间推理流量低峰期缩容的机器腾挪到了离线GPU资源池，给离线业务使用，白天再腾挪回在线GPU资源池进行扩容，达到潮汐复用的目的。3.3.4 利用率提升措施三：GPU虚拟化对于开发任务场景，长期独占GPU资源且利用率低，我们通过vivo自研VGPU虚拟化技术，减少开发任务占用的物理GPU卡数，释放冗余算力。如图所示，我们可以将单机4卡GPU机器，通过开启VGPU虚拟出16卡VGPU，相当于一卡顶四卡。VGPU的优点是：可支持1:2、1:4超卖、还可以用内存补充显存不足，所以对用户是无感知使用的，很适用于开发任务这种对性能要求低的场景。3.3.5 利用率提升总结与规划总之，训练平台通过低优任务、训推潮汐部署、GPU虚拟化等策略，深度适配差异化业务场景特性，实现了资源高效复用。AI整体GPU利用率均值绝对值提升了5个百分点，接近行业一流水平。未来训练平台也会持续对GPU利用率进行综合治理。例如进行低效任务治理、低效资源盘活、成本账单统计、奖励与惩罚措施的实施等等，让稀缺的GPU资源发挥更大价值！四、GPU平台未来展望在容器平台层面，我们会从多集群联邦调度、在离线GPU混部、国产异构计算芯片支持、GPU资源池化等方面能力进行综合建设，支撑上层平台业务对GPU资源的高效利用。训练平台层面，我们会增强故障预警、任务动态容错等能力，增强业务稳定性；同时完善对大模型训练全流程能力的支撑，以及对GPU资源进行更精细化的运营，从而让GPU业务更加稳定、资源利用更加高效！
Go语言跌到第16位：TIOBE榜单背后，咱们该怎么看这事儿？
刚出的榜单，Go掉得挺多今年1月的TIOBE编程语言排行榜出来了。有个事儿挺显眼的，Go语言这次排到了第16名。要知道，2024年11月它还在第7名呢，这才过了多久，直接掉了9名。很多写Go的朋友看到这个可能心里会犯嘀咕：这语言是不是不行了？以后还能不能用它找工作了？咱们先别急着下结论。在讨论这个问题之前，咱们得先搞清楚这个榜单到底是怎么回事，这次排名下降是不是真的代表Go语言出了大问题。TIOBE指数到底是啥？TIOBE这个榜单，它统计的数据来源其实是各大搜索引擎。简单说，就是看有多少人在百度、谷歌、必应这些地方搜这门语言的名字。它反映的是一种“搜索热度”。这里面有个逻辑大家要明白：一门语言搜的人多，不代表用的人就多；反过来，搜的人少，也不代表用的人就少。通常什么样的人会去搜？新手刚开始学的时候，或者遇到报错搞不定的时候，搜得最多。如果一门语言大家都会用了，或者它运行很稳定、没啥新花样，大家反倒不去搜了。所以，TIOBE的排名主要代表的是大家对这门语言的“好奇心”和“陌生感”，而不是它在实际项目里的使用率。为啥这次Go掉到了第16？那Go语言这次为啥排名掉得这么明显？我觉得有这么几个实实在在的原因。Rust语言现在确实很受欢迎。在这次榜单上，Rust排到了第13名。Rust在安全性、系统底层开发这些方面确实有优势，吸引了很多开发者的注意力。本来有些可能打算学Go的人，现在可能转头去研究Rust了。大家的关注点分散了，搜Go的人自然就少了一些。还有就是Go语言现在太“稳”了。它现在的版本兼容性做得很好，依赖管理也成熟了。以前大家可能会经常搜“Go怎么配置环境”、“Go这个库怎么用”，现在这些问题都解决了，不需要老去搜。而且，Go语言现在主要用在服务器后台、云计算这些地方。大家用Docker、用Kubernetes，底层其实都是Go写的，但大家平时操作的是命令行，不需要直接去写Go代码，也就不会去搜它。实际情况到底怎么样？排名虽然掉了，但咱们看看实际工作中的情况。现在的互联网公司，特别是做后端开发的，用Go的还是非常多。像很多大厂的核心系统，依然是用Go在写。在云原生这个领域，Go的位置目前还是很稳固的，没什么语言能轻易替代它。Go语言有个很大的优点，就是简单、直接。代码写起来快，跑起来性能也不错，维护起来也方便。对于公司来说，这能省成本，能提高效率。只要这个优势还在，公司就不会轻易把它换掉。总结所以看到排名下降，不用太担心。这个榜单反映的是当下的关注度和话题度，不是实际的市场占有率。Go语言现在进入了一个平稳发展的阶段，不像刚出来时那么有新鲜感，但它在实际工作中还是非常有用的。大家该学还是学，该用还是用。选编程语言，看的是能不能解决实际问题，能不能帮你把活干好，而不是看它在榜单上排第几。只要它还能帮你高效地开发系统，它就是有价值的。⚡️ 别把时间浪费在低效复习上很多人复习抓不住重点。作为过来人，我分析了100+份大厂面试记录，将 Go/Java/AI 的核心考察点、高频题、易错点 浓缩进了一份 PDF。不搞虚的，全是干货。加我微信：wangzhongyang1993，备注 【面经】 免费发你，立即纠正你的复习方向，把时间用在刀刃上。
CVE-2026-22822：External Secrets Operator严重漏洞破坏命名空间隔离机制
External Secrets Operator 中发现了一个严重安全漏洞。该工具是 Kubernetes 生态中广泛使用的外部密钥管理组件，用于连接 AWS Secrets Manager、HashiCorp Vault 等外部密钥系统与 Kubernetes 集群。漏洞编号为 CVE-2026-22822，CVSS 评分高达 9.3（严重），意味着攻击者可能借此直接获取敏感数据。 该漏洞导致 不安全的密钥读取（Insecure Secret Retrieval），并破坏了 Kubernetes 中最基本的命名空间隔离机制。 问题源于一个名为 getSecretKey 的模板函数。该函数最初是为了支持 senhasegura DevOps Secrets Management (DSM) 提供商而引入的，但后来被发现功能过于强大，从而带来安全隐患。 根据安全公告：“该函数能够在 external-secrets 控制器的 roleBinding 权限下跨命名空间读取密钥，从而绕过我们的安全机制。” 这意味着，一个命名空间中的恶意资源或配置错误的资源，可能读取到另一个命名空间的密钥—— 而这些密钥原本是完全不允许它访问的。“攻击者或配置错误的资源可以从非预期的命名空间中读取密钥。” 这种绕过的影响极为严重。如果攻击者能够读取特权命名空间中的密钥，他们就能轻松进一步提升权限并完全控制集群。报告指出：“未经授权访问密钥可能导致权限提升、数据泄露，或服务账号与凭据被窃取。” 管理员应立即审计其集群。该漏洞影响 External Secrets Operator 从 v0.20.2 到 v1.2.0 的所有版本。 维护者采取了果断的修复方式：直接删除了该功能。“该函数已被完全移除，因为它能实现的所有功能都可以通过其他方式完成，同时不会破坏我们的安全防护机制。” 用户被敦促立即升级到 v1.2.0 版本，该版本通过删除问题代码彻底修复了漏洞。 对于暂时无法升级的用户，也有临时缓解方案。管理员可以使用 Kyverno、Kubewarden 或 OPA 等策略引擎来 “阻止在任何 ExternalSecret 资源中使用 getSecretKey 函数”。
今天跟大家分享一个etcd的内存大量占用的问题，这是前段时间在我们开源软件Easegress中遇到的问题，问题是比较简单的，但是我还想把前因后果说一下，包括，为什么要用etcd，使用etcd的用户场景，包括etcd的一些导致内存占用比较大的设计，以及最后一些建议。希望这篇文章不仅仅只是让你看到了一个简单的内存问题，还能让你有更多的收获。当然，也欢迎您关注我们的开源软件，给我们一些鼓励。为什么要用ETCD先说一下为什么要用etcd。先从一个我们自己做的一个API网关 – Easegress（源码）说起。Easegress 是我们开发并开源的一个API应用网关产品，这个API应用网关不仅仅只是像nginx那样用来做一个反向代理，这个网关可以做的事很多，比如：API编排、服务发现、弹力设计（熔断、限流、重试等）、认证鉴权（JWT，OAuth2，HMAC等）、同样支持各种Cloud Native的架构如：微服务架构，Service Mesh，Serverless/FaaS的集成，并可以用于扛高并发、灰度发布、全链路压力测试、物联网……等更为高级的企业级的解决方案。所以，为了达到这些目标，在2017年的时候，我们觉得在现有的网关如Nginx上是无法演进出来这样的软件的，必需重新写一个（后来其他人也应该跟我们的想法一样，所以，Lyft写了一个Envoy。只不过，Envoy是用C++写的，而我用了技术门槛更低的Go语言）另外，Easegress最核心的设计主要有三个： 一是无第三方依赖的自己选主组集群的能力 二是像Linux管道命令行那样pipeline式的插件流式处理（支持Go/WebAssembly） 三是内置一个Data Store用于集群控制和数据共享。 对于任何一个分布式系统，都需要有一个强一制性的基于Paxos/Raft的可以自动选主机制，并且需要在整个集群间同步一些关键的控制/配置和相关的共享数据，以保证整个集群的行为是统一一致的。如果没有这么一个东西的话，就没有办法玩分布式系统的。这就是为什么会有像Zookeeper/etcd这样的组件出现并流行的原因。注意，Zookeeper他们主要不是给你存数据的，而是给你组集群的。Zookeeper是一个很流行的开源软件，也被用于各大公司的生产线，包括一些开源软件，比如：Kafka。但是，这会让其它软件有一个依赖，并且在运维上带来很大的复杂度。所以，Kafka在最新的版本也通过内置了选主的算法，而抛弃了外挂zookeeper的设计。Etcd是Go语言社区这边的主力，也是kubernetes组建集群的关键组件。Easegress在一开始（5年前）使用了gossip协议同步状态（当时想的过于超前，想做广域网的集群），但是后发现这个协议太过于复杂，而且很难调试，而广域网的API Gateway也没遇到相应的场景。所以，在3年前的时候，为了稳定性的考量，我们把其换成了内嵌版本的etcd，这个设计一直沿用到今天。Easegress会把所有的配置信息都放到etcd里，还包括一些统计监控数据，以及一些用户的自定义数据（这样用户自己的plugin不但可以在一条pipeline内，还可以在整个集群内共享数据），这对于用户进行扩展来说是非常方便的。软件代码的扩展性一直是我们追求的首要目标，尤其是开源软件更要想方设法降低技术门槛让技术易扩展，这就是为什么Google的很多开源软件都会选使用Go语言的原因，也是为什么Go正在取代C/C++的做PaaS基础组件的原因。背景问题好了，在介绍完为什么要用etcd以后，我开始分享一个实际的问题了。我们有个用户在使用 Easegress 的时候，在Easegress内配置了上千条pipeline，导致 Easegress的内存飙升的非常厉害- 10+GB 以上，而且长时间还下不来。用户报告的问题是——在Easegress 1.4.1 上创建一个HTTP对象，1000个Pipeline，在Easegres初始化启动完成时的内存占用大概为400M，运行80分钟后2GB，运行200分钟后达到了4GB，这期间什么也没有干，对Easegress没有进行过一次请求。一般来说，就算是API再多也不应该配置这么多的处理管道pipeline的，通常我们会使用HTTP API的前缀把一组属于一个类别的API配置在一个管道内是比较合理的，就像nginx下的location的配置，一般来说不会太多的。但是，在用户的这个场景下配置了上千个pipeline，我们也是头一次见，应该是用户想做更细粒度的控制。经过调查后，我们发现内存使用基本全部来自etcd，我们实在没有想到，因为我们往etcd里放的数据也没有多少个key，感觉不会超过10M，但不知道为什么会占用了10GB的内存。这种时候，一般会怀疑etcd有内存泄漏，上etcd上的github上搜了一下，发现etcd在3.2和3.3的版本上都有内存泄露的问题，但都修改了，而 Easegress 使用的是3.5的最新版本，另外，一般来说内存泄漏的问题不会是这么大的，我们开始怀疑是我们哪里误用了etcd。要知道是否误用了etcd，那么只有一条路了，沉下心来，把etcd的设计好好地看一遍。大概花了两天左右的时间看了一下etcd的设计，我发现了etcd有下面这些消耗内存的设计，老实说，还是非常昂贵的，这里分享出来，避免后面的同学再次掉坑。首当其冲是——RaftLog。etcd用Raft Log，主要是用于帮助follower同步数据，这个log的底层实现不是文件，而是内存。所以，而且还至少要保留 5000 条最新的请求。如果key的size很大，这 5000条就会产生大量的内存开销。比如，不断更新一个 1M的key，哪怕是同一个key，这 5000 条Log就是 5000MB = 5GB 的内存开销。这个问题在etcd的issue列表中也有人提到过 issue #12548 ，不过，这个问题不了了之了。这个5000还是一个hardcode，无法改。（参看 DefaultSnapshotCatchUpEntries 相关源码）// DefaultSnapshotCatchUpEntries is the number of entries for a slow follower // to catch-up after compacting the raft storage entries. // We expect the follower has a millisecond level latency with the leader. // The max throughput is around 10K. Keep a 5K entries is enough for helping // follower to catch up. DefaultSnapshotCatchUpEntries uint64 = 5000另外，我们还发现，这个设计在历史上etcd的官方团队把这个默认值从10000降到了5000，我们估计etcd官方团队也意识到10000有点太耗内存了，所以，降了一半，但是又怕follwer同步不上，所以，保留了 5000条……（在这里，我个人感觉还有更好的方法，至少不用全放在内存里吧……）另外还有下面几项也会导致etcd的内存会增加 索引。etcd的每一对 key-value 都会在内存中有一个 B-tree 索引。这个索引的开销跟key的长度有关，etcd还会保存版本。所以B-tree的内存跟key的长度以及历史版本号数量也有关系。 mmap。还有，etcd 使用 mmap 这样上古的unix技术做文件映射，会把他的blotdb的内存map到虚拟内存中，所以，db-size越大，内存越大。 Watcher。watch也会占用很大的内存，如果watch很多，连接数多，都会堆积内存。 （很明显，etcd这么做就是为了一个高性能的考虑）Easegress中的问题更多的应该是Raft Log 的问题。后面三种问题我们觉得不会是用户这个问题的原因，对于索引和mmap，使用 etcd 的 compact 和 defreg （压缩和碎片整理应该可以降低内存，但用户那边不应该是这个问题的核心原因）。针对用户的问题，大约有1000多条pipeline，因为Easegress会对每一条pipeline进行数据统计（如：M1, M5, M15， P99, P90, P50等这样的统计数据），统计信息可能会有1KB-2KB左右，但Easegress会把这1000条pipeline的统计数据合并起来写到一个key中，这1000多条的统计数据合并后会导致出现一个平均尺寸为2MB的key，而5000个in-memory的RaftLog导致etcd要消耗了10GB的内存。之前没有这么多的pipeline的场景，所以，这个内存问题没有暴露出来。于是，我们最终的解决方案也很简单，我们修改我们的策略，不再写这么大的Value的数据了，虽然以前只写在一个key上，但是Key的值太大，现在把这个大Key值拆分成多个小的key来写，这样，实际保存的数据没有发生变化，但是RaftLog的每条数据量就小了，所以，以前是5000条 2M（10GB），现在是5000条 1K（500MB），就这样解决了这个问题。相关的PR在这里 PR#542 。总结要用好 etcd，有如下的实践 避免大尺寸的key和value，一方面会通过一个内存级的 Raft Log 占大量内存，另一方面，B-tree的多版本索引也会因为这样耗内存。 避免DB的尺寸太大，并通过 compact和defreg来压缩和碎片整理降低内存。 避免大量的Watch Client 和 Watch数。这个开销也是比较大的。 最后还有一个，就是尽可能使用新的版本，无论是go语言还是etcd，这样会少很多内存问题。比如：golang的这个跟LInux内核心相关的内存问题 —— golang 1.12的版sget的是 MADV_FREE 的内存回收机制，而在1.16的时候，改成了 MADV_DONTNEED ，这两者的差别是，FREE表示，虽然进程标记内存不要了，但是操作系统会保留之，直到需要更多的内存，而 DONTNEED 则是立马回收，你可以看到，在常驻内存RSS 上，前者虽然在golang的进程上回收了内存，但是RSS值不变，而后者会看到RSS直立马变化。Linux下对 MADV_FREE 的实现在某些情况下有一定的问题，所以，在go 1.16的时候，默认值改成了 MADV_DONTNEED 。而 etcd 3.4 是用 来1.12 编译的。 最后，欢迎大家关注我们的开源软件！ https://github.com/megaease/
希望各位大神解答一下我找不到工作的原因。
下面是我的简历持有 CKA ccna 认证。长期负责高并发电商系统的稳定性与性能治理，理解 Nginx 的事件驱动模型、Worker 并发机制与请求生命周期控制方式，并将其抽象为 “进入策略（ Admission ）— 排队策略（ Queueing ）— 满载策略（ Overload ）” 的系统行为诊断框架。通过拆解全链路时间指标（ Time-based Metrics ），结合 P95 / P99 延迟分位数，对比 request_time 与 upstream_response_time，判断请求阻塞发生在进入控制、系统排队或下游依赖阶段，用于快速界定网络层、应用层与数据层的性能边界。参与并主导多次从单体架构向云原生、无状态化架构的演进，关注系统的可解释性、稳定性与成本控制。技术技能SRE 与性能诊断 使用 Ingress / Queue / Worker / Egress 作为系统分层对象进行问题定位 基于 P95 / P99 延迟分位数 分析尾延迟（ Tail Latency ） 通过 request_time 与 upstream_response_time 的分位数差异判断系统内部是否发生排队 区分整体性能退化与少量请求异常放大的不同问题模式 依据进入控制、排队与满载策略分析系统稳定性取舍 Web 与中间件 Nginx 事件驱动模型、Worker 并发模型、连接与请求生命周期 使用 limit / buffer / backlog / timeout 等配置参数实施系统行为控制 Nginx 与 PHP-FPM 的 Worker / Process / Queue 协同关系 高并发 WordPress 架构的稳定性与性能治理 云原生与基础设施 阿里云：ECS 、RDS 、OSS 、ALB AWS Docker 、Kubernetes （ CKA ） Terraform （基础设施即代码） Calico （ Kubernetes 网络模型与 NetworkPolicy ） 数据库与数据处理 MySQL 使用与常见性能问题定位 SQL 编写 PL/SQL 阅读 ETL 流程（数据抽取、清洗、加载） 结合 P95 / P99 延迟分布 判断数据库是否为系统尾延迟来源 自动化与运维 Ansible Playbook Shell 脚本 配置一致性与变更管理 网络 TCP/IP VPN 负载均衡 CCNA 网络体系 工作经历基础设施负责人 / 高级运维工程师负责自营跨境电商平台的技术架构设计、云资源管理与系统稳定性。性能瓶颈诊断与容量优化 通过时间指标发现平均响应时间稳定，但 P95 / P99 延迟显著升高 在 upstream_connect_time 正常的情况下，response_time 分位数拉长 判断请求未阻塞在网络或 TCP 层，而是在系统内部发生资源排队 结合 Nginx 与 PHP-FPM 的并发模型，将问题定位为应用层并发策略导致的 Worker 争用 优化措施： 引入 Redis 缓存，降低同步资源竞争 调整 PHP-FPM Worker 数量，减少高分位请求等待时间 调整 Nginx 超时与失败处理策略，防止慢请求放大系统负载 结果： 页面 P95 延迟从约 5 秒下降至 2 秒以内 尾延迟明显收敛 高峰期服务稳定性显著提升 电商架构云原生改造 数据库迁移至阿里云 RDS 媒体资源迁移至 OSS 前端通过 ALB 进行多节点负载 应用层实现无状态化部署 结果： 系统支持水平扩展 综合成本下降约 30% 大促期间可用性维持在 99.9% 日常运维 使用 Ansible 管理 Nginx / PHP 配置 MySQL 备份与恢复演练 OpenVPN 远程访问环境维护 早期经历网络管理员 / IT 支持2011 年 – 2015 年 企业网络规划与服务器维护 SQL 数据提取与分析 教育背景与证书 CKA （ Certified Kubernetes Administrator ） CCNA （ Cisco Certified Network Associate ） 请教各位。我做了 10 年电商，从 23 岁就开始做了，这些爱好自学的。现在走下坡路了，要出来找工作了。 我学历也很低，是函授大专。今年 33 岁了。 我对内核，nginx,sre ，这些也有深入的理解，我不会开发软件，纯粹的想走运维路线 最近也打算学 python ，不会写脚本确实没有竞争力。 我知道我的问题，学历低，没项目经验和实际的工作经验，年纪也大。 上面每项技术，我确实认真的学了很久，而且做过大量的实验实操，理论也很扎实。 boss 直聘主动联系我的人很多，但是简历发了后基本就没下文了。 各位有某些负责招聘的老大，希望能说一下你们的观点 假如我真的没戏，我就不打算找这些工作了。 我也做外贸独立站。然后平时会搭建很多开源项目，也不是玩，确实是投入实际使用。所以不断的积累了相关的操作。就是把自己学的，都在开源项目里应用。
背景前天朋友提供一个内推岗，这个公司蛮不错的，规模大待遇好还不是外包也不是有争议的 web3 ，他在里面工作，说招好几个月了还是没人去。我有个个人微服务项目准备拿去应聘，然而推荐后说没办法还是得垂直经验，因为现在有 AI 生成代码很简单，个人项目很容易被认为是 AI 代工。项目介绍项目原先是通过网课教程做的但不符合生产要求被我全部推翻重写，原来是 go micro 2.9.1 现在是 go micro 4 ，所有服务都是领域驱动，改过框架源码，链路追踪、监控、日志系统、架构等全部一人完成，期间技术栈做了很大的调整，一共迭代 6 个版本，目前是 6.1 ，耗时 3 个月，至今仍在迭代，有部分自编组件。包含压测报告、决策记录、变更日志和自述文件（含项目介绍及部署指南），用 Github Project 管理项目，2 周一版，部署在阿里云 K8S 集群上，使用超过 15 个组件，还用到 LUA 脚本。服务是模拟支付回调扣减库存过程，每个服务 2 个副本，单个 Pod 上限为单核 CPU + 512M 内存，压测 1596Qps ，P99 为 84ms 。不存在 AI 代工我开发过程中主要是用 AI 推荐轻量级工具并分析其难度，代码大部分还是自己写，因为 go micro 做 EDA 架构的案例本身就少得可怜直接导致 AI 生成的代码不靠谱，最后还是被我的方案优雅地取代。开发过程中每个版本都是巨大的挑战。请问各位大佬如何证明个人项目不是 AI 代工以实现成功转型 Golang 开发？
RustFS 作为新一代的分布式对象存储系统，提供了 Helm Chart 以便 Kubernetes 集群上安装 RustFS 实例。而 DirectPV 是一个符合 CSI 标准的 Kubernetes 存储项目，由 Minio 发布且开源。本文使用 DirectPV 为 Kubernetes 上的 RustFS 实例提供后端存储服务，实现两个对象存储服务的“结合”。前提运行良好的 Kubernetes 集群。本文使用 K3S 作为测试环境，根据 K3S 安装指南完成安装：# 安装 K3S curl -sfL https://get.k3s.io | sh - # 安装确认 kubectl get nodes NAME STATUS ROLES AGE VERSION vm-0-17-ubuntu Ready control-plane 63m v1.34.3+k3s1一块空磁盘本文在安装 K3S 的服务器上（OS 为 Ubuntu 24.04）挂载了一块容量为 20GB 的新磁盘：df -h vdb 253:16 0 20G 0 disk /root/data/disk mount | grep vdb /dev/vdb on /root/data/disk type ext4 (rw,relatime)安装 DirectPV可以直接根据 minio/directpv 文档进行 DirectPV 的安装。这个过程中会使用到 krew plugin，根据不同的 OS 执行安装命令即可。在 Ubuntu 上执行如下命令：( set -x; cd "$(mktemp -d)" && OS="$(uname | tr '[:upper:]' '[:lower:]')" && ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" && KREW="krew-${OS}_${ARCH}" && curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" && tar zxvf "${KREW}.tar.gz" && ./"${KREW}" install krew )安装完毕，将 PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" 写到 ~/.bashrc 或 ~/.zshrc 即可。开始安装 DirectPV。安装 directpv krew 插件kubectl krew install directpv在 Kubernetes 集群中安装 DirectPVkubectl directpv install Installing on unsupported Kubernetes v1.34 ███████████████████████████████████████████████████████████████████████████ 100% ┌──────────────────────────────────────┬──────────────────────────┐ │ NAME │ KIND │ ├──────────────────────────────────────┼──────────────────────────┤ │ directpv │ Namespace │ │ directpv-min-io │ ServiceAccount │ │ directpv-min-io │ ClusterRole │ │ directpv-min-io │ ClusterRoleBinding │ │ directpv-min-io │ Role │ │ directpv-min-io │ RoleBinding │ │ directpvdrives.directpv.min.io │ CustomResourceDefinition │ │ directpvvolumes.directpv.min.io │ CustomResourceDefinition │ │ directpvnodes.directpv.min.io │ CustomResourceDefinition │ │ directpvinitrequests.directpv.min.io │ CustomResourceDefinition │ │ directpv-min-io │ CSIDriver │ │ directpv-min-io │ StorageClass │ │ node-server │ Daemonset │ │ controller │ Deployment │ └──────────────────────────────────────┴──────────────────────────┘ DirectPV installed successfully安装确认并获取安装信息 kubectl -n directpv get pods NAME READY STATUS RESTARTS AGE controller-54d56fb9f8-92cz8 3/3 Running 0 90m controller-54d56fb9f8-kfltl 3/3 Running 0 90m controller-54d56fb9f8-ncxcn 3/3 Running 0 90m node-server-vgpn2 4/4 Running 0 90m kubectl directpv info ┌──────────────────┬──────────┬───────────┬─────────┬────────┐ │ NODE │ CAPACITY │ ALLOCATED │ VOLUMES │ DRIVES │ ├──────────────────┼──────────┼───────────┼─────────┼────────┤ │ • vm-0-17-ubuntu │ - │ - │ - │ - │ └──────────────────┴──────────┴───────────┴─────────┴────────┘ 0 B/0 B used, 0 volumes, 0 drives添加磁盘（驱动）首先检测磁盘信息并将其信息写到 drives.yaml 文件中：kubectl directpv discover Discovered node 'vm-0-17-ubuntu' ✔ ┌─────────────────────┬────────────────┬───────┬────────┬────────────┬──────┬───────────┬─────────────┐ │ ID │ NODE │ DRIVE │ SIZE │ FILESYSTEM │ MAKE │ AVAILABLE │ DESCRIPTION │ ├─────────────────────┼────────────────┼───────┼────────┼────────────┼──────┼───────────┼─────────────┤ │ 253:16$PXmUgO0FF... │ vm-0-17-ubuntu │ vdb │ 20 GiB │ ext4 │ - │ YES │ - │ └─────────────────────┴────────────────┴───────┴────────┴────────────┴──────┴───────────┴─────────────┘ Generated 'drives.yaml' successfully.drives.yaml 文件内容如下：version: v1 nodes: - name: vm-0-17-ubuntu drives: - id: 253:16$PXmUgO0FF7sKtsaVihMadap1hCZil9Rksbz2SdQkMfA= name: vdb size: 21474836480 make: "" fs: ext4 select: "yes"接着使用 drives.yaml 文件进行 DirectPV 初始化：kubectl directpv init drives.yaml --dangerous ███████████████████████████████████████████████████████████████████████████ 100% Processed initialization request '3a70561d-3de0-4756-b256-159fc98593d1' for node 'vm-0-17-ubuntu' ✔ ┌──────────────────────────────────────┬────────────────┬───────┬─────────┐ │ REQUEST_ID │ NODE │ DRIVE │ MESSAGE │ ├──────────────────────────────────────┼────────────────┼───────┼─────────┤ │ 3a70561d-3de0-4756-b256-159fc98593d1 │ vm-0-17-ubuntu │ vdb │ Success │ └──────────────────────────────────────┴────────────────┴───────┴─────────┘恭喜你，走到这一步，你已经成功安装了 DirectPV（之前的每一步出错都会导致失败，请认真查看命令以及输出结果），使用如下命令确认：kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE directpv-min-io directpv-min-io Delete WaitForFirstConsumer true 90m local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 115m可以看到，名为 directpv-min-io 的 StorageClass 已经存在。接下来就使用这个 SC 进行 RustFS 的安装。在 K3S 上安装 RustFSRustFS 提供 Helm Chart来在 Kubernetes 上安装 RustFS。目前支持两种模式：单机单盘（SNSD）和多机多盘（MNMD）。可以将 GitHub Repo 代码 clone 到本地，然后进入到 helm/rustfs 目录下进行安装，也可以直接使用 RustFS 的远端仓库（RustFS 已经将 Helm Chart 发布到了 Artifact Hub），比如：# 添加仓库 helm repo add rustfs https://charts.rustfs.com # 安装 RustFS helm install rustfs -n rustfs rustfs/rustfs --create-namespace --version 0.0.80由于 RustFS Helm Chart 默认使用 local-path StorageClass，而且默认的 PVC 大小为 256Mi，因此需要根据自身情况设置合适的大小，最简单的方式就是在本地创建一个 values.yml 文件，然后修改如下内容：storageclass: name: directpv-min-io dataStorageSize: 256Mi logStorageSize: 256Mi当然，也可以用 --set 来实现参数的覆盖，但是由于 RustFS 多种安装模式、多种 Ingress Controller，以及 pod 资源的自定义等，--set 就需要指定多个参数，会显得繁琐。将需要变更的信息写到本地 values.yml，然后用 -f 指定，可能更加便捷的自定义安装 RustFS。本文采用本地安装模式（也就是 Helm Chart 代码在本地），执行如下命令进行安装：helm install rustfs ./ -n rustfs --create-namespace -f values.yaml 查看 PVCkubectl -n rustfs get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE data-rustfs-0-rustfs-0 Bound pvc-8e9b520f-3a96-4a64-afb3-70f13d3edcd3 256Mi RWO directpv-min-io <unset> 61s data-rustfs-0-rustfs-1 Bound pvc-8bef3219-469c-452c-969a-89c8470d3945 256Mi RWO directpv-min-io <unset> 61s data-rustfs-0-rustfs-2 Bound pvc-aee2c489-6f4c-47dc-b464-b09fc5ea112c 256Mi RWO directpv-min-io <unset> 61s data-rustfs-0-rustfs-3 Bound pvc-b59ec27c-9fb0-4ad1-a204-9858c1d405da 256Mi RWO directpv-min-io <unset> 61s data-rustfs-1-rustfs-0 Bound pvc-8d840468-f6be-4154-ae42-73f68f6e36e3 256Mi RWO directpv-min-io <unset> 61s data-rustfs-1-rustfs-1 Bound pvc-c5adc67b-f6ea-470a-861d-9b48b610bbee 256Mi RWO directpv-min-io <unset> 61s data-rustfs-1-rustfs-2 Bound pvc-8d7b98e0-ff0b-4d5f-869c-fe7c1b71ffc2 256Mi RWO directpv-min-io <unset> 61s data-rustfs-1-rustfs-3 Bound pvc-9268589f-7ca7-4480-a724-36bfcdc29cff 256Mi RWO directpv-min-io <unset> 61s data-rustfs-2-rustfs-0 Bound pvc-f31689f3-1aa8-42f7-8fcb-f309a6b390b5 256Mi RWO directpv-min-io <unset> 61s data-rustfs-2-rustfs-1 Bound pvc-28fecb41-9dd7-436d-9317-e8a3a588a87a 256Mi RWO directpv-min-io <unset> 61s data-rustfs-2-rustfs-2 Bound pvc-77d4c8e6-918a-4b28-a2bc-408195f807d3 256Mi RWO directpv-min-io <unset> 61s data-rustfs-2-rustfs-3 Bound pvc-6deab996-a8a3-4e02-ae6c-845f863526c0 256Mi RWO directpv-min-io <unset> 61s data-rustfs-3-rustfs-0 Bound pvc-46c7cc1a-1f25-4c3e-8168-3c288ee552d5 256Mi RWO directpv-min-io <unset> 61s data-rustfs-3-rustfs-1 Bound pvc-a0403935-2471-48d8-beac-fcf28fd85a7a 256Mi RWO directpv-min-io <unset> 61s data-rustfs-3-rustfs-2 Bound pvc-d0c88736-ee1a-47e5-a335-53d086e87913 256Mi RWO directpv-min-io <unset> 61s data-rustfs-3-rustfs-3 Bound pvc-9fbac8a8-cb59-430b-abc1-4ad5105ed4ad 256Mi RWO directpv-min-io <unset> 61s logs-rustfs-0 Bound pvc-bc673cea-6cf0-479f-a323-5c2102479796 256Mi RWO directpv-min-io <unset> 61s logs-rustfs-1 Bound pvc-c823f3a4-2e07-4331-bdd3-f0c6172bb15b 256Mi RWO directpv-min-io <unset> 61s logs-rustfs-2 Bound pvc-059eeaf9-b209-41ec-87f6-da87f0105c41 256Mi RWO directpv-min-io <unset> 61s logs-rustfs-3 Bound pvc-348e4bfb-d272-4deb-ae8e-fc6ea70d4d74 256Mi RWO directpv-min-io <unset> 61s可以看到生成了分布式安装所需的所有 PVC，状态是 Bound。接着查看 pods 状态：kubectl -n rustfs get pods NAME READY STATUS RESTARTS AGE rustfs-0 1/1 Running 0 69s rustfs-1 1/1 Running 0 69s rustfs-2 1/1 Running 0 69s rustfs-3 1/1 Running 0 69s可以看到 pod 运行正常。接着就可以使用 ingress 来访问该 RustFS 实例了。注意事项安装 DirectPV 的过程中，会对该磁盘上的数据进行格式化，而且该磁盘不能被其他程序占用，否则会出现如下错误： ┌──────────────────────────────────────┬────────────────┬───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ REQUEST_ID │ NODE │ DRIVE │ MESSAGE │ ├──────────────────────────────────────┼────────────────┼───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ e9adb7af-8061-46b1-8112-d86e5fb653cd │ vm-0-17-ubuntu │ vdb │ Failed; unable to format device /dev/vdb; unable to execute command [mkfs.xfs -i maxpct=50 -m uuid=2be5b9cc-beeb-4d54-bbcb-a1cbc5f0ef97 -f -L DIRECTPV /dev/vdb]; output=mkfs.xfs: cannot open /dev/vdb: Device or resource busy │ │ │ │ │ ; error=exit status 1 │ └──────────────────────────────────────┴────────────────┴───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘可以通过将此磁盘 umount 来解决。
本文以麒麟V10为例，演示超简单离线部署k8s 1.32.11。1 说明关于ktkt是基于kk二次开发产物，具备kk的所有功能，二开重点适配了信创国产化环境。主要改进包括：简化arm架构部署过程、支持国产化和国际环境在线、离线部署及一条命令所有节点初始化。支持arm64和amd64架构操作系统，已适配芯片+操作系统 如下：CPU： 鲲鹏、飞腾、海光、兆芯、intel、amd 等。OS： Centos、Ubuntu、Debian、银河麒麟V10、麒麟国防版、麒麟信安、中标麒麟V7、统信UOS、华为欧拉、移动大云、阿里龙蜥、TencentOS等。注：本文使用kt版本3.1.13kt文档： kt文档2.环境准备服务器基本信息主机名架构OS配置IPmasterx86_64麒麟V102核4G192.168.85.1532.1 上传离线制品操作系统不需要安装docker,不需要设置selinux,swap等操作，全新的操作系统即可。将离线制品、配置文件、kt和sh脚本上传至服务器其中一个节点(本文以master为例)，后续在该节点操作创建集群。2.2 修改配置文件根据实际服务器信息，配置到生成的config-sample.yaml中kind: Cluster metadata: name: sample spec: hosts: - {name: master, address: 192.168.85.160, internalAddress: 192.168.85.143, user: root, password: "123123"} roleGroups: etcd: - master control-plane: - master worker: - master # 如需使用 kk 自动部署镜像仓库，请设置该主机组 （建议仓库与集群分离部署，减少相互影响） # 如果需要部署 harbor 并且 containerManager 为 containerd 时，由于部署 harbor 依赖 docker，建议单独节点部署 harbor registry: - master controlPlaneEndpoint: ## Internal loadbalancer for apiservers internalLoadbalancer: haproxy domain: lb.kubesphere.local address: "" port: 6443 kubernetes: version: v1.32.11 clusterName: cluster.local autoRenewCerts: true containerManager: docker etcd: type: kubekey network: plugin: calico kubePodsCIDR: 10.233.64.0/18 kubeServiceCIDR: 10.233.0.0/18 ## multus support. https://github.com/k8snetworkplumbingwg/multus-cni multusCNI: enabled: false registry: type: harbor registryMirrors: [] insecureRegistries: [] privateRegistry: "dockerhub.kubekey.local" namespaceOverride: "kubesphereio" auths: # if docker add by `docker login`, if containerd append to `/etc/containerd/config.toml` "dockerhub.kubekey.local": username: "admin" password: Harbor@123 # 此处可自定义，kk3.1.8新特性 skipTLSVerify: true # Allow contacting registries over HTTPS with failed TLS verification. plainHTTP: false # Allow contacting registries over HTTP. certsPath: "/etc/docker/certs.d/dockerhub.kubekey.local" addons: []2.3 系统初始化解压kt-x86.tar.gz文件后执行./kt init-os -f config-sample.yaml 已适配操作系统和架构见1.说明该命令kt会根据配置文件自动判断操作系统和架构以完成所有节点的初始化配置和依赖安装。3 创建 Harbor私有仓库3.1 创建镜像仓库./kt init registry -f config-sample.yaml -a artifact-x86-k8s13211.tar.gz此命令会在harbor节点自动安装docker和docker-compose3.2 创建harbor项目创建 Harbor 项目chmod +x create_project_harbor.sh && ./create_project_harbor.sh4 创建k8s./kt create cluster -f config-sample.yaml -a artifact-x86-k8s13211.tar.gz --with-local-storage此命令kt会自动将离线制品中的镜像推送到harbor 私有仓库执行后会有如下提示,输入yes/y继续执行继续等待一段时间最终可以看到安装成功的消息验证5 总结本文主要以离线方式部署，适用于在线和离线两种状态，而如果在线状态，那么步骤3可忽略，两条命令即可搞定。配合最新版kt，系统初始化从未如此简单，不论x86还是arm，不论在线还是离线，不论国际还是国产操作系统，统统搞定。