KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
术语工作定义(本课程口径) — keel 龙骨
私有化交付工程:把一套系统送进客户内网 的参考信息:术语工作定义(本课程口径)
只写本课判断要用到的那一层定义,以及经常被搞混的那一侧。
名词的完整来历与衍生概念不在本课范围,本课只在第一次用到时给一句够做判断的定义。
一、这条链路上的角色
| 术语 | 本课口径 | 常见误用 |
|---|---|---|
| 私有化交付 | 把一套系统连同运行它所需的一切送进一个没有外网出口的环境,并让它在那里跑起来、能升级、能回退 | 当成「部署到更远的一台机器」——那个前提(网还在)已经不成立了 |
| 内网隔离 / 无出口 | 那台机器到不了外面。本课的可观察形态是内核直接拒绝:Network is unreachable |
与「网慢」「偶发超时」混为一谈——后两者重试有用,前者重试没有意义 |
| 我们这边 | 有外网的那一侧。构建镜像、打交付包都只发生在这里 | 以为现场也能构建——现场既没有外网,也不该装构建工具链 |
| 现场 / 客户机房 | 只能靠介质接收制品的那一侧。没有我们的人,通常也没有 TTY | 按「有自己人在场」设计脚本(问交互问题、依赖人工判断) |
| 交付包 | 一次安装所需的全部输入 + 完整性证明。最小形态:两个镜像 tar + 编排文件 + 配置模板 + 脚本 + MANIFEST.sha256 |
当成普通压缩包——它里面的东西丢了要回有外网的机器重打 |
二、制品与镜像
| 术语 | 本课口径 | 常见误用 |
|---|---|---|
| 制品 | 交付包里不可再生的那部分,本课就是两个镜像 tar | 把编排文件、脚本也算成制品——它们随时能再生成一份 |
| 镜像 | 一套自足的运行环境 + 应用代码。本课读数是 215MB,其中应用代码 61.4kB | 以为镜像重是因为代码大 |
| 基础镜像 | 被整块继承的那一层,本课是 python:3.12-slim,179MB |
把它算成「我们写的」,于是以为可以靠改代码瘦身 |
| 依赖层 / 代码层 | 分成两层的两个东西:依赖层的输入是 requirements.txt,代码层的输入是源码 |
把 COPY 顺序反了,于是改一行代码就重装依赖 |
| 多阶段构建 | 构建阶段只产出一个 venv,运行阶段把它拷走。本课不重讲语法 | 以为多阶段是为了让镜像小——本课的理由是少一样客户看不懂的东西 |
| 一个镜像,多种角色 | web / worker / migrate / config / doctor 共用一份代码,靠启动命令区分 |
让镜像自带一个默认角色,于是客户以为在跑 worker、其实起来的是 web |
save / load |
把镜像导出成 tar / 从 tar 导回本地 daemon。这是唯一成立的搬运动作 | 用 pull 代替——在没有出口的地方它只会挂到超时 |
| 未压缩 tar | 包内的镜像文件本身。load 吃的是 save 的原样输出,所以压缩只做在外面一层 |
以为解开包不会占磁盘,于是前置检查里省掉磁盘余量判断 |
MANIFEST.sha256 |
每个制品的哈希清单。它管的是「包在搬运途中有没有坏」 | 把它当「装完之后有没有被人改过」的校验——那不是它的职责 |
三、编排与解析
| 术语 | 本课口径 | 常见误用 |
|---|---|---|
| 编排文件 | 现场被直接使用的那一份 compose 文件。它与开发时那份有四处刻意不同 | 把开发用的 compose 打进交付包(里面带 build:) |
| 解析期 | compose 读文件、展开变量、解析依赖的那个阶段。不需要 daemon | 以为配置错要在启动后才暴露——本课的必填项在解析期就死 |
必填变量 ${VAR:?} |
没有默认值、缺了当场失败的变量。本课有 4 个 | 给必填项配一个「看起来合理」的默认值,于是错的东西被安静地带到运行期 |
| 归一化 | 解析输出对值的统一改写,如 60s 变 1m0s、512M 变 536870912 |
用原文串比对判断「这个值有没有被改过」 |
deploy.resources.limits |
Compose 翻译 Swarm 语法的子集。本课里它只出现在运行中的容器上,mem_limit 字段没有 |
只看解析输出得出「没设限」的结论 |
| 一次性进程 | 跑完就退的进程,如 migrate。它的退出码是它唯一的产物 |
给它配 restart——重试会把失败藏起来 |
service_completed_successfully |
下游等上游「成功退出」的条件,migrate 到 web / worker 靠它连着 |
只用「已启动」当条件,于是新代码可能配上旧结构 |
| 拓扑顺序 | 依赖解析后的服务顺序:db → migrate → web → worker |
以为是文件里的书写顺序 |
--pull never |
禁止 compose 去仓库取镜像。离线场景的正确默认,不是可选优化 | 省略它,于是根因被埋在一段超时与一句 failed to resolve reference 后面 |
| 半启动 | 一部分容器起来了、其余没起来,如端口被占时只有 web 没起 | 把它报成「安装失败」——现场状态其实已经变了 |
四、实例与配置
| 术语 | 本课口径 | 常见误用 |
|---|---|---|
| 实例 | 资源名前缀 + 一份配置 + 一份数据。三者缺一,多实例就不成立 | 以为「多写一份 .env」就等于多了一个实例 |
| 实例名 / 资源名前缀 | name: 那一行决定的东西,容器名、网络名、卷名都带它 |
以为它只是个显示用的标签——它撞车就是数据错位 |
| 配置自证 | board config 打印的「变量名 / 当前生效值 / 来源」三列,来源只有 env 与 默认值 |
靠「看配置文件」回答「我改的生效了吗」 |
| 脱敏 | 密钥只留长度与前两位(本课显示 (23 chars)) |
把明文打进自检输出——客户截图发过来就等于外泄 |
| 幂等 | 同一动作跑第二遍不产生额外副作用。本课的第二遍会跳过已有镜像、保持 .env 不动 |
第二遍「顺手」重新生成密钥——已存的数据全部连不上 |
五、停机、迁移与回退
| 术语 | 本课口径 | 常见误用 |
|---|---|---|
停机窗口 stop_grace_period |
SIGTERM 之后等多久才 SIGKILL |
用一个经验数字,而不是与任务最长耗时对齐 |
| 优雅停机 | 收到 SIGTERM 后把手上的活干完再退 |
以为「进程能收到信号」就等于「停得干净」 |
| 孤儿任务 | 状态是 running、但已经没有进程在跑它的任务 |
用 status 当判据去回收——会把正在跑的任务抢回来 |
claimed_at |
被领走的时间戳。判断孤儿用它,而不是 status |
忘了从旧版本升上来的数据这一列是 NULL |
| 迁移 | (版本号, 上行 SQL, 下行 SQL) 三元组。升级与回滚是同一段代码的两个方向 |
把它当成一段只能往前的 SQL |
| 结构版本 | schema_migrations 里记录跑到哪一版 |
用镜像版本号代替它——两者是两件事 |
| 迁移逐条提交 | 每一版各自提交,所以「迁移失败」常常是停在中间而不是什么都没发生 | 以为失败就回到原点 |
| 下行迁移 | 回滚时执行的退结构动作。跑它的镜像必须认识新结构 | 用旧镜像执行 --to N,得到一次退出码 0 的静默空操作 |
切栈 / 切 .env |
把 BOARD_IMAGE 换到新版本并重新起栈 |
先切再迁——顺序反了就没有可退回的位置 |
六、现场可观察面
| 术语 | 本课口径 | 常见误用 |
|---|---|---|
healthz |
只证明「进程还活着」,刻意不碰数据库 | 让它去连库——数据库抖动会把容器拖进反复重启 |
readyz |
证明「我真的能干活」:连得上库 且 结构版本对得上 | 与 healthz 合成一个端点 |
board doctor |
查「这个镜像在当前现场能不能干活」:代码版本 / 工作目录可写 / 结构版本 | 拿它当业务自检——它只报事实与下一步动作 |
internal: true |
网络没有通往宿主机的路由。可观察形态是内核拒绝,不是超时 | 当成「访问会被拦」——它是「没有路」 |
docker compose ls -q |
要实例名的正确开关(ls 不支持 Go 模板格式化) |
用 --format '{{.Name}}' 并丢掉 stderr,得到一个静默的空值 |
| 退出码 = 失败条数 | 自检脚本的约定(0 表示全过) | 只把结论打印在屏幕上,于是没有人知道昨晚那次成没成 |
与相邻课程术语的分界
- 「层」「构建上下文」「容器」这四个概念属于基础概念层的讲义,本课只在下游的后果上使用它们;
- 「探针」「滚动更新」「资源预算」的名词在两处都出现,但本课用的是 compose 这一层的表达
(healthcheck/stop_grace_period/deploy.resources);
K8s 那一层的对应物见《Kubernetes 应用课》——
不要把两套名词互换着用,现场多数只有一个能落地。