尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

direnv 给每个项目自动切环境变量,再没手动 source 过

direnv 给每个项目自动切环境变量,再没手动 source 过 你是否遇到过这样一个情况: 在A项目的终端之中执行相应的命令, 然而所实际使用的却是B项目的数据库连接配置, 直至花费了相当长的时间之后才发现, 自己连接的数据库出现了错误。这种情况是我确实存在, 并且这样的状态并不是仅仅发生了一次。根本原因就在于, 环境变量这一东西是属于全局范围的, 并且是伴随着 shell 进程来运行的。我在同一时间打开了五六个项目, 每个项目所需要的环境变量都是不相同的, 这边项目连接的是测试数据库, 那边项目连接的是开发数据库, 各个项目的 API 密钥也全是各不一样。过去通常的做法是, 在每个项目目录下放置一个 .env 文件, 或者放置一个 env.sh 脚本, 只要进入到该目录里, 做的第一件事就是要去执行一下 ./env.sh 这个操作。但是实际的问题是, 我总是会忘记去做这步操作。从当前这个终端标签页切换到其他页面的时候, 脑子里已经记不住具体要做什么了另外开启一个新的浏览窗口后, 也因为忙碌而忘记了原本的任务当同事邀请我去协助排查某个程序错误时, 我在临时切换目录的过程中, 同样因为环境变动而导致思绪中断并遗忘了待办的事情。就是来彻底根除这个“忘了”的情况的。它怎么工作总结为一句话来讲, 就是当你执行cd命令进入某个目录的时候, 系统会自动地加载对应的那个目录的环境变量信息一旦你使用 cd 命令离开那个特定的空间位置的时候, 相关的那些环境变量就会被自动地卸载掉。它的底层原理是在你的 shell 程序里挂载了一个挂钩机制。当你每次切换工作目录时, 这个挂钩就会自动启动, 去检查当前的路径以及它的所有父级路径下, 是否存在一个 .envrc 文件。如果找到了这个文件存在, 它就会执行该文件的内容, 从而把在文件内部定义好的所有环境变量都加载并注入到当前的 shell 环境中。一旦你离开了这个指定的目录范围, 该机制就会立刻撤销之前注入的那些变量, 让系统状态恢复成原来的情况。在这样一个过程之中, 你本人完全没必要去做任何的操作, 仅仅只需要执行一下cd这个命令, 整个任务就全部处理完毕了。组装和搭配这个事情, 其实也就分成了两步来做:# 装mac / linuxbrew你需要把hook挂接到壳程序中, 并且要把这个操作添加到以点号开头的zshrc文件或者以点号开头的文件的末尾位置。eval $( hook zsh)# bash 的话换成eval $( hook bash)然后在项目目录里面, 写一个 .envrc:# -a/.envrc://:5432/dev-xxxxx.envrc这个东西, 它的本质, 其实就是shell这种脚本类型, 所以它能够去处理的事情, 那就是任何那个shell脚本能够去处理的那些事情。比如, 实现当某个动作触发时, 系统会自动地对该虚拟环境执行激活操作。.venv/bin/# 再一个选择呢就是把已有的那个文件叫做.env的东西给它直接加载进来, 这样的话就不需要去重新编写一遍了。初次执行 cd 命令前往该目录时, 系统可能会阻拦并提示当前路径下的 .envrc 文件尚未获得授权, 从而要求您进行手动确认。这是一个安全机制, 这个机制的作用是为了防止在你把别人的仓库克隆下来的时候有人利用恶意存在的 .envrc 文件来偷偷执行代码。allow当你把环境变量配置文件 .envrc 修改完毕之后, 你还得再多执行一个许可授权的动作, 也就是要重新进行一次 allow 操作。allow .allow 这一步, 是它具有的关键性的安全防护举措。.envrc 这个文件, 它本质上是一种会被系统自动执行的 shell 脚本。试想一下, 如果不法分子把一个带有恶意代码的脚本藏到了仓库里面, 而你只是简单地切入了到该目录底下操作, 那么你就很有可能已经陷入了危险的境地。所以, 系统设定了强制性的规则: 对于每一个 .envrc 文件, 都必须由你本人亲手执行过 allow 这一动作之后, 系统才会去运行该文件的代码部分。而且, 一旦这个文件的具体内容发生了任何变化, 你就需要再次手动确认执行 allow 操作。对于这个安全机制, 大家千万不要觉得它非常麻烦或者繁琐不顾其必要性, 因为这个机制在过去确实挽救过不少关键的情况。在用起来比较顺手之后, 会养成一些习惯。经过了一段时期的运行, 我固化了几个具体的用法。第一点是把.envrc文件提交到版本控制之中, 而.env这个用来存放真正密钥的文件不放进版本控制里面。在我的.envrc文件内通常写入的是配置的结构以及那些非敏感的配置信息。对于敏感的密钥则放置在已经被git忽略了的.env文件中。具体的加载工作是由外部工具来完成的。这样做的好处在于, 当团队成员从代码库中克隆下来这个项目之后, .envrc文件已经是现成的了, 每个人只需要各自去填写属于自己的敏感信息就可以了。另外一点就是, 能够使用它来管理多个版本的开发工具链。因为在.envrc这个配置文件里面是可以修改PATH环境变量的, 这样一来, 我们就能够让某个比较旧的项目自动去使用特定版本的node, 或者是采用特定的PATH路径顺序, 当进入该项目目录的时候会自动进行切换, 而当我们离开该目录时又会自动还原到原来的状态, 这种操作方式比起手动执行nvm use命令要更加省心省力一些。第三点内容是要去协助管理功能层面的运行环境。其内部已经预装配置了一些相关的东西, 比如说像这一块。这是一个名为强.envrc强的小工具, 它的作用非常简单, 只需要在命令行里输入一行指令, 就可以让你的项目去自动使用当前所在的那个目录底下所设置好的虚拟环境。# node 项目自动把 /.bin 加进 PATHnode在此特地给出来一个提醒。它用起来确实是挺方便的, 可是有两处比较麻烦的地方, 我必须要在这里讲一下。首先, 这个功能只会在交互式的那个 Shell 环境里面才起作用, 因为它主要是依靠那个钩子hook来做事的。所以, 大家要是去写一些 CI持续集成脚本, 还有 定时任务那种情况, 或者是其他那种非交互式的脚本程序里头, 它是根本不起作用的。在那些特定的地方, 到底该怎么去传递环境变量, 你就还是得按照原来的规矩老老实实地去做传参操作, 千万不要想当然地认为 .envrc 这个东西是无所不能、放之四海而皆准的万能钥匙。再说第二条, 大家千万别把它当成密钥管理工具来看待。它实际上只是一个起到自动作用的便利工具。真正的密钥管理工作还是应该依托于 vault 来进行。把生产环境下的密钥直接硬编码到 .envrc 文件里面去, 这是一个非常不好的做法。但是, 就关于再也再也不用记住需要手动去做这一件事情来说, 它做得那是干干净净。在把这个东西安装上之后的那种咦我这个变量怎么就不生效了的这种抓狂的时刻, 基本上就从我的生活里面消失了。从今以后, 当我克隆完一个项目之后的第一件事, 就是去看一下有没有那个 .envrc 这个文件存在, 要是没有的话呢, 我就给它专门去建立它一个。这是一个简单的工具, 不过它每天都帮助我解决一些问题, 把这些小问题解决掉以后积累起来就变得很多了。
返回列表