I have rails 4.1 app and multistage (staging, production) deployment with capistrano3.
I want to deploy it to one stage server (which use rvm) and one production server (which use ruby env)
By default everything works nice on production server, but without rvm1-capistrnao3 gem installed and included in Capefile I cannot deploy to staging.
Is there a way to require 'rvm1/capistrano3' in Capefile, only if I deploy to staging like that
cap staging deploy
Here is what I've done to fix it
I made default capistrano multistage setup, like Doug Hall said!
The tricky part is the way to include rvm1-capistrano3 in Capefile
See deepak's workaround here https://github.com/capistrano/rvm/issues/49
So instead of just require 'rvm1/capistrano3' in Capefile, do it like that
task :use_rvm do
require 'rvm1/capistrano3'
end
task 'staging' => [:use_rvm]
When you run cap install, it creates a file called config/deploy.rb and two files in the config/deploy directory: production.rb and staging.rb. Use the config/deploy.rb file for all settings that both the production and staging servers have in common. Use the other two for the respective settings on those machines. I would require 'capistrano/rvm' in your Capfile, but only use it in the config/deploy/staging.rb file. Capistrano executes the common config/deploy.rb FIRST, then calls the proper staging.rb/production.rb file, so all set values from config/deploy.rb are available in the staging.rb/production.rb file.
Related
what's the differences between these two tasks, why i need to add RAILS_ENV=production when cap deploy?
thanks!
You need to specify RAILS_ENV=production environment variable so that your config/environments/production.rb configuration file is used when precompiling assets. It usually contains production configuration for assets pipeline:
config.assets.js_compressor = :uglifier
config.assets.digest = true
If you omit RAILS_ENV=production then development configuration will be used (config/environments/development.rb).
The first one will precompile your assets on your local dev box (development environment) and the other will precompile your assets on your production environment. Your settings in your config files are most likely different and so it will go of what is configured off what is in the environment config for whatever you set RAILS_ENV to.
Was going to write as a comment but too long...
--
Production vs Local
Something you also need to consider with this, is if you're precompiling for the production environment, it essentially compiles & configures your files for that environment
Simply, this means if you have any special conditions / dependencies for production only, using RAILS_ENV=production will use these over your local setup. This is why you'll have this setup in your Gemfile:
#Gemfile
group :production do
gem 'xxxx'
end
--
SHELL VARIABLES
Something else you need to appreciate is RAILS_ENV is a SHELL VARIABLE. This means that whenever you run a shell session (I.E load cmd), these variables can be set to provide specific functionality.
In relation to RAILS_ENV, it means you'll be able to tell Rails to run in production mode for the time being; as opposed to running in development, testing or staging modes
In my vhost, I have:
<Directory /var/www/prod/myapp/myapp/public>
...
RailsEnv production
...
</Directory>
and while any code dependent on it being production is correctly running there in the app itself (ex: display the Google Analytics code if Rails.env.production?), when I run rake about from /var/www/prod/myapp/myapp, I get:
Application root /var/www/prod/myapp/myapp
Environment development
Database adapter mysql2
which means that I have to prefix any deployment related rake stuff with RAILS_ENV=production. Granted, it's all in a deployment script at this point so it doesn't matter much, but why isn't Rake aware that it's production? Shouldn't the Passenger setting be enough? And if not, how do I fix it so I won't need to specify the environment manually?
Side-note: I am running the development instance of the app on the same box, with Environment set to development in its corresponding vhost configuration.
EDIT: Phusion Passenger version 4.0.20
rake is entirely unaware of passenger's configuration. It doesn't even know that you're using passenger. Since it isn't launched by passenger, it would have to (assuming it knew you were using apache/passenger) parse the apache config files to find this out, which would get pretty complicated, especially in the presence of multiple apps.
You could set this in one of your shell's startup files, however that doesn't sound like a good idea if you have multiple environments on the same machine.
You could stick
ENV['RAILS_ENV']='production'
At the top of one of Rails' startup files - boot.rb seems to do the trick. This would make passenger's setting ineffective though, and obviously you would only want to do this on the production deploy of your script.
Personally (especially on a machine with multiple environments in action) I'd stick to typing RAILS_ENV=production.
but why isn't Rake aware that it's production?
Because rake and all rails related commands internally do this
ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development"
which means that if you didnt have RAILS_ENV or RACK_ENV environment, then it will use development environment by default.
Shouldn't the Passenger setting be enough?
NO. Passenger setting is just for making your app up/live in desire or say virtual environment. It doesn't change any system configuration.
And if not, how do I fix it so I won't need to specify the environment manually?
That's very easy. Just set environment variable. If you are using bash (normally people do) you can simple do this
echo "export RAILS_ENV=production" >> ~/.bashrc ; source ~/.bashrc
This will make your server as rails production server, so if you run rails c or rake db:migrate etc or any rails or rake command it will run in production server for all available applications.
I am running the development instance of the app on the same box, with Environment set to development in its corresponding vhost configuration.
This is a problem. If you set the above environment variable, then whenever you run any code like rake db:migrate inside this app ..that will run in production environment. To avoid this either you dont set environment variable or specify environment on every command. There is one hack available . Include this line at the top of config/boot.rb
ENV["RACK_ENV"] = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development"
Future reading : How can I make a custom environment in rails a default environment?
what's the differences between these two tasks, why i need to add RAILS_ENV=production when cap deploy?
thanks!
You need to specify RAILS_ENV=production environment variable so that your config/environments/production.rb configuration file is used when precompiling assets. It usually contains production configuration for assets pipeline:
config.assets.js_compressor = :uglifier
config.assets.digest = true
If you omit RAILS_ENV=production then development configuration will be used (config/environments/development.rb).
The first one will precompile your assets on your local dev box (development environment) and the other will precompile your assets on your production environment. Your settings in your config files are most likely different and so it will go of what is configured off what is in the environment config for whatever you set RAILS_ENV to.
Was going to write as a comment but too long...
--
Production vs Local
Something you also need to consider with this, is if you're precompiling for the production environment, it essentially compiles & configures your files for that environment
Simply, this means if you have any special conditions / dependencies for production only, using RAILS_ENV=production will use these over your local setup. This is why you'll have this setup in your Gemfile:
#Gemfile
group :production do
gem 'xxxx'
end
--
SHELL VARIABLES
Something else you need to appreciate is RAILS_ENV is a SHELL VARIABLE. This means that whenever you run a shell session (I.E load cmd), these variables can be set to provide specific functionality.
In relation to RAILS_ENV, it means you'll be able to tell Rails to run in production mode for the time being; as opposed to running in development, testing or staging modes
I have two files on the server, one in each environment's shared directory, named rvmrc. This contains rvm use ree-1.8.7-2012.02#appname-production --create for production and rvm use ree-1.8.7-2012.02#appname-staging --create for staging. This should allow the app to run under its own gemset, because I've built in a task to the deploy script to link the corresponding shared/rvmrc file into the app as .rvmrc. That task is displayed below, in my deploy.rb example.
I still need to get bundler to use the correct gemset during the deploy, though. I thought I could do this by using set :rvm_ruby_string, "ree-1.8.7-2012.02#appname-#{rails_env}" to dynamically set the rvm_ruby_string to the environment's gemset. However, I find that my deploys only use the production gemset - even when doing cap staging deploy.
See this question for more information on my thought process for even trying this (and to chime in if you think it's just a bad idea).
What do I need to change to get my deploys to use the correct gemset based on the environment?
In my deploy file, the relevant lines that I have (I've stripped out quite a bit) are:
require 'rvm/capistrano'
require 'capistrano/ext/multistage'
require 'bundler/capistrano'
set :stages, %w(staging production)
set :default_stage, "staging"
set :rvm_ruby_string, "ree-1.8.7-2012.02#appname-#{rails_env}"
set :rvm_type, :system
set :bundle_without, [:development]
namespace :deploy do
task :rvmrc do
run "rm #{latest_release}/.rvmrc; ln -s #{shared_path}/rvmrc #{latest_release}/.rvmrc"
end
end
before "bundle:install", "deploy:rvmrc"
In my production.rb file, the relevant lines that I have (I've stripped out quite a bit) are:
set :branch, "master"
set :rails_env, "production"
In my staging.rb file, the relevant lines that I have (I've stripped out quite a bit) are:
set :branch, "staging"
set :rails_env, "staging"
You can set the ruby version and gemset when you launch the application. I.e. use rvm wrappers as it is described for the use with God in the link. No .rvmrc symbolic link juggling needed that way.
I.e., if you're using Unicorn, create a wrapper:
rvm use ree-1.8.7-2012.02#appname-production
rvm wrapper ree-1.8.7-2012.02#appname-production ree187prod unicorn
That gives you ~.rvm/bin/ree187prod_unicorn. Use it instead of unicorn in your start script. Unicorn will then use the correct ruby version and gemset.
First off let me say this is the first time I've deployed out a rails application so I'm pretty new to this. I have my production environment running successfully now and deployed it using Capistrano, but the deploy failed the first time due to missing gems. To get around it I basically cloned my repo on the server, ran
bundle install
This successfully installed the gems and Capistrano deployed successfully the next time around.
So with that in mind, is there a correct way to get new gems to install on each deploy?
My environment is Ubuntu Server, Apache2, Passenger, Rails.
Thanks!
We have the following in our deploy.rb
require 'bundler/capistrano'
load 'deploy/assets'
before 'deploy', 'rvm:install_rvm'
ssh_options[:forward_agent] = true
set :rvm_ruby_string, ENV['GEM_HOME'].gsub(/.*\//,"") # Read from local system
require 'rvm/capistrano'
set :rvm_ruby_string, '1.9.3-p194'
...
Works like a treat for us although usually on a new build we'll have to install a few gems on the server directly.
Adding this to the top of your config/deploy.rb file will make Capistrano execute bundle install.
require "bundler/capistrano"