很早就大致了解cloud_foundry有自己的ruby,而不是使用系统提供的ruby。并且还有两个版本的ruby,今天终于遇到了,大致搞清楚了。
他们在哪里
首先我们要知道cloud_foundry把自己的ruby,gem装到哪里去了,这个可以去看config目录下面的deployment_info.conf文件。里面包含了一个ruby_bin_dir变量。这个路径就是ruby所在,在本机上面是:/root/cloudfoundry/.deployments/devbox/deploy/rubies/ruby-1.9.2-p180/bin。
ruby下面有什么
在bin目录下面可以看到许多已近安装的软件,包括gem、rails、rack、bundle等。

这里的软件才是cf真正使用到的。
有个办法可以验证,我们在终端中直接输入:gem list --local查看安装的gem包,会发现gem非常少,bundle之类的根本没有。如果使用这个gem,那么vcap::common之类的模块也无法使用。
而如果跑到这个路径下面执行这里的gem,那么就可以看到所需要的结果了。
cf是怎么使用这里的软件的
既然知道了cf确实是使用这个位置下面的ruby的,那么到底在哪里做了这个相应的操作呢?
我们来看vcap_dev文件,在dev_setup/bin目录里面的。我在
http://blog.youkuaiyun.com/cherry_sun/article/details/7730008里面分析过,我们start的时候是通过
exec_cmd("#{ruby_binary} #{vcap_launch} #{command} #{vcap_components["components"].join(" ")} -c #{deployment_config_path} -v #{vcap_path} -l #{deployment_info["deployment_log_path"]}")
这句话来执行start的,那么这里的ruby_binary其实就是我们上面提到的ruby的绝对路径。有兴趣可以去看下代码。归根到底,这个ruby的路径还是从前面提到的deployment_info.conf文件中取得的。而这个文件其实是vcap_dev_setup在安装的时候写入的。
cf的gem和bundle如何发生作用的
我们知道要让ruby项目取得依赖,我们可以利用gem和bundle来实现。使用bundle install来安装相应的gem包,然后在项目当中写下:
require "rubygems"
require "bundler/setup"
两行代码(可以看bundler官网:
http://gembundler.com/)
第一步
在cf当中,第一步bundle install是在安装时完成的,现在采用chef了,就是在chef的cookbook中定义的。我在
http://blog.youkuaiyun.com/cherry_sun/article/details/7730008中已经有提到了,可以参看最后一部分,cloud controller的recipe分析,其中的
cf_bundle_install就是在做bundle install。当然,这个bundle也是使用了cf自己的bunlder:File.join(node[:ruby][:path], "bin", "bundle")
第二步
然后就是两个require了,这里有两个实现方式。
首先是最简单的,看dea/lib/dea/dea.rb最开头,就有两句:
require 'rubygems'
require 'bundler/setup'
第二种要看vcap/cloud_controller/config/boot.rb文件了,这个文件的最前面有:
require 'rubygems'
require 'erb'
begin
require 'fiber'
rescue LoadError
$stderr.puts "CloudController requires a Ruby implementation that supports Fibers"
exit 1
end
# Set up gems listed in the Gemfile.
gemfile = File.expand_path('../../Gemfile', __FILE__)
begin
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
rescue Bundler::GemNotFound => e
STDERR.puts e.message
STDERR.puts "Try running `bundle install`."
exit!
end if File.exist?(gemfile)
想必应该可以看懂了,就是在把bundle和gem加载进来。这个boot.rb被health manager调用到了,我们可以看health_manager.rb文件最前面的部分:
def self.setup
$:.unshift(lib_dir.to_s) unless $:.include?(lib_dir.to_s)
require root.join('config', 'boot')
require 'active_record'
require 'active_support/core_ext'
require 'yajl'
require 'eventmachine'
require 'nats/client'
require 'vcap/common'
require 'vcap/component'
require 'vcap/logging'
require 'vcap/rolling_metric'
require 'vcap/priority_queue'
也是一目了然,把上面提到的boot.rb require进去了。