Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Deploy API only Rails App with Capistrano
Truemark Technology profile imagePrabin Poudel
Prabin Poudel forTruemark Technology

Posted on • Edited on • Originally published atprabinpoudel.com.np

     

Deploy API only Rails App with Capistrano

Capistrano is a deployment automation tool built on Ruby, Rake, and SSH. It allows you to deploy your app to a remote server in a single command after initial configurations are done.

Deployment with capistrano is as easy ascap production deploy. But to be able to hit this command, a lot of configurations need to be added first.

Today we will be looking into setting up capistrano in our API only Rails application for making it easier to deploy to any remote server.

Skills required to follow the tutorial

Intermediate:

  • Rails
  • Linux skills to work with commands in server where your app has been deployed

You should have

  • Existing Rails app
  • Linux server already setup to run Rails app

NOTE:
I am using rbenv for ruby so all configurations will be based on that, you can replace it as required for your version manager as required e.g. for rvm.

Step 1: Install Capistrano Gems

Add the following to your Gemfile under development group

group:developmentdogem"capistrano"gem"capistrano-rails"gem'capistrano-rbenv'end
Enter fullscreen modeExit fullscreen mode

Run the following from command line:

$ bundle install
Enter fullscreen modeExit fullscreen mode

That should install the latest version of capistrano gems, now let's lock those versions by looking at Gemfile.lock, these versions were what I had in my lock file, yours could be different.

group:developmentdogem"capistrano","~> 3.17",require:falsegem"capistrano-rails","~> 1.6",require:falsegem'capistrano-rbenv','~> 2.2',require:falseend
Enter fullscreen modeExit fullscreen mode

Step 2: Generate default configuration files

Run the generator to create a basic set of configuration files:

$ bundle exec cap install
Enter fullscreen modeExit fullscreen mode

Step 3: Require correct plugins in Capfile

Uncomment the following plugins in Capfile located at the root of the project

# require "capistrano/rvm"require'capistrano/rbenv'# require "capistrano/chruby"require'capistrano/bundler'require"capistrano/rails/assets"require'capistrano/rails/migrations'# require 'capistrano/passenger'
Enter fullscreen modeExit fullscreen mode

Step 4: Update Deploy file

Update the deploy file atconfig/deploy.rb with values as required:

  1. application: Set to the application name or project name
  2. repo_url: Set to the URL where your code is being stored, you can normally get this withgit remote -v and copy the URL of origin
  3. linked_files: Set to a list of files that should be shared and persisted over all releases, for e.g. config/database.yml, config/master.key, config/application.yml, etc. These files will not be deleted/reset in every release (other files will!!)
  4. linked_dirs: Set to a list of folders that should be shared and persisted over all releases, for e.g. log, tmp/pids, node_modules, etc. These folders will not be deleted/reset in every release (other folders will!!)
  5. keep_releases: Set to a number of previous releases you want to keep in the server after each release, I normally keep this to 3.
  6. conditionally_migrate: Skip migration if files in "db/migrate" were not modified. I normally set this to "true" but default is "false"

Your deploy file could look something like below:

# frozen_string_literal: true# config valid for current version and patch releases of Capistranolock'~> 3.17.0'set:application,'contract-template-editor-api'set:repo_url,'git@github.com:truemark/contract-template-editor/api.git'# Default value for :linked_files is []set:linked_files,%w[config/application.yml config/database.yml config/master.key]# Default value for linked_dirs is []set:linked_dirs,%w[log tmp/pids tmp/cache tmp/sockets vendor/bundle .bundle public/system public/uploads node_modules]# Default value for keep_releases is 5set:keep_releases,3# Skip migration if files in db/migrate were not modified# Defaults to falseset:conditionally_migrate,true
Enter fullscreen modeExit fullscreen mode

Step 5: Update environment specific deploy files

I have normally worked on projects that has staging and production environment and configuration files for these two environment is provided default by Capistrano; each environment specific file is located underconfig/deploy/{environment}.rb.

In these files, there should be configurations that can change based on the environment of the Rails application.

Configurations for each environment will be the same with different value based on the environment e.g. server ip address will be different in production and staging.

We will only be looking atconfig/deploy/production.rb in this tutorial.

Update the deploy file atconfig/deploy/production.rb with values as required:

  1. server: IP address of the server where you will deploy the app. It is a good idea to sore this value inside env file or rails credentials and take it from there.
  2. user: name of the user in the server, normally it will be "deploy" but could be username e.g. prabin
  3. roles: list of accessible roles for this user
  4. deploy_to: path of the folder to deploy your app to, you can get the path by logging in to the server, going to the folder you want your app to be deployed to and enter the commandpwd. If you haven't created the folder yet, you can create one e.g. contract-template-api and set the path of that folder.
  5. branch: git branch that will be used to deploy the app, normally "main" or "master"
  6. stage: environment of the app, should be "production"
  7. rails_env: same as stage, should be "production"

Your file could look something like below:

serverENV['deploy_server_ip'],user:'deploy',roles:%w[app db web],primary:'true'set:deploy_to,'path to the folder where app should be deployed e.g. /home/deploy/contract-template-editor/api'set:branch,'main'set:stage,:productionset:rails_env,:production
Enter fullscreen modeExit fullscreen mode

Step 6: Upload secret keys and files

Secret keys and files should never be committed to git. These files are required for app to function properly. Normally these files are always configured in the developer's machine so they can be uploaded directly from the project to the server using ssh.

Create a new rake task atlib/capistrano/tasks/config_files.rake and add the following content:

namespace:config_filesdodesc'Upload yml files inside config folder'task:uploaddoonroles(:app)doexecute"mkdir -p#{shared_path}/config"upload!StringIO.new(File.read('config/database.yml')),"#{shared_path}/config/database.yml"upload!StringIO.new(File.read('config/application.yml')),"#{shared_path}/config/application.yml"upload!StringIO.new(File.read('config/master.key')),"#{shared_path}/config/master.key"endendend
Enter fullscreen modeExit fullscreen mode

We now need to tell capistrano to run this code during deployment, add the following to the end ofconfig/deploy.rb

# ================================================# ============ From Custom Rake Tasks ============# ================================================# ===== See Inside: lib/capistrano/tasks =========# ================================================# upload configuration filesbefore'deploy:starting','config_files:upload'
Enter fullscreen modeExit fullscreen mode

Step 7: Create a database if deploying for the first time

Create a new rake task atlib/capistrano/tasks/database.rake and add the following content:

namespace:databasedodesc'Create the database'task:createdoonroles(:app)dowithinrelease_pathdowithrails_env:fetch(:rails_env)doexecute:rake,'db:create'endendendendend
Enter fullscreen modeExit fullscreen mode

We now need to tell capistrano to run this code during deployment, add the following to the end of the deploy file.

# set this to false after deploying for the first timeset:initial,true# run only if app is being deployed for the very first time, should update "set :initial, true" above to run thisbefore'deploy:migrate','database:create'iffetch(:initial)
Enter fullscreen modeExit fullscreen mode

Step 8: Reload the Rails application after successful deploy

Create a new rake task atlib/capistrano/tasks/application.rake and add the following content:

namespace:applicationdodesc'Reload application'task:reloaddodesc'Reload app after deployment'onroles(:app),in: :sequence,wait:5doexecute:touch,release_path.join('tmp/restart.txt')endendend
Enter fullscreen modeExit fullscreen mode

We now need to tell capistrano to run this code during deployment, add the following to the end of the deploy file.

# reload application after successful deployafter'deploy:publishing','application:reload'
Enter fullscreen modeExit fullscreen mode

Final file

Your final "config/deploy.rb" file should look similar to this:

# frozen_string_literal: true# config valid for current version and patch releases of Capistranolock'~> 3.17.0'set:application,'{project name}'set:repo_url,'{remote git repository where project for the code is stored}'# Default value for :linked_files is []append:linked_files,%w[config/application.yml config/database.yml config/master.key]# Default value for linked_dirs is []append:linked_dirs,%w[log tmp/pids tmp/cache tmp/sockets vendor/bundle .bundle public/system public/uploads node_modules]# Default value for keep_releases is 5set:keep_releases,3# Skip migration if files in db/migrate were not modified# Defaults to falseset:conditionally_migrate,true# ================================================# ============ From Custom Rake Tasks ============# ================================================# ===== See Inside: lib/capistrano/tasks =========# ================================================# upload configuration filesbefore'deploy:starting','config_files:upload'set:initial,true# run only if app is being deployed for the very first time, should update "set :initial, true" above to run thisbefore'deploy:migrate','database:create'iffetch(:initial)# reload application after successful deployafter'deploy:publishing','application:reload'
Enter fullscreen modeExit fullscreen mode

Deploy the app

From the command line you can now deploy the app to production using the following command:

cap production deploy
Enter fullscreen modeExit fullscreen mode

The app should be deployed in around 5-10 minutes, if you encounter any error while deploying and need any help, please post a comment below and I will do my best to help you resolve it.

Bonus 1: Whenever for cron jobs

whenever gem is used in Rails applications to schedule cron jobs e.g. send email notification about monthly expenditure on the 1st of each month.

Add the following to the deploy file just below "set :conditionally_migrate, true":

# Skip migration if files in db/migrate were not modified# Defaults to falseset:conditionally_migrate,true# Set unique identifier for background jobsset:whenever_identifier,->{"#{fetch(:application)}_#{fetch(:stage)}"}
Enter fullscreen modeExit fullscreen mode

whenever_identifier should be set to unique identifier for cron jobs, this is required if you have deployed multiple applications to same server (normally for staging servers) that require whenever gem so that those applications don't clash with one another for cron jobs. This is optional if you only have one application in the server.

Create a new rake task atlib/capistrano/tasks/whenever.rake and add the following content which will be responsible for updating cron tasks configured inside the "config/schedule.rb":

namespace:wheneverdodesc'Update cron job'task:update_crontabdoonroles(:app)dowithincurrent_pathdoexecute:bundle,:exec,"whenever --update-crontab#{fetch:whenever_identifier} --set 'environment=#{fetch(:stage)}'"endendendend
Enter fullscreen modeExit fullscreen mode

We now need to tell capistrano to run this code during deployment, add the following to the deploy file just below "before 'deploy:migrate', 'database:create' if fetch(:initial)":

# run only if app is being deployed for the very first time, should update "set :initial, true" above to run thisbefore'deploy:migrate','database:create'iffetch(:initial)# update cron job from whenever schedule file at "config/schedule.rb"after'deploy:finishing','whenever:update_crontab'
Enter fullscreen modeExit fullscreen mode

Bonus 2: Sidekiq for background jobs

Sidekiq gem is used in Rails applications to schedule background jobs so as to perform them at a later point without having to stop the execution of other codes.

Capistrano Configurations

Create a new rake task atlib/capistrano/tasks/sidekiq.rake and add the following content which will be responsible for updating cron tasks configured inside the "config/schedule.rb":

namespace:sidekiqdodesc'Quieten sidekiq'task:quietdoonroles(:app)doputscapture("pgrep -f 'sidekiq' | xargs kill -TSTP")endenddesc'Restart Sidekiq'task:restartdoonroles(:app)doexecute:sudo,:systemctl,:restart,:sidekiqexecute:sudo,:systemctl,'daemon-reload'endendend
Enter fullscreen modeExit fullscreen mode

We now need to tell capistrano to run this code during deployment, add the following to the deploy file just below "after 'deploy:publishing', 'application:reload'":

# reload application after successful deployafter'deploy:publishing','application:reload'# sidekiq related commandsafter'deploy:starting','sidekiq:quiet'after'deploy:reverted','sidekiq:restart'after'deploy:published','sidekiq:restart'
Enter fullscreen modeExit fullscreen mode

Now try to deploy the app to production and server will ask for password when running sidekiq commands. To fix that we need to add some more configurations in the remote server.

Server Configurations

We are assuming that sidekiq is already configured in your remote server. If you have not configured it yet, you can refer to the section "Bonus: Setup Sidekiq in Ubuntu Server" atSetup Active Job with Sidekiq in Rails

For capistrano to perform sudo actions without asking for the password, the user used by capistrano, normally "deploy" user should be in the sudo group and you should add commands that need to be executed in the server with sudo access but without using password to "/etc/sudoers" file.

  1. Add deploy user to the sudo group

    You can add your deploy user to the sudo group with the following command

    # add "deploy" user to sudo group$ sudo usermod -aG sudo deploy# verify if the user has been added to the sudo group# result should include "sudo" for the deploy user$ groups deploydeploy : deploy sudo
  2. Add commands required for the sidekiq restart and daemon-reload to be performed without password

    • Open the sudoers file for the edit withsudo EDITOR=nano visudo, this will ensure that the content inside the file is validated before saving so you don't end up with invalid file. If you dosudo nano /etc/sudoers then it doesn't validate the content so you should never do that.
    • Add the following below the lineroot ALL=(ALL:ALL) ALL under "# User privilege specification"
      deploy ALL=NOPASSWD: /bin/systemctl restart sidekiq  deploy ALL=NOPASSWD: /bin/systemctl daemon-reload
  3. You can try running above two commands now in the command line of the server and it should run normally without asking for password:

    $ sudo systemctl restart sidekiq# doesn't ask for the password and executes the command

Now if you try to deploy again, capistrano won't stop to ask password when running sidekiq commands.

Conclusion

We have come to the finish line, now you should be able to deploy your API only Rails application to the server with one command.

Thanks for reading. Happy tinkering and happy coding!

Image Credits

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

More fromTruemark Technology

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp