Coder Social home page Coder Social logo

esshka / deploy-rails-capistrano3 Goto Github PK

View Code? Open in Web Editor NEW

This project forked from maxivak/deploy-rails-capistrano3

0.0 2.0 0.0 180 KB

Example of deploying Rails app with Capistrano 3

Home Page: http://maxivak.com/deploy-a-rails-application-with-capistrano-3/

Ruby 100.00%

deploy-rails-capistrano3's Introduction

deploy rails app with capistrano3

Example of deploying Rails application to a Linux server with Nginx+Passenger.

Find all necessary files in the repository and read about features below:

Capistrano 3

Initialize Capistrano

Gemfile

group :development do
  gem 'capistrano',  '~> 3.1'
  gem 'capistrano-rails', '~> 1.1'
 ...
end

Run the command

cap install

This command will create files:

Capfile
config/deploy.rb
config/deploy/production.rb
config/deploy/staging.rb
lib/capistrano/tasks          # directory

Setup

Gemfile

group :development do
  gem 'capistrano',  '~> 3.1'
  gem 'capistrano-rails', '~> 1.1'
  #gem 'capistrano-bundler', '~> 1.1'
  gem 'capistrano-rvm',   '~> 0.1'

end

Capfile

require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
#require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'

Restart server

Passenger

Restart application after deploy:

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      execute :touch, release_path.join('tmp/restart.txt')
    end
  end
  after :publishing, :restart
end

You can run this command manually to restart the app

cap production deploy:restart

This gem provides more functionality on working with Passenger: https://github.com/capistrano/passenger

Linked files, dirs

Some of the files should be stored in shared folder and shared across all releases. File from the 'linked_files' list are symlinked to files in shared folder.

For example, you may want to store users' uploaded files in public/uploads directory. This directory should not new in each release after deploy.

set :linked_dirs, fetch(:linked_dirs, []).push('bin', 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :linked_dirs, fetch(:linked_dirs) + %w{public/uploads}

set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')

Note! You need to copy linked files to the server before deploy manually. The files are not copied to the shared folder by Capistrano.

Config files

Task to copy files to shared directory:

set :config_dirs, %W{config config/environments/#{fetch(:stage)} public/uploads}
set :config_files, %w{config/database.yml config/secrets.yml}


namespace :deploy do
  desc 'Copy files from application to shared directory'
  ## copy the files to the shared directories
  task :copy_config_files do
    on roles(:app) do
      # create dirs
      fetch(:config_dirs).each do |dirname|
        path = File.join shared_path, dirname
        execute "mkdir -p #{path}"
      end

      # copy config files
      fetch(:config_files).each do |filename|
        remote_path = File.join shared_path, filename
        upload! filename, remote_path
      end

    end
  end
end

run the command:

cap production deploy:copy_config_files

Precompile assets

By default assets are precompiled every time during the deploy process. rake assets:precompile can take up a noticable amount of time of a deploy.

Run the task manually:

cap production deploy:assets:precompile

Precompile assets only after changes

We will redefine default precompile task to check for changed files. Assets will be precompiled only if changes are detected in certain files or folders defined by variable :assets_dependencies.

# set the locations that we will look for changed assets to determine whether to precompile
set :assets_dependencies, %w(app/assets lib/assets vendor/assets Gemfile config/routes.rb)


# clear the previous precompile task
Rake::Task["deploy:assets:precompile"].clear_actions
class PrecompileRequired < StandardError; end


namespace :deploy do
  namespace :assets do
    desc "Precompile assets if changed"
    task :precompile_changed do
      on roles(:app) do
        within release_path do
          with rails_env: fetch(:rails_env) do
            begin

              # find the most recent release
              latest_release = capture(:ls, '-xr', releases_path).split[1]

              # precompile if this is the first deploy
              raise PrecompileRequired unless latest_release

              #
              latest_release_path = releases_path.join(latest_release)

              # precompile if the previous deploy failed to finish precompiling
              execute(:ls, latest_release_path.join('assets_manifest_backup')) rescue raise(PrecompileRequired)

              fetch(:assets_dependencies).each do |dep|
                #execute(:du, '-b', release_path.join(dep)) rescue raise(PrecompileRequired)
                #execute(:du, '-b', latest_release_path.join(dep)) rescue raise(PrecompileRequired)

                # execute raises if there is a diff
                execute(:diff, '-Naur', release_path.join(dep), latest_release_path.join(dep)) rescue raise(PrecompileRequired)
              end

              warn("-----Skipping asset precompile, no asset diff found")

              # copy over all of the assets from the last release
              execute(:cp, '-rf', latest_release_path.join('public', fetch(:assets_prefix)), release_path.join('public', fetch(:assets_prefix)))

            rescue PrecompileRequired
              warn("----Run assets precompile")

              execute(:rake, "assets:precompile")
            end
          end
        end
      end
    end
  end
end

This solution was found in the post https://coderwall.com/p/aridag/only-precompile-assets-when-necessary-rails-4-capistrano-3

Use the new task instead of the default precompile task:

namespace :deploy do
  namespace :assets do
    desc "Precompile assets if changed"
    task :precompile do
      on roles(:app) do
        invoke 'deploy:assets:precompile_changed'
        #Rake::Task["deploy:assets:precompile_changed"].invoke
      end
    end
  end
end

Precompile assets locally

Sometimes you need to precompile assets locally and upload them to the server.

Define a task to compile assets locally and copy them to the server. If your local machine is on Windows, make sure you have zip archiver (for example, 7zip).

namespace :deploy do
  namespace :assets do

    desc 'Run the precompile task locally and upload to server'
    task :precompile_locally_archive do
      on roles(:app) do
        run_locally do
          if RUBY_PLATFORM =~ /(win32)|(i386-mingw32)/
            execute 'del "tmp/assets.tar.gz"' rescue nil
            execute 'rd /S /Q "public/assets/"' rescue nil

            # precompile
            with rails_env: fetch(:rails_env) do
              execute 'rake assets:precompile'
            end
            #execute "RAILS_ENV=#{rails_env} rake assets:precompile"

            # use 7zip to archive
            execute '7z a -ttar assets.tar public/assets/'
            execute '7z a -tgzip assets.tar.gz assets.tar'
            execute 'del assets.tar'
            execute 'move assets.tar.gz tmp/'
          else
            execute 'rm tmp/assets.tar.gz' rescue nil
            execute 'rm -rf public/assets/*'

            with rails_env: fetch(:rails_env) do
              execute 'rake assets:precompile'
            end

            execute 'touch assets.tar.gz && rm assets.tar.gz'
            execute 'tar zcvf assets.tar.gz public/assets/'
            execute 'mv assets.tar.gz tmp/'
          end
        end

        # Upload precompiled assets
        execute 'rm -rf public/assets/*'
        upload! "tmp/assets.tar.gz", "#{release_path}/assets.tar.gz"
        execute "cd #{release_path} && tar zxvf assets.tar.gz && rm assets.tar.gz"
      end
    end

  end
end

If you don't want to archive the assets before upload, use this task which will copy folder /public/assets to the server file by file.

namespace :deploy do
  namespace :assets do

    desc 'Precompile assets locally and upload to server'
    task :precompile_locally_copy do
      on roles(:app) do
        run_locally do
          with rails_env: fetch(:rails_env) do
            #execute 'rake assets:precompile'
          end
        end

        execute "cd #{release_path} && mkdir public" rescue nil
        execute "cd #{release_path} && mkdir public/assets" rescue nil
        execute 'rm -rf public/assets/*'

        upload! 'public/assets', "#{release_path}/public", recursive: true

      end
    end
  end
end

Run tasks :

cap production deploy:assets:precompile_locally_archive

or 

cap production deploy:assets:precompile_locally_copy

To replace default precompile task with the new task:

namespace :deploy do
  namespace :assets do
    desc "Precompile assets"
    task :precompile do
      on roles(:app) do
        invoke 'deploy:assets:precompile_locally_archive'
        #Rake::Task["deploy:assets:precompile_locally_archive"].invoke
      end
    end    
  end  
end

Maintenance page

Use these tasks if you need to show a certain page on site to visitors while the app is updating:

cap production deploy:web:enable 
cap production deploy:web:disable

Create a page 'app/views/admin/maintenance.html.haml'

<div style="width:100%;">
<div style="width:900px; margin:0 auto;">
  <h1>Site is offline for <%= reason ? reason : 'maintenance' %></h1>
  <p>We're currently offline for <%= reason ? reason : 'maintenance' %> as of <%= Time.now.utc.strftime('%H:%M %Z') %>.</p>
  <p>Sorry for the inconvenience.
  <p>We'll be back <%= deadline ? "by #{deadline}" : 'shortly' %>.</p>

</div></div>

The task will compile the template and put it in 'shared/public/system/maintenance.html'

Tasks:

# maintenance page
namespace :deploy do
  namespace :web do
    desc <<-DESC
      Present a maintenance page to visitors.
        $ cap deploy:web:disable REASON="a hardware upgrade" UNTIL="12pm Central Time"
    DESC

    task :disable do
      on roles(:web) do
        execute "rm #{shared_path}/system/maintenance.html" rescue nil

        require 'erb'
        reason = ENV['REASON']
        deadline = ENV['UNTIL']
        template = File.read('app/views/admin/maintenance.html.haml')
        #page = ERB.new(template).result(binding)
        content = ERB.new(template).result(binding)

        path = "public/system/maintenance.html"
        File.open(path, "w") { |f| f.write content }

        upload! path, "#{shared_path}/public/system/maintenance.html", :mode => 0644
      end

    end

    task :enable do
      on roles(:web) do
        execute "rm #{shared_path}/public/system/maintenance.html"
      end
    end

  end
end

The solution was found here: http://stackoverflow.com/questions/2244263/capistrano-to-deploy-rails-application-how-to-handle-long-migrations.

Run the tasks before and after deploy:

before "deploy", "deploy:web:disable"
after "deploy", "deploy:web:enable"

Now we need to show this page on site. You need to modify settings on your web server to use this maintenance page.

Nginx

If you have Nginx as a web server, add this code to the server's configuration:

server {
  passenger_enabled on;

  server_name yoursite.com;
  ...

  if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html break;
  }

}

Delete old repos

set :keep_releases, 5

Keep only several releases. Old releases will be deleted automatically after successful deploy.

Deploy

Before deploy

Run this command after you change your config files (like config/database.yml)

cap production deploy:copy_config_files

Deploy

cap production deploy

cap <stage_name> deploy

References

Tutorials about deploy

deploy-rails-capistrano3's People

Contributors

maxivak avatar

Watchers

Eugeny avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.