【问题标题】:How to link chef with capistrano for deployment如何将厨师与 capistrano 联系起来进行部署
【发布时间】:2013-03-12 13:29:16
【问题描述】:

我已经配置了 chef 环境,并且可以使用 capistrano 部署我的应用程序。现在我想让我的 chef 处理 capistrano 来部署我的应用程序。怎么办?

【问题讨论】:

    标签: deployment capistrano chef-infra recipe


    【解决方案1】:

    我做相反的事情,即。通过 Capistrano 部署我的厨师食谱。我推荐它。

    #config/deploy.rb
    ...
    before 'bundle:install', "provision:default", "deploy:config_db_yml_symlink"
    ...
    

    这将在安装包之前执行服务器的主厨配置,这很重要,因为很多 gem 依赖于安装到操作系统的包。

    #config/deploy/provision.rb
    Capistrano::Configuration.instance(:must_exist).load do
      namespace :provision do
        task :default do
          provision.setup
          provision.web
          provision.db
          provision.db_slave
        end
    
        task :setup, once: true do
          provision.get_environment_variables
          provision.update_cookbooks
        end
    
        task :db, :roles => :db do
          next if find_servers_for_task(current_task).empty?
          if rails_env == 'staging'
            run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j db.json -l debug}
          else
            run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j db_master.json -l debug}
          end
        end
    
        task :db_slave, :roles => :db_slave do
          next if find_servers_for_task(current_task).empty?
          run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j db_slave.json -l debug}
        end
    
        task :web, :roles => :web do
          next if find_servers_for_task(current_task).empty?
          run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j web.json -l debug}
        end
    
        task :get_environment_variables do
          run "if [ -d ~/.config ]; then " +
            "cd ~/.config && git fetch && git reset origin/master --hard; " +
            "else git clone git@github.com:mycompany/config.git .config; fi"
          run "sudo cp ~/.config/secureshare/#{rails_env}/environment /etc/environment"
        end
    
        task :update_cookbooks do
          run "if [ -d /u/chef ]; then " +
            "cd /u/chef && git fetch && git reset origin/master --hard; " +
            "else git clone git@github.com:mycompany/chef.git /u/chef; fi"
        end
      end
    
      namespace :deploy do
        task :setup, :except => { :no_release => true } do
          dirs = [deploy_to, releases_path, shared_path]
          dirs += shared_children.map { |d| File.join(shared_path, d.split('/').last) }
          dirs += [File.join(shared_path, 'sockets')]
          run "#{try_sudo} mkdir -p #{dirs.join(' ')}"
          run "#{try_sudo} chmod g+w #{dirs.join(' ')}" if fetch(:group_writable, true)
          run "#{try_sudo} chown -R ubuntu:ubuntu #{dirs.join(' ')}" if fetch(:group_writable, true)
        end
    
        task :config_db_yml_symlink do
          run "ln -s #{shared_path}/database.yml #{release_path}/config/database.yml"
        end
      end
    end
    

    我的项目中有一个名为 provision 的文件夹,用于处理厨师角色的定义,尽管食谱位于不同的存储库中。

    #provision/solo.rb
    root = File.absolute_path(File.dirname(__FILE__))
    cookbook_path '/u/chef'
    role_path root + "/roles"
    log_level :debug
    log_location STDOUT
    

    节点在项目中定义

    #provision/db_slave.json
    {
      "run_list": ["role[db_slave]"]
    }
    

    和角色

    #provision/roles/db_slave.rb
    name "db_slave"
    description 'A postgresql slave.'
    run_list(["recipe[base]", "recipe[postgresql::slave]", "recipe[rails]","recipe[papertrail]", "recipe[fail2ban]"])
    override_attributes(
      'kernel' => {
      'shmmax' => ENV['KERNEL_SHMMAX'],
      'shmall' => ENV['KERNEL_SHMALL'],
      'msgmax' => ENV['KERNEL_MSGMAX'],
      'msgmnb' => ENV['KERNEL_MSGMNB']  
    },
    'postgresql' => {
      'user'     => ENV['PG_USER'],
      'password' => ENV['PG_PASSWORD'],
      'database' => ENV['PG_DATABASE'],
      'master_host' => ENV['PG_HOST']
    },
    'app_dir' => ENV['APP_DIR'],
    'papertrail' => {
      'port' => ENV['PAPERTRAIL_PORT'],
      'log_files' => [
        "#{ENV['APP_DIR']}/shared/log/*.log",
        "/var/log/*.log",
        "/var/log/syslog",
        "/var/log/upstart/*.log",
        "/var/log/postgresql/*.log"
      ]
    },
    'new_relic' => {
      'key' => ENV['NEW_RELIC_LICENSE_KEY']
    })
    

    所有这些都不会在应用程序中保留任何敏感信息。我还使用 capistrano-ec2group 将服务器映射到使用 EC2 安全组的角色。

    group :myapp_web, :web
    group :myapp_web, :app
    group :myapp_db, :db, :primary=>true
    group :myapp_db_slave, :db_slave
    

    因此,基本上您将厨师食谱保存在一个存储库中,将环境变量保存在另一个存储库中,并将您的应用程序保存在另一个存储库中 - 并使用 Capistrano 来配置服务器和部署您的应用程序。

    您也可以将您的厨师食谱保存在您的应用程序存储库中,但这会抑制项目之间的重用。关键是将所有更改的内容放入环境变量中,并将它们分别存储到应用程序和配方中。

    如果配置正确,要添加新服务器,您只需在 EC2 中启动一个,应用所需的安全组,然后

    cap deploy
    

    【讨论】:

      【解决方案2】:

      您可以观看关于 Application Deployment 的 Foodfightshow 剧集。

      你可以例如使用 Chef 将配置文件(例如数据库凭据)放入服务器,同时使用 Capistrano 推送源代码。

      【讨论】:

        【解决方案3】:

        你不能。或者至少不会很简单。

        Chef 是一个拉取系统——客户端从 Chef 服务器拉取信息,并对其采取行动。

        Capistrano 是一个推送系统——你告诉它登录到服务器并在那里执行任务。

        我认为您集成它们的唯一方法是在每台机器上本地运行 Capistrano,但我看不到这样做的原因。

        Chef 的部署资源可能无需集成 Capistrano 即可满足您的所有需求。如果您仍想独立于 Chef-client 运行将部署推送到服务器,最好不要通过 Chef 部署并保留当前系统。

        如果您想要持续交付,请将 Capistrano 脚本连接到 CI 服务器并在管道结束时运行它们。

        @StephenKing 提到的播客是有关此事的重要信息来源。

        【讨论】:

          猜你喜欢
          • 2011-10-15
          • 2017-01-20
          • 1970-01-01
          • 1970-01-01
          • 2011-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-10
          相关资源
          最近更新 更多