FDE Times 数据在招 FDE 职位 826▼35 近 7 天在招职位数的变化(同口径比较):不计入本周新开始追踪的公司的职位近 7 天新增 77在招公司 154支持远程 25%美国薪资中位数 $202k招聘最多 Databricks 104
ENVI

前线部署工程师(FDE)的专业媒体

技能指南 · 指南

软件装进客户集群后,如何依然看得见它

完整 VPC 或本地部署时,厂商既不掌握集群也不掌握数据,诊断信号必须从第一天就设计好。

分享微博

要点速览

  • Reducto 的基础设施方向前线部署工程师(FDE)负责把软件部署进客户环境的全部工作,从规划、配置到测试和上线。
  • 遥测只携带作业 ID、状态、耗时、脱敏后的错误类别等元数据,因此错误码从一开始就要足够具体。
  • 升级有阻断性的前置条件;物理隔离环境中的安装,只有在有人生成支持包时才会把信号送出去。
表格对比 Reducto 的三种部署模型。混合 VPC(高亮):数据位于客户的云中,计算运行在 Reducto 的基础设施上,客户无需 GPU。完整 VPC:数据和计算都在客户的云中,客户需要 Kubernetes 和 PostgreSQL。本地部署:数据位于客户的基础设施上,计算在现场运行,客户自行管理基础设施。
只有混合 VPC 把计算(包括 GPU 推理)移出了客户的基础设施,另外两种模型把一切都留在客户一侧。来源:Reducto 部署文档。

合同已经签了。客户的安全团队只提了一个条件:任何文档都不得离开他们的基础设施。从现在起,你的软件将运行在一个不属于你的集群上,躲在一道不是你配置的防火墙后面;凌晨 2 点出故障时,最先发现的很可能是客户。

文档处理软件公司 Reducto 正是在为这样的岗位招人:Forward Deployed Engineer, Infrastructure Specialist,即基础设施方向的前线部署工程师(FDE)。按照职位描述,这个人负责把 Reducto 部署进客户环境,并端到端地承担这项工作,从规划、配置到测试和上线。

如果你想做基础设施方向的 FDE,这是最先要练的技能。让软件在自己的机器上跑起来很容易,难的是让它在别人的机器上跑起来,并且依然知道它是健康还是出了问题。

数据在谁手里,计算在谁手里?

敲下第一条命令之前,你要先弄清客户买的是哪种模型,因为这决定了数据由谁持有、计算由谁运行,以及你将在哪里调试。Reducto 提供三种部署模型,其中 VPC 和本地部署(on-premise)仅面向 Enterprise 客户。基础设施方向的 FDE 最常遇到的两种区别如下。

混合 VPC 完整 VPC / 本地部署
数据与存储 留在客户的云账号中 位于客户环境内部
计算 完全由 Reducto 托管,使用临时的单租户 worker,除内存外不保留任何内容 在客户环境内部运行
你能看到什么 Reducto 数据库中的作业记录:状态、请求设置、结果存放位置 只能看到客户允许的内容,因为可观测性访问和出站流量由客户控制
客户控制什么 云账号以及接收结果的存储 网络、API 访问、Kubernetes 策略、存储策略、可观测性、出站流量

最后一行体现了客户控制范围的扩大,而完整 VPC/本地部署这一列是最难的情况。在混合 VPC 下,结果写入客户的存储,但你仍有作业记录可以查看状态。在完整 VPC 或本地部署下,连查看系统的权限都需要你去申请。

所以项目启动时要问的不只是数据放在哪里,还要问:谁给你开通日志和指标的访问权限,信号允许通过哪条路径发出去。

不碰文档,也能看清系统

Reducto 的安全策略划了一条清晰的界线:遥测是只含元数据的可观测性手段,不是数据管道。它可以包含作业 ID、计数、状态、耗时、脱敏后的错误类别,以及其他用于调试的元数据。

职责划分同样分明。Reducto 负责应用安全和租户级访问控制;客户负责对外网络暴露、调用方授权、出站流量控制、Kubernetes 加固,以及遥测的路由和保留期限。换句话说,你的遥测发往哪里、保存多久,由客户决定。

设想你为一个文档处理作业设计的遥测事件。下面是假设的示例,并非 Reducto 的数据结构:

{
  "event": "job_completed",
  "job_id": "j_8f2c",
  "pages": 42,
  "file_type": "pdf",
  "duration_ms": 18350,
  "worker": "cpu-3",
  "status": "partial",
  "error_code": "TABLE_PARSE_TIMEOUT"
}

没有文件名,也没有文档里的任何一行文字。但当客户反馈“昨天那份合同文件返回的结果不完整”时,你依然可以筛选出 partial 状态的作业,发现它们都超过 40 页,并且带有同一个超时错误码。这样你就有了一个可以用自己的样本数据去验证的假设。

由此得出的教训是:错误类别必须足够具体。一个笼统的 error: "failed" 字段,会逼得你去请客户把文档发过来,而这恰恰是合同所禁止的。

一次升级,逐步拆解

首次安装只是开始,因为本地部署的版本之后还要升级很多次。Reducto 本地部署版 v1.12.6 的更新日志写明:Helm 要求 Redis 以及健康的 io/cpu worker(v1.12.6 或更高版本)就位后,才允许升级。

这句话有两种理解:要么是 worker 必须运行 v1.12.6 的镜像,要么是这种阻断机制从 chart v1.12.6 起才存在。所以不要把其中一种理解硬编码进脚本。去问厂商,并把版本检查保留为可选项。

这个阻断条件保护了你,但也可能让升级卡在客户安排好的维护窗口中途。在 Helm 有机会拒绝之前,先自己跑一遍检查。下面的脚本用来说明思路;其中的命名空间、标签、deployment 名称,以及镜像标签带有版本号的假设,都是虚构的:

#!/usr/bin/env bash
set -euo pipefail
NS="${1:-reducto}"
CHECK_VERSION="${CHECK_VERSION:-0}"   # 与厂商确认后设为 =1
MIN="1.12.6"

echo "== Redis =="
redis_ready=$(kubectl -n "$NS" get pods -l app=redis \
  -o jsonpath='{.items[*].status.containerStatuses[*].ready}')
[[ -n "$redis_ready" && "$redis_ready" != *false* ]] \
  || { echo "Redis 缺失或未就绪"; exit 1; }

for role in io cpu; do
  echo "== worker $role =="
  d="worker-$role"
  ready=$(kubectl -n "$NS" get deploy "$d" -o jsonpath='{.status.readyReplicas}')
  want=$(kubectl -n "$NS" get deploy "$d" -o jsonpath='{.spec.replicas}')
  [ "${ready:-0}" = "$want" ] \
    || { echo "$d 未就绪:${ready:-0}/$want"; exit 1; }

  if [ "$CHECK_VERSION" = "1" ]; then
    image=$(kubectl -n "$NS" get deploy "$d" \
      -o jsonpath='{.spec.template.spec.containers[0].image}')
    ver="${image##*:}"; ver="${ver#v}"
    lowest=$(printf '%s\n%s\n' "$MIN" "$ver" | sort -V | head -n1)
    [ "$lowest" = "$MIN" ] \
      || { echo "$d 当前版本为 $ver,低于 $MIN"; exit 1; }
  fi
done

echo "预检通过,可以执行 helm upgrade"

默认情况下,如果 Redis 没有 pod 或有容器未就绪,或者某个 worker 副本数不足,脚本就会停止。用 CHECK_VERSION=1 运行时,它还会把 worker 镜像标签中的版本与 v1.12.6 进行比较。它不能取代 Helm 自身的检查;如果客户使用 latest 之类的标签或镜像摘要,你就得换一种方式读取版本。

这个脚本的价值之一在于客户可以自己运行。如果客户不给你 kubeconfig,一个打包成单条命令、输出结果清晰易读的诊断工具,就能弥补你没有的访问权限。

集群无法访问互联网时

Honeycomb 把这种情况分成两种模型:由厂商自己运维平台,或者由客户管理全部基础设施。第二种适合物理隔离(air-gapped)环境,在那里,你原以为会“自动回传”的每一个信号都得另找出路。

Replicated 的做法是:收集物理隔离环境中安装实例的遥测,并存放在客户环境内的一个 Kubernetes Secret 中。只有当有人在该环境中生成支持包(support bundle)时,这些数据才会到达厂商,而且本地存储有容量上限。

实际影响是:如果客户每隔几个月才生成一次支持包,较早的信号可能早已被挤出存储。对于用量、日志、补丁等每一类数据流,都要在一开始就和客户确认:它怎么出去,由谁带出去,多久一次。

动手试试:上线前要完成的五项任务

第一项任务是和客户一起确定部署模型,回答三个问题:数据放在哪里,计算在哪里运行,集群能否访问互联网。把答案写进项目启动文档,并由安全团队签字确认。

接着列一张表,写明客户方每一项事务的负责人:对外网络暴露、出站流量、Kubernetes 策略、可观测性访问、遥测路由和保留期限。每一行都要有具体的人名。

然后以书面形式约定遥测字段清单,让安全团队逐个字段审查。之后,为每一次升级操作编写预检,并请客户在预发布环境中试运行。最后,写一份假设你没有任何访问权限的故障处理手册:客户要运行哪些命令,要把哪些输出发回给你。

让项目拖延一个月的那些错误

最常见的错误是把客户环境当成自己的开发环境。你可能会碰到内部镜像仓库、代理、网络策略和变更审批流程,而这些在厂商文档里从未提及。

其次是把遥测留到以后再做。由于遥测路由由客户控制,等到第一次出故障时再加一个日志字段,可能需要再走一轮安全审查。相反的错误是日志打得太多:只要有一行把文档内容打印到 stdout,就足以打破整份合同赖以成立的“只含元数据”承诺。

最后一个错误是把升级当成一条命令。它其实是一次排好期的工作会话,有前置条件,也有回滚路径。如果没有在预发布环境测试过回滚,你就等于没有回滚路径。

求职时如何证明这项技能

阅读 FDE 招聘启事时,留意“customer environments”“on-prem”“VPC”或“air-gapped”这类字眼。

在简历上,不要写“熟悉 Kubernetes”。可以写这样一行:在客户运维的集群上部署并升级系统,并提供客户运维人员可自行运行的诊断工具。

如果还没有真实项目,一个包含 Helm chart、预检脚本和只含元数据的遥测数据结构的代码仓库,就是面试官五分钟内能看完的证据。

客户的集群永远不会属于你。但只要从第一天起就为“看得见它”而设计,你依然能把工作做好。

这篇文章对你有帮助吗?

8 个信源
路线图上的下一篇 · 阶段 5: 部署上线在 Ema,谁做演示,谁就得把它送上生产环境前线部署构建者一人设计、销售并交付同一个智能体工作流,演示里抄的每条近路,都是日后要自己还的债。