Ruby rbenv system wide install (support for multi-user usecase)

ruohanc · December 21, 2013 · Last by ruohanc replied at September 07, 2014 · 6070 hits
Topic has been selected as the excellent topic by the admin.

起因

@luikore 吕大神的帖子 [姨妈] 终于把 rvm 换成 rbenv 了, 讨论 rbenv 比之 rvm 不足的地方,我列了这么四点

  • rvm 傻瓜的帮你处理一些库依赖 (特别是在 osx 下系统 readline 和 brew 安装的 GNU readline 傻傻分不清楚的时候)
  • rvm 良好的处理了多用户服务器环境下的管理
  • 它官方有提供 offline 安装的方法,对我来说很重要,我有很多机器都不能上外网 (生产环境安全要求严格).
  • 有一个 binary 功能,可以让我自己打包一个适应本地环境的 ruby, 避免在每个服务器上编译 (未验证)

今天来尝试用 rbenv 解决上述问题

整理下需求:

  1. 目标环境:是 linux 下的 production 运行环境,满足多用户共同使用的需求
  2. 库依赖:只专注于解决第一个问题,跨平台的库依赖问题不予解决 (比如不同系统使用不同的包管理,不同的包名等问题)
  3. 离线安装:能够完全只依赖有限的网络条件 offline 安装 (基本解决)
  4. 多用户支持:使用 linux 组权限解决 rbenv 的 none root 用户使用问题 (比如安装新 ruby, 切换默认 ruby, 全局性的安装&删除 gem)

最后的结果

多用户支持

通过 linux 的组权限解决,不完美,有点小问题。

问题在 umask 的设置上,系统默认是 umask 022 即组权限默认抹去 写权限. 在类似的场景下可能会出现 permission deny: 用户 A 在 gem 的默认位置上安装了 gem A, 但是用户 B 想把它删掉

解决这个问题的根本办法是请在 production 环境里面使用 bundle install --deployment 谢谢!

离线安装支持

这部分没有写在脚本里,按照两步走:

  1. 离线安装 rbenv 和 ruby-install: 简单,打个 tar 包就好了
  2. 离线安装 ruby: 简单,建立一个 $RBENV_PREFIX/cache 文件夹,然后把 ruby 源代码放进去就好了

参考资料:Package download caching

部署运行方式

linux 的安全性问题就不赘言了,总之你需要用一个独立的帐号来运行你的 rails app, 那么你应该这么做

折腾个什么劲啊,用 capistrano-rbenv 呗

安装脚本参考

GIST 在此

PREFIX="/usr/local"
RBENV_PREFIX="$PREFIX/rbenv"
BIN_PATH="$PREFIX/bin"
RBENV_GROUP="rbenv"

umask 002

## Install rbenv, ruby-build and rbenv-gem-rehash
git clone git://github.com/sstephenson/rbenv.git $RBENV_PREFIX

mkdir $RBENV_PREFIX/plugins
git clone git://github.com/sstephenson/ruby-build.git $RBENV_PREFIX/plugins/ruby-build
git clone git://github.com/sstephenson/rbenv-gem-rehash.git $RBENV_PREFIX/plugins/rbenv-gem-rehash

## add rbenv script to PATH
ln -s $RBENV_PREFIX/bin/rbenv $BIN_PATH/rbenv

## Add rbenv to the System wide profile:
## @note profiles only will be sourced in `login shell`,
##       see the difference here(Chinese): https://gist.github.com/yegle/1564928
cat <<EOF > /etc/profile.d/rbenv.sh
# rbenv setup
export RBENV_ROOT=${RBENV_PREFIX}
eval "\$(rbenv init -)"
EOF

chmod +x /etc/profile.d/rbenv.sh
source /etc/profile.d/rbenv.sh

## set rbenv group property
groupadd $RBENV_GROUP
chown -R :rbenv $RBENV_PREFIX
find $RBENV_PREFIX -type d -exec chmod g+Xs {} \;

## Install Ruby
#rbenv install 1.9.3-p484
#rbenv install 2.0.0-p353
#rbenv global 2.0.0-p353

## Rehash:
#rbenv rehash

2013-12-28 Update: chef 线上部署参考方案

经过线上验证,rbenv + ruby 完全可以通过 tar 包的方式快速部署到每一个服务器上(每个环境打一次包,用上面提供的脚本就行),我这里有一个 chef 的配置给大家参考:

多行 echo redirect 用 heredoc 更简单哦

<<EOF > /etc/profile.d/rbenv.sh
  # rbenv setup
  export RBENV_ROOT=${RBENV_PREFIX}
  eval "\$(rbenv init -)"
EOF

rbenv 应该尽量安装到用户下。

#2 楼 @alvin2ye 这是给 SA 部署方式的讨论啦,你单机开发么千万别搞这么麻烦。

@ruohanc 可以加上

$ RUBY_CONFIGURE_OPTS="--with-readline-dir=`brew --prefix readline`"
rbenv install 2.0.0-p195

这样在 pry 或 irb 里才可以输入非 ASCII 字符

#5 楼 @zealinux 嗯..解决方案总是有的,但是找到这个解决方案的过程并不愉悦。我的意思是如果你用 rvm, 完全不用受这个罪..

#1 楼 @luikore 被你忽悠了,还以为真可以像你这样写,像下面这样才行噻

cat <<EOF > /etc/profile.d/rbenv.sh
# rbenv setup
export RBENV_ROOT=${RBENV_PREFIX}
eval "\$(rbenv init -)"
EOF

我正在做部署测试,回头再报告下结果。

#7 楼 @ruohanc 哦,原来只有 zsh 才能这么写...

#9 楼 @fsword #10 楼 @luikore

走过,路过,不要错过。。。 😄

@huacnlee 新的部署方式!内网可以直接用我打好的包喔,gist 里面写的 IP 是内网可用的 IP 喔。

标题容易让人误会,简单的说发布就可以了

#14 楼 @iambowen 唔。。没发现误会的点呀~ 就是说一个系统级别的安装方式而已。

看到这个帖子,前段时间也研究了下, https://github.com/cao7113/rbenv-pluger

17 Floor has deleted
18 Floor has deleted
19 Floor has deleted

#7 楼 @ruohanc 老大,你不能挖坑啊,

ruby-build 不是放到 plugins 就可以直接用吧,我在 14.04 下要安装的 ./install.sh,人家最开始的代码就挺好的啊:

# Install ruby-build:
pushd /tmp
  git clone git://github.com/sstephenson/ruby-build.git
  cd ruby-build
  ./install.sh
popd

另外 ## Install Ruby 之前要装依赖的:

apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6 libreadline6-dev zlib1g zlib1g-dev

你的 bash 里面没有 PATH 相关的内容,装完了不能用啊

Installed ruby-2.1.2 to /home/xxxxx/.rbenv/versions/2.1.2

还得加上:

echo 'export PATH="/home/xxxxx/.rbenv/versions/2.1.2/bin:$PATH"' >> /etc/profile.d/rbenv.sh

#20 楼 @Peter rbenv init - 你运行下这个看看,是包括了 PATH 的。然后你的 PATH 是错的,应该用 .rbenv/shims

装依赖跟你的系统相关,我这里没有 cover ruby 的编译安装,所以当然也没说

#20 楼 @Peter btw...这个方法我已经线上稳定运行一年了.. 你先自己看看吧。

#21 楼 @ruohanc 谢谢回复,我的确掉另一个坑里了,这个 bash 要用 root 身份运行,我用的 sudo 提权,导致 source 这类命令不会被执行。

#22 楼 @ruohanc 建议把:

ln -s $RBENV_PREFIX/bin/rbenv $BIN_PATH/rbenv
cat <<EOF > /etc/profile.d/rbenv.sh
# rbenv setup
export RBENV_ROOT=${RBENV_PREFIX}
eval "\$(rbenv init -)"
EOF

换成:

cat <<EOF > /etc/profile.d/rbenv.sh
# rbenv setup
export RBENV_ROOT=${RBENV_PREFIX}
export PATH=${RBENV_ROOT}/bin:${PATH}
eval "\$(rbenv init -)"
EOF

或者换成:

ln -s $RBENV_PREFIX/bin/rbenv $BIN_PATH/rbenv
cat <<EOF > /etc/profile.d/rbenv.sh
# rbenv setup
eval "\$(rbenv init -)"
EOF

如果你都 ln -s 了,那下面这句就没有任何意义了:

export RBENV_ROOT=${RBENV_PREFIX}

#24 楼 @Peter 你可以试试看。成功了告诉我,反正写着也没事,不纠结这个。

不过我怀疑不写会有问题,比如你看这里 https://github.com/sstephenson/rbenv/blob/13a474c4e9c3305179b364723349fc49b3e935e3/libexec/rbenv#L39

if [ -z "${RBENV_ROOT}" ]; then
  RBENV_ROOT="${HOME}/.rbenv"
else
  RBENV_ROOT="${RBENV_ROOT%/}"
fi
export RBENV_ROOT
You need to Sign in before reply, if you don't have an account, please Sign up first.