Cloud Foundry vcap_dev start過程分析

我們會通過bin/vcap_dev start命令來啓動所有的cf組件,當然,也可以指定某些組件,比如bin/vcap_dev start health_manager。

下面大致研究下流程。

1. vcap_dev文件

首先是vcap_dev文件,前面主要處理了命令參數以及路徑等問題。最後可以看到

exec_cmd("#{ruby_binary} #{vcap_launch} #{command} #{vcap_components["components"].join(" ")} -c #{deployment_config_path} -v #{vcap_path} -l #{deployment_info["deployment_log_path"]}")

exec_cmd意思就是執行cmd,而ruby_binary是ruby,vcap_launch就是和vcap_dev同位置的vcap文件,後面的command就是我們的啓動指令start,當然可能是stop,restart之類的。

2. vcap文件

所以我們就可以跑去vcap文件看個究竟了。

因爲本文研究start,所以直接看vcap文件的start函數:

  def start
    if !running?

      pid = fork do
        # Capture STDOUT when no log file is configured
        if !log_file?
          stdout = File.open(log_file, 'a')
          stdout.truncate(0)
          STDOUT.reopen(stdout)
          stderr = File.open(log_file, 'a')
          STDERR.reopen(stderr)
        end
        # Make sure db is setup, this is slow and we should make it faster, but
        # should help for now.
        if is_cloud_controller?
          cc_dir = File.expand_path(File.join(DIR, '..', 'cloud_controller'))
          Dir.chdir(cc_dir) { `bundle exec rake db:migrate` }
        end
        exec("#{component_start_path}")
      end

      Process.detach(pid)

      start = Time.now
      while ((Time.now - start) < 20)
        break if running?
        sleep (0.25)
      end
    end

    status

    if !running?
      if File.exists?(log_file)
        log = File.read(log_file)
        STDERR.puts "LOG:\n #{log}" if !log.empty?
      end
    end
  end
其他的不理會,重點語句是exec("#{component_start_path}"),當然cc還需要做一個db migrate。那麼我們看component_start_path,這也是個函數。這個函數所做的事情就是跑去vcap的相應目錄下面,然後執行bin目錄下的同名文件。以health manager爲例,它執行vcap/bin/health_manager文件,同時以-c傳入.deployment/devbox/config下面的health_manager.yml文件。那麼vcap_dev start任務就交接完成了,接下來由bin下面的腳本執行了。

這裏的vcap路徑下有bin目錄,而vcap/health manager下面也有bin,vcap腳本調用的是vcap下的bin。之前搞錯了。那麼看health manager的bin腳本:

exec(File.expand_path("../../health_manager/bin/health_manager", __FILE__), *ARGV)

他就直接調用vcap/health_manager/bin/health_manager腳本了

3. bin腳本

然後我們看看bin下面的腳本都在做什麼:

home = File.join(File.dirname(__FILE__), '/..')
ENV['BUNDLE_GEMFILE'] = "#{home}/Gemfile"
require File.join(home, 'lib/health_manager')
很簡單,就是設置了bundle gemfile的環境變量,然後指向lib下的health_manager文件。Lib下的health_manager.rb主要有三個部分,第一個部分是module CloudController,用來添加非常多的依賴(require),目前不清楚這麼做的意義。第二部分是HealthManager類,那就不提了。重要的是第三部分,也就是文檔末尾的一些代碼:

if $0 == __FILE__ || File.expand_path($0) == File.expand_path(File.join(File.dirname(__FILE__), '../bin/health_manager'))

  config_path = ENV["CLOUD_FOUNDRY_CONFIG_PATH"] || File.join(File.dirname(__FILE__), '../config')
  config_file = File.join(config_path, "health_manager.yml")
  options = OptionParser.new do |opts|
    opts.banner = 'Usage: healthmanager [OPTIONS]'
    opts.on("-c", "--config [ARG]", "Configuration File") do |opt|
      config_file = opt
    end
    opts.on("-h", "--help", "Help") do
      puts opts
      exit
    end
  end
  options.parse!(ARGV.dup)

  begin
    config = YAML.load_file(config_file)
  rescue => e
    $stderr.puts "Could not read configuration file:  #{e}"
    exit 1
  end

  EM.epoll

  EM.run { HealthManager.start(config) }
end

首先去讀config file,然後解析了options參數,我們知道bin腳本已經傳入了-c參數,所以在options解析中,config會覆蓋掉。在讀取config之後,就使用Event Machine啓動HealthManager了。EM.epoll是一個linux下的調用命令,對我們沒有意義。EM.run就是我們要看的,可以看到這裏只調用了HealthManager.start函數。後面就不再深入了,大致的流程就是完成配置,然後開啓NATS,訂閱NATS事件,然後發送NATS消息。

總結一下:vcap_dev和vcap腳本都用來處理安裝之後的啓動停止等任務,他們會調用vcap/bin目錄下對應的腳本,而這些腳本又會去相應組件的目錄下執行更爲詳細的任務

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章