本节摘要:环境管理的目标只有一个:让「在我机器上是好的」这句话失效。本节讲开发、集成、生产三套环境的隔离清单——目标区域、连接凭据、物化参数各自怎么隔离——以及三边必须严格一致的部分:代码、依赖图、测试定义。最后给一套轻量级的环境命名与切换约定,两个环境起步,长了再拆。
单人项目、数据仅供自己分析,一套环境确实够——这正是 1.3 节方案判断框架的延伸。但只要出现第二个消费者(同事的报表、业务的看板),第二套环境就该立起来:开发者在自己的环境里随便试、随便重建,业务看的表纹丝不动。团队再扩大、接入持续集成后,第三套(持续集成的验证环境)也随之出现。
三套环境的分工:
环境的实现机制在 dbt 里非常轻:代码只有一份,环境差异全部落在两处配置——目标区域(同一套模型,在开发环境建到开发者的个人模式里,在生产建到正式模式里)与连接凭据(各环境各自的仓库地址与账号)。dbt 的目标(target)机制就是为此设计的:一份连接配置文件里写多个目标,命令行或环境变量指定用哪个。
目标仓库区域。 三套环境各写各的区域(不同数据库、不同模式或不同项目,取决于仓库形态)。区域隔离的深层价值不只是「互不干扰」,而是权限可以分级:开发者的账号在生产区域只读甚至无权,写权限只在开发区域——物理上杜绝了「开发者直接改生产表」。6.3 节的访问控制会沿这条线继续展开。
连接凭据。 每套环境一套凭据,且凭据不进版本库——用环境变量在部署时注入,本地开发用本机的私密配置。凭据进库是数据团队最常见的安全事故(1.2 节已提过),这里给出工程上的根治法:代码仓库里只放凭据的「占位模板」,真实值由部署系统注入。做到这一步,密钥泄漏面从「整个仓库的所有历史提交」缩到「部署系统一处」。
物化与环境参数。 同一个模型,开发环境用视图(快、省资源),生产环境用表或增量(业务要求)——这类按环境分叉的配置用变量注入实现(4.1 节的宏与变量分工):配置默认值写生产,开发与集成环境启动时覆盖。注意分叉的是参数而不是逻辑——逻辑分叉会让「验证通过的代码」与「上线运行的代码」根本不是同一份,环境一致性就崩了。
环境之间,下面三样东西必须严格同源,任何一边私改都是自毁:
抽象讲完,看一眼具体形态。连接配置文件里,多个目标并列,每个目标声明仓库类型、目标区域与该环境的凭据引用:
连接配置结构(示意) - 目标 dev: 仓库类型:某云仓库 目标模式:analytics_dev_{用户名} # 每人一个个人模式 凭据:从本机环境变量读取 - 目标 prod: 仓库类型:某云仓库 目标模式:analytics # 正式模式 凭据:从部署系统的密钥管理读取 角色:只读分析 + 部署专用写入
日常使用的体验是「换目标即换环境」:开发时指定 dev 目标,验证时切 prod 目标——代码零改动,区域与凭据整体切换。这个体验正是「隔离靠配置、不靠改代码」的直接兑现。
一个值得养成的习惯:每次在本地切到生产目标做验证后,立刻切回开发目标。本地连着生产写操作的事故,几乎都发生在「切了目标忘了切回」之后——开发默认目标设为 dev、生产目标只在明确需要时显式指定,用默认值的惯性对冲健忘。
背景:某团队的集成环境为省资源,只同步了生产两周内的数据。一次口径变更(新增了「近九十天复购」字段)在集成环境全绿通过——九十天窗口里两周数据足够测试跑通。上线当晚,生产构建在计算九十天复购时扫描了完整历史,跑了四十分钟,把凌晨调度窗口挤爆,下游三张表没跑完,早报延迟两小时。
定位与处置:表面原因是「集成数据不全」,根因是环境间存在一个未被记录的行为差异(历史数据深度),且没有人在变更评审时评估过它的影响。处置分三步:应急上,当晚手动补跑剩余下游,早报改为上午十点发布并提前告知业务方;机制上,把「集成环境数据深度」写进环境说明文档,并在上线检查单里加一条「涉及窗口期或历史扫描的变更,需按生产数据量评估耗时」;工程上,该口径改用增量预聚合(4.3 节的手法)把生产耗时从四十分钟压回五分钟。
这个案例的启示:环境一致性检查单里,最容易被忽略的恰恰是「数据本身的一致性」——代码一致、测试一致还不够,数据的量级与形态差异同样是环境差异。凡是要扫历史、按窗口算的逻辑,评审时都该问一句:集成环境的数据够验证它吗?
⚠️ 常见坑:「我在生产修了一下配置,忘了同步回代码库。」这种改动当场有效、无人知晓,下次流水线一发布就被冲掉,数字突变,全场排查。根因是生产环境出现了绕过代码的变更通道。规矩只有一条:生产上发生的任何变更,要么来自流水线,要么事后立刻补进代码库——补的过程走评审,等于给应急操作补了一次复盘。
两个环境的起步方案足够用很久:生产环境用固定的正式模式名;开发环境用「开发前缀加开发者标识」的个人模式名,dbt 会在编译期把目标模式名拼进表的全名,切换环境就是切换一个目标参数。团队扩大后再把集成环境独立出来,模式命名规则不变。
给一套可以直接抄的约定:开发者的每次功能开发在独立分支上进行,分支对应开发环境的一个目标;合并请求触发集成环境的流水线;合并后主干自动部署生产。三个环境各司其职,命名规则从第一天起就不需要改——这也是环境设计的评价标准:规则的一次性。环境方案如果每加一个人就要重定一次,说明它在靠人肉维持,而不是靠机制。
要,但别靠自觉。个人模式里的模型与数据是纯中间产物,放着不管有两个代价:存储费用按月累加,以及「僵尸表」干扰排查——新人看到别人个人模式里的一张旧表,分不清是参考实现还是废弃实验。轻量做法是一个月度清理任务:列出三十天没有构建记录的个人模式,通知本人后批量清除。规则讲清楚之后没有任何悲剧:模型代码在版本库里,重建只是几分钟的事;真正回不来的只有「当时为什么建它」的记忆,而这正是通知期要保住的东西。清理任务本身也用 dbt 的清单命令加一段脚本实现,写完进版本库——它自己也不该是绕过代码的存在。
环境立住了,代码怎么从分支走到生产?下一节把持续集成与部署的流水线搭起来。