In my Gemfile I specify what branch to use on a git repository based on RAILS_ENV. However when Capistrano deploys, it runs the bundle install command - and since it's run through a shell, the proper environment (staging) isn't set. It defaults to development and gives me an error stating that there's a mismatch between Gemfile.lock and what is installed.
You are trying to install in deployment mode after changing your
Gemfile. Run bundle install elsewhere and add the updated
Gemfile.lock to version control.
You have added to the Gemfile:
* source: git#bitbucket.org:MyRepository/manager-engine.git (at develop)
You have deleted from the Gemfile:
* source: git#bitbucket.org:MyRepository/manager-engine.git (at master)
You have changed in the Gemfile:
* manager from git#bitbucket.org:MyRepository/manager-engine.git (at develop) to no specified source
Gemfile:
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
gem 'manager', git: "git#bitbucket.org:MyRepository/manager-engine.git", branch: "#{ [:production, :staging].include?(RAILS_ENV.to_sym) ? :master : :develop }"
i.e., use the 'develop' branch if the rails environment is anything other than 'production' or 'staging'.
deploy/staging.rb:
set :branch, :master
set :keep_releases, 2
set :stage, :staging
set :rails_env, 'staging'
set :bundle_without, [:development, :test]
set :deploy_to, '/home/useraccount/rails_deployments/staging.www'
server 'localhost', user: 'useraccount', roles: %w{web app db}
So to be the most concise:
In regular SSH terminal, to install the repository gem under the proper environment, I have to issue RAILS_ENV=staging bundle install. Otherwise, just running bundle install installs the repository from the develop branch. Since Capistrano just runs bundle install and doesn't include the RAILS_ENV, this problem is occurring. But doesn't Capistrano set :rails_env, or is that not a real system environment variable?
I guess if there's no better way...
I ended up using a method illustrated somewhere else in SO and modified it for my needs.
Modify Gemfile to contain:
# Read environment from A) Explicit set through command, B) Existence of override file's contents or C) Default to development
RAILS_ENV = ENV['RAILS_ENV'] || `cat .rails-env`.to_s.split.first || 'development'
If .rails-env contains nothing or doesn't exist, it defaults to development. Otherwise it takes the first word as the environment. To create the file from the command line, just type echo "your-environment-name-here" > .rails-env, assuming you're in the app's root directory.
You can also create the file upon every deploy with capistrano using the command above, or just create a symlink to the file and share it between deployments:
Deploy.rb:
set :linked_files, %w{ .rails-env }
So now the environment can be forced via a file in the root of your app called .rails-env. Explicit RAILS_ENV calls such as RAILS_ENV=test bundle exec ... will still work as advertised.
Related
I have a Rails 4 app that connects to a second, external database. So I added the database credentials to my database.yml file and excluded it from version control in git. I need to deploy it when I push to Heroku using Capistrano.
I found some questions raised for this task, but they don't work for me and they were answered prior to the release of Capistrano 3.
I set up capistrano by adding:
group :development, :test do
gem 'capistrano-rails', '~> 1.1.1'
end
and
running bundle install then bundle exec cap install as it says in the install instructions.
I created a new folder in my app and copied the database.yml file there: myApp/shared/config/database.yml (not sure if this was necessary)
Finally, I created the following task in deply.rb:
after "deploy:update_code","deploy:config_symlink"
namespace :deploy do
task :config_symlink do
run "cp #{shared_path}/shared/config/database.yml #{release_path}/config/database.yml"
end
end
This didn't work and threw an error when pushed to Heroku:
/app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.2.1/lib/active_record/connection_adapters/connection_specification.rb:248:in `resolve_symbol_connection': 'pg_development' database is not configured. Available: ["production"] (ActiveRecord::AdapterNotSpecified)
I tried putting this task in the production.rb file as well as adding set :linked_files, %w{config/database.yml} to the development.rb file.
Can someone help me get the database.yml file into production on Heroku?
So I'm deploying to a Ubuntu droplet hosted on DigitalOcean a Rails 4 application running on Apache and Phusion Passenger. After deployment I've been getting 500s as a result of Rails production not finding the secret_key_base token for production. However, if I run an echo $SECRET_KEY_BASE it returns the rake secret generated by my deploy.rb.
The deploy.rb task to set that up is:
namespace :deploy do
task :start do ; end
task :stop do ; end
desc "Setup ENV variables"
task :env_vars do
on "root#xxx.xxx.xxx.xx" do
execute "export SECRET_KEY_BASE=#{`bundle exec rake secret`}"
end
end
end
before "deploy", "deploy:env_vars"
However, Rails is still not picking it up. I even ssh'd into my server and in rails console checked and ENV["SECRET_KEY_BASE"] returns the correct secret token.
I thought using Capistrano's :default_env would work, but that only seems to set up environmental variables for the deploy task, but not actually on the server. Is there any easy way to solve this solution? My fallback is to just place the secret within secrets.yml since the repo is private, but I rather not do that.
There is a gem for exactly this task:
https://github.com/capistrano-plugins/capistrano-secrets-yml
Install
Add this to Gemfile:
group :development do
gem 'capistrano', '~> 3.2.1'
gem 'capistrano-secrets-yml', '~> 1.0.0'
end
And then:
$ bundle install
Setup and usage
make sure your local config/secrets.yml is not git tracked. It should be on the disk, but gitignored.
populate production secrets in local config/secrets.yml:
production:
secret_key_base: d6ced...
add to Capfile:
require 'capistrano/secrets_yml'
create secrets.yml file on the remote server by executing this task:
$ bundle exec cap production setup
You can now proceed with other deployment tasks.
You can create a file in your server called application.yml in shared/config.
Choose any one of solution from bellow
Following code in deploy.rb will automatically symlink your application.yml
set :linked_files, %w{config/application.yml}
Or
Then symlink this application.yml with your current/config/application.yml with a simple capistrano task.
Rather than exporting env variables in deploy.rb, use dotenv to load environment variables from .env[.<staging>] into ENV when rails booting.
Follow these steps:
Add this line to the top of your Gemfile:
gem 'dotenv-rails'
Put .env.production file into the linked_file in deploy/production.rb:
set :linked_files, fetch(:linked_files, []).push('.env.production')
On the remote host, add the .env.production file in shared folder which contains this line:
SECRET_KEY_BASE=<Your secret>
Give up on environment vars and just simply read a file. Do this in secrets.yml.
production:
secret_key_base: <%= File.read('/home/me/SECRET_KEY_BASE').strip %>
Then make the secret file.
$ rake secret > ~/SECRET_KEY_BASE
Before settling on this solution I tried exporting the secret from my .bash_profile, .profile, and .bashrc (top and bottom). I also tried PermitUserEnvironment and .ssh/environment. I have no idea how an environment variable gets from "the environment" into a capistrano deployment. I ran ssh example.com printenv and saw my vars. I logged in and saw my vars. But puma started with capistrano... it always has it's own environment.
Capistrano raises the error "ERROR: Gem bundler is not installed, run gem install bundler first."
But when I clone the project to /tmp/project of the targe server bundle runs (as root) smoothly.
The server is a Ubuntu 12.04.2 LTS, ruby was installed via rvm.
I added "source /usr/local/rvm/scripts/rvm" to the /root/.bashrc but it did not solve the problem.
require "bundler/capistrano"
set :application, 'myproject'
set :repository, "git#myproject.git"
set :branch, 'staging'
set :user, 'root'
set :domain, "mydomain"
set :deploy_to, "/var/webapps/#{application}"
role :web, domain # Your HTTP server, Apache/etc
role :app, domain # This may be the same as your `Web` server
role :db, domain, :primary => true # This is where Rails migrations will run
role :db, domain
default_run_options[:pty] = true
# [and then the tasks]
TIA.
EDIT
This very same deploy script worked in another server, with ruby installed in the same way. The only difference I remember is that that server was a CentOS.
Also tried rvm wrapper rvm current bundle bundle as suggested here
Edit 2
I compared the env command via ssh and via capistrano. The following env variables were missing when env was issued by capistrano:
__array_start=0
_first=0
_second=1
escape_flag=1
GEM_HOME=/usr/local/rvm/gems/ruby-1.9.3-p392
GEM_PATH=/usr/local/rvm/gems/ruby-1.9.3-p392:/usr/local/rvm/gems/ruby-1.9.3-p392#global
IRBRC=/usr/local/rvm/rubies/ruby-1.9.3-p392/.irbrc
LC_ADDRESS=pt_BR.UTF-8
LC_IDENTIFICATION=pt_BR.UTF-8
LC_MEASUREMENT=pt_BR.UTF-8
LC_MONETARY=pt_BR.UTF-8
LC_NAME=pt_BR.UTF-8
LC_NUMERIC=pt_BR.UTF-8
LC_PAPER=pt_BR.UTF-8
LC_TELEPHONE=pt_BR.UTF-8
LC_TIME=pt_BR.UTF-8
LESSCLOSE=/usr/bin/lesspipe %s %s
LESSOPEN=| /usr/bin/lesspipe %s
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
MY_RUBY_HOME=/usr/local/rvm/rubies/ruby-1.9.3-p392
RUBY_VERSION=ruby-1.9.3-p392
rvm_bin_path=/usr/local/rvm/bin
rvm_debug_clr=
rvm_error_clr=
rvm_notify_clr=
rvm_path=/usr/local/rvm
rvm_prefix=/usr/local
rvm_reset_clr=
rvm_version=1.19.5 (stable)
rvm_warn_clr=
The following env vars were different:
_=/usr/bin/env # ssh
_=/bin/sh # capistrano
LANG=en_US.UTF-8 # ssh
LANG=C # capistrano
LANGUAGE=en # ssh
LANGUAGE=C # capistrano
# ssh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/rvm/bin
# capistrano
PATH=/usr/local/rvm/gems/ruby-1.9.3-p392/bin:/usr/local/rvm/gems/ruby-1.9.3-p392#global/bin:/usr/local/rvm/rubies/ruby-1.9.3-p392/bin:/usr/local/rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
I had a similar problem with one of my setups, though I use rbenv to manage ruby versions. The issue was that bundler was not installed on the Ruby version my project was pointing to.
I did a quick check online and you have a few options:
run rvm gemset use global && gem install bundler (installs to
global version)
edit your /.bashrc ... something along those lines
([[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm")
Running gem env may show you that you are forcing a path, and you would then need to remove the entry from ~/.gemrc or /etc/gemrc
My 2-cents
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"