Capistrano和环境变量

61
我已经开始使用环境变量进行配置,这很好用,但是在部署或者运行capistrano任务时会出现问题。
Capistrano 3似乎会在每个命令前加上/usr/bin/env,这会删除我通过.bashrc设置的任何环境变量。 编辑 - 经过更多研究,这可能不是问题所在。问题可能是因为capistrano作为非登录、非交互式shell执行,并且不加载.bashrc.bash_profile。还是卡住了。
如何确保在capistrano执行任务时设置环境变量是最好的方法?
5个回答

68

您可能需要查看"环境变量"和"Shell变量"之间的区别

当您启动SSH时,应用程序将会加载在.bashrc文件中定义的SHELL变量。这些变量仅在shell的生命周期内存在,因此我们使用它们的情况不如使用"ENV"变量多。

最好将"ENV"变量放在以下位置:

/etc/environment

像这样:

export ENVIRONMENT_VAR=value

这将使变量在整个系统中可用,而不仅仅是在不同的shell会话中。


更新

你尝试过吗?

Capistrano:我可以为整个cap会话设置环境变量吗?

set :default_env, { 
  'env_var1' => 'value1',
  'env_var2' => 'value2'
}

1
我需要为单个用户设置变量,但这些变量需要在运行的进程中可用。我已经在.bashrc文件中添加了“export FOO=BAR”,并且在SSH中可以正常工作。但在Capistrano中却不行。 - Rahul Sekhar
你的环境变量在 /etc/environment 还是 .bashrc 中? - Richard Peck
.bashrc文件中,我需要这些环境变量仅适用于一个用户。 - Rahul Sekhar
5
啊,看起来Capistrano3使用的是default_env而不是default_environment(https://github.com/capistrano/capistrano/pull/564)。这似乎可行。虽然不是最理想的解决方案,但对我来说可以工作 :) - Rahul Sekhar
1
我认为我们不需要在/etc/environment中添加export - Hassan Akram
显示剩余9条评论

62
尽管这个问题已经被解答,但我会将它保留在这里,以防其他人遇到与我相同的情况。
Capistrano确实可以加载.bashrc。但是如果你看一下文件顶部,会有这样一行注释:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return

解决方案就是把任何设置放在这个之上,Capistrano 就可以按照我想要的方式工作。

这个解决方案也被记录在 这个 GitHub 问题 中。


2
运行得很顺利,比上面的解决方案不那么复杂。 - rolebi
这对我的Rails 4.2应用程序和Capistrano3有所帮助。Rails正在寻找诸如数据库密码和secret_key_base这样的事物,这些事物需要通过ENV变量设置...我已经将它们添加到了我的bashrc文件的末尾...但是那些并没有绑定,因此在部署结束时一切都崩溃了。 - Steven Chanin
这个帮了我很多,之前花了好几个小时才找到正确的解决方案。非常感谢! - Alexander
谢谢!我已经将所有客户配置移动到了.bashrc文件的顶部。 - Abdullah Aden

30
为了调试问题,请在config/deploy.rb中添加一个简单的任务:
namespace :debug do
  desc 'Print ENV variables'
  task :env do
    on roles(:app), in: :sequence, wait: 5 do
      execute :printenv
    end
  end
end

现在运行cap staging debug:env。您应该能够看到ENV变量的有效配置。

文件的顺序和名称取决于您的发行版,例如,在Ubuntu上,源代码序列如下:

  1. /etc/environment
  2. /etc/default/locale
  3. /etc/bash.bashrc
  4. ~/.bashrc

~/.bashrc包含以下首行代码时,之后的任何代码都不会被源码:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

为了理解capistrano如何加载ENV变量,这张图表(source)可能会有所帮助。
很可能由于非交互式会话,~/.bash*文件未被加载。

capistrano env variables loading


2
你需要在 /etc/environment 文件中设置环境变量,以使它们对系统中的所有用户和进程可用。在 .bashrc.bash_profile 文件中设置的环境变量仅在 shell 会话中可用,而自动产生的进程和服务则不行。
我之前制作了一个 Capistrano 库 (capistrano-env_config),用于管理和同步群集中的环境变量,它通过修改 /etc/environment 文件实现。该库易于使用,类似于如何使用 Heroku 工具包设置环境变量。这里是一些示例:
cap env:list
cap env:get[VARIABLE_NAME, VARIABLE_NAME, ...] 
cap env:unset[VARIABLE_NAME, VARIABLE_NAME, ...] 
cap env:set[VARIABLE_NAME=VALUE, VARIABLE_NAME=VALUE, ...] 
cap env:sync

0
我采用的解决方案是:
  1. 在需要部署到的所有服务器的/etc/ssh/sshd_config中启用PermitUserEnvironment选项。
  2. 为每个用户的家目录添加一个~/.ssh/environment文件,并以KEY=VALUE对的形式添加环境变量(我通过其自身用户将每个应用程序和服务部署到该用户的主目录)。

参考: http://en.wikibooks.org/wiki/OpenSSH/Client_Configuration_Files#.7E.2F.ssh.2Fenvironment

实际上,情况比这更糟。我使用Upstart来管理Puma/Rails,并且还需要在那里设置env vars。因此,在经过多天的实验后,我最终采取了以下完整但可怕的解决方案:

1. 使用"export KEY=VALUE"在用户的.bashrc中设置我的环境变量。(这样当我进行交互式SSH时,它们就存在了。) 2. 使用"KEY=VALUE"在用户的.ssh/environment文件中设置我的环境变量。(这样当Capistrano SSH时,它们就存在了。) 3. 在/etc/init/puma.conf的"script"部分中设置我的环境变量。(这样当Puma/Rails启动时,它们就存在了。)
维护多个文件/模板和多种格式(带有导出,不带导出等)中相同的环境变量列表真是一件讨厌的事情...幸运的是,使用Puppet在使用Capistrano部署之前管理节点配置可以让这变得稍微容易/更可靠...
我真的很讨厌Linux Shell、初始化和点文件的整个领域。是时候进行完全重启了。

“他们说只需使用环境变量!”但是将它们放在三个地方真的很麻烦!如果唯一的原因是为了防止将机密信息放入源代码控制文件中,为什么不将它们添加到不在源代码控制中的配置文件中呢? - ryan2johnson9
1
我已经放弃了之前为该项目构建的一切,并开始使用全新且更好的技术:Docker、Thin、Sinatra、Sequel和etcd。目前正在开发一个工具,用于将生产密钥存储/检索到etcd中。不再使用Rails、Puppet、Capistrano、SSH、环境变量和所有其他笨重的垃圾。我甚至还没有完成,但已经感受到了天壤之别。 - odigity
  1. 在 /etc/init/puma.conf 的 "script" 部分设置我的环境变量。(这样当 Puma/Rails 启动时它们就存在了。)- 这对我很有帮助!非常感谢!
- Disha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接