【问题标题】:Why do I need to precompile Rails assets on app servers and not web servers only?为什么我需要在应用服务器而不是 Web 服务器上预编译 Rails 资产?
【发布时间】:2013-05-02 17:19:26
【问题描述】:

我正在将一个简单的 Rails 应用程序部署到这个小型 ubuntu 精确 64 服务器设置:
* 1 个运行 nginx 的网络服务器
* 2 个运行独角兽的应用服务器
* 1 db 服务器运行 postgresql

我的服务器配置了 Puppet,我正在使用 capistrano 推送应用程序。

我的Capfile

load 'deploy'
# Uncomment if you are using Rails' asset pipeline
load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks

deploy.rb 文件超级简单

# Execute "bundle install" after deploy, but only when really needed
require "bundler/capistrano"

# Name of the application in scm (GIT)
set :application, "devops-test-app"
set :repository, "https://github.com/geoffroymontel/devops-test-app.git"
set :scm, :git

set :deploy_to, "/var/www/#{application}"

# server there the web server is running (nginx)
role :web, "172.16.0.2"

# server there the db is running
# This is where Rails migrations will run
role :db, "172.16.0.3", :primary => true

# servers there the app servers are running (unicorn)
role :app, "172.16.0.4", "172.16.0.5"

set :rails_env, :production

# user on the server
set :user, "deployer"
set :use_sudo, false

namespace :deploy do 
  task :start, :roles => :app, :except => { :no_release => true } do
    run "service unicorn_#{application} start"
  end

  task :stop, :roles => :app, :except => { :no_release => true } do
    run "service unicorn_#{application} stop"
  end

  task :restart, :roles => :app, :except => { :no_release => true } do
    run "service unicorn_#{application} restart"
  end

  task :copy_in_database_yml do
    run "cp #{shared_path}/config/database.yml #{latest_release}/config/"
  end

  # Precompile assets
  # I have to precompile the assets on the app servers too, and I don't really know why...
  # namespace :assets do
  #   task :precompile, :roles => [:web, :app], :except => { :no_release => true } do
  #     run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
  #   end
  # end
end

before "deploy:assets:precompile", "deploy:copy_in_database_yml"

如果我不在应用服务器上预编译资产,应用程序将失败。

$ cap ROLES="app" COMMAND="cat /var/www/devops-test-app/current/log/production.log" invoke
  * 2013-05-01 21:43:10 executing `invoke'
  * executing "cat /var/www/devops-test-app/current/log/production.log"
    servers: ["172.16.0.4", "172.16.0.5"]
    [172.16.0.5] executing command
 ** [out :: 172.16.0.5] Connecting to database specified by database.yml
 ** [out :: 172.16.0.5] Connecting to database specified by database.yml
 ** [out :: 172.16.0.5] Started GET "/posts" for 172.16.0.2 at 2013-05-01 19:42:10 +0000
 ** [out :: 172.16.0.5] Processing by PostsController#index as HTML
 ** [out :: 172.16.0.5] Rendered posts/index.html.erb within layouts/application (25.7ms)
 ** [out :: 172.16.0.5] Completed 500 Internal Server Error in 122ms
 ** [out :: 172.16.0.5] 
 ** [out :: 172.16.0.5] ActionView::Template::Error (application.css isn't precompiled):
 ** [out :: 172.16.0.5] 2: <html>
 ** [out :: 172.16.0.5] 3: <head>
 ** [out :: 172.16.0.5] 4:   <title>DevopsTestApp</title>
 ** [out :: 172.16.0.5] 5:   <%= stylesheet_link_tag    "application", :media => "all" %>
 ** [out :: 172.16.0.5] 6:   <%= javascript_include_tag "application" %>
 ** [out :: 172.16.0.5] 7:   <%= csrf_meta_tags %>
 ** [out :: 172.16.0.5] 8: </head>
 ** [out :: 172.16.0.5] app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__677166568443748084_17536100'
 ** [out :: 172.16.0.5] app/controllers/posts_controller.rb:7:in `index'

如果我取消注释deploy.rb 中的注释行,一切都很好。

但是为什么? 我以为您只需要在 Web 服务器上编译资产,而不是在应用服务器上。

请帮我理解为什么:)

谢谢,最好的问候

杰弗里

【问题讨论】:

    标签: ruby-on-rails capistrano asset-pipeline unicorn


    【解决方案1】:

    因为,除其他外,Rails 会生成预编译资产的清单,包括文件名中文件的哈希值,然后在您将资产包含在页面中时使用这些名称。当你说image_url('foo.jpg') 时,Rails 最终会在源代码中生成foo-b48cf0140bea12734db05ebcdb012f1d265bed84.jpg

    Rails 需要知道这些资产使用什么编译名称,所以它必须有清单,所以预编译需要在应用服务器上完成。

    查看public/assets/manifest.yml - 这是 Rails 需要的文件,以便正确提供预编译资产。

    【讨论】:

    • 谢谢!就是这样 !我很惊讶 capistrano 没有为具有角色的服务器预编译资产 :app ?是错误还是功能?
    • 看起来其他人也有同样的问题。见capistrano issues on github
    • 虽然是这样,但这并不是实际编译资产的真正原因。您可以编译一次,然后将清单文件同步到所有相关服务器。
    【解决方案2】:

    这是 Capistrano 中的 known bug

    1) 评论

    load 'deploy/assets'

    在您的 Capfile 上。

    2) 在deploy.rb 文件的顶部添加以下行:

    set :assets_role, [:web, :app]
    load 'deploy/assets'

    就是这样!

    【讨论】:

    • 我收到错误“无法加载此类文件 -- 部署/资产”
    【解决方案3】:

    确保您已将 Nginx 配置为在不访问应用程序服务器的情况下提供静态文件。这很可能没有配置,因此资产存在,但 Nginx 没有为它们提供服务并且正在回退到应用程序。

    【讨论】:

    • 感谢您的帮助。我查了一下,Nginx 实际上是在为这些资产提供服务。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多