如果你想要在开发和生产模式下,高效的管理你的应用,那么你就需要理解什么是环境变量。现在越来越多的Ruby工程师开始使用环境变量,但是可能有些人没有真正的理解它是怎么工作的。这么文章将会告诉你,环境变量是如何工作的,在什么情况下不能使用环境变量,并且还会介绍,如何在Rails应用中使用几个最常用的管理环境变量的方法。
每个进程都拥有一组自己的环境变量
运行在服务器上的每一个程序,至少运行于一个进程之上。并且这些进程持有自己的一组环境变量,其他进程不可以访问。
可以理解的错误,初学者通常认为环境变量是服务器范围内使用的。就像系统服务配置文件一样。
进程和它的环境变量的生命周期是一样的
环境变量是生命周期是和它所在的进程是一样的,也就是说,当你的应用的进程退出,重启,那么原先的环境变量就都会消失。
你可以通过在IRB 中设置环境变量来查看这个特性:
当进程退出的时候,环境变量也随之消失了。
这就是为什么你的环境变量在你重启服务或者退出shell的时候,消失的原因。如果你想要环境变量有效的话,你就需要将它们存储在想.bashrc这样的配置文件当中。
子进程可以从父进程中继承环境变量
每一个应用进程都会有一个父进程,这是因为每个程序都是在其他程序中触发启动的。
如果你使用bash shell 打开 vim ,那么vim的父进程就是这个shell。如果你的Rails应用是用了imagemagick去识别图片,那么识别程序的父进程就是你的Rails应用。
子进程从父进程中继承环境变量。
在下面的例子中,我在IRB中设置了 环境变量$MARCO的值,然后执行输出shell中环境变量的值。
那么IRB就是我们创建的shell的父进程,然后它获得了$MARCO环境变量的拷贝。
父进程可以定制环境变量给子进程
默认情况下,父进程会拷贝一份环境变量到子进程中,不过它还可以,从命令行你可以使用env命令,或者设置环境变量的特殊语法去设置传递给子进程的环境变量。
子进程不可以修改它的父进程的环境变量
上面已经提到了,子进程只是获得了父进程的环境变量的拷贝而不是引用,所以通过下面的例子我们可以看到,修改子进程的环境变量的值,相应在父进程中没有变化。
环境变量的改变不会同步到其他进程中
环境变量是存储在进程空间的,也就是表明,运行相同程序的两个进程的环境变量的变化不会相互影响。
环境变量与shell变量是不同的
环境变量和本地变量经常被搞混,shell为自己提供了一个 本地的变量系统,在语法上shell变量和环境变量的用法是一样的,但是shell变量不会被拷贝到子进程中去。
下面是一个例子,首页使用在命令行中设置了一个本地变量(shell变量)的值,然后通过Ruby命令访问环境变量哈希中与之同名的变量,结果返回是找不到的,然后再使用export 对本地变量进行转换后它就可以在环境变量中被访问了。
管理环境变量实践
假设我们有两个Rails 应用同时运行在同一个服务器上,然后这两个应用又同样需要访问第三方的API_KEY ,我们可以将这个第三方API_KEY存放在环境变量中。但是如何为他们设置不同的值呢。
看完上面的介绍,想必你也知道了,环境变量与服务器上的两个Rails应用一样是运行在不同的进程当中的,所以它们是独立的,可以被分别设置,那现在剩下的问题就是如何设置这个环境变量的值了。
Figaro
当你安装完Figaro到Rails应用之后,在config/application.yml中的键值对,都将会在应用启动的时候被加载进ruby的ENV中。
安装gem:
# Gemfile
gem "figaro"
然后添加键值对到 application.yml。注意一定要将这个文件添加到.gitignore中以防止重要的信息被提交到代码仓库中。
# config/application.yml
API_KEY: 12345
Dotenv
dotenv 与Figaro非常的相似,除了它是从.env文件中加载的环境变量,而不是YAML中。
安装:
# Gemfile
gem "dotenv"
然后添加配置信息到.env文件中,与上面一样,.env文件也要加到到.gitignore中。
# .env
API_KEY=12345
在Rails中就可以使用ENV哈希访问它了。
ENV['API_KEY']
你还可以像下面这样,在shell中运行命令加载预定于的环境变量:
dotenv ./my_script.sh
Secrets.yml?
抱歉虽然Secrets.yml很酷,但他并不会设置环境变量,所以它其实不是Figoaro和dotev这样的Gem的替代方案。