Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good workflow for Continuous Deployment to a VPS using Travis CI and Capistrano?

I have a Ruby web app that is hosted on a Digital Ocean VPS. Under the current setup, I have a bash script that lives on the VPS that does the following upon execution:

  • Stops the app server
  • Clones the latest git repository code to the local server
  • Runs database migrations
  • Starts the app server
  • Clean up

Obviously, this approach isn't scalable (or even good). So I'm trying to setup a deployment pipeline using Travis CI + Capistrano that automatically installs, builds, tests, and deploys this web app upon git push.

So far, we have Travis CI performing the install, build, and testing of our code upon every git push, but we are stumbling on the best way to accomplish the deployment step. Because we have JS and SASS files that need to be built using gulp, we are unable to just pull straight from git onto the server and run. And since Travis CI is building these files already, we are curious if it is appropriate to leverage the built files from Travis CI and send them directly from Travis CI to our servers.

Some options we've considered:


SCP + Direct Transfer

Like the custom deployment FTP example on Travis CI, we could SCP the built files to our server and call a bash script that runs migrations and restarts the app server.

Capistrano + Direct Transfer

We could install Capistrano on Travis CI and use it to directly transfer files that were built on Travis CI to our servers. Before packaging and sending, we would need to clean up any files/directories that would not need to be transferred (node_modules, bower, etc.). After transferring the package, we could again use Capistrano to extract it, run database migrations, and restart the app server.

For this, how do we minimize deployment downtime? And how do we manage errors and rollbacks?

Capistrano + Git

We could push the built Travis CI files to a Git tag on github and use Capistrano to pull the Git tag on the server, run database migrations, and restart the app server.

For this, it seems that git releases should only be for prod, so how do we manage the different environments (dev, stage, and prod)?


Anyway, we've researched quite a bit online, and haven't been able to find a solution for our needs that lays out a best-standard approach to deploying from Travis CI to a non-supported deployment provider.

Given the situation above, what is the best way to deploy from Travis CI to a VPS?

like image 209
Stephen Watkins Avatar asked Aug 19 '14 20:08

Stephen Watkins


People also ask

How does Travis CI work?

As a continuous integration platform, Travis CI supports your development process by automatically building and testing code changes, providing immediate feedback on the success of the change. Travis CI can also automate other parts of your development process by managing deployments and notifications.

Which of the following provides are supported by Travis CI?

Continuous Deployment to the following providers is supported: anynines. AWS CloudFormation. AWS CodeDeploy.


1 Answers

I ended up using a Capistrano task to package the release from Travis CI and upload it to the appropriate server.

I had to create a new SCM in Capistrano (which I called Travis) that overwrote the release creation tasks of the default SCM.

I've posted it to this github thread: https://github.com/capistrano/capistrano/issues/722#issuecomment-54653745

And for completion, the custom Capistrano code is also below.

set :scm, :git

namespace :travis do

  desc 'Check that travis is reachable'
  task :check do
      exit 1 unless true
  end

  desc 'Package to release'
  task :create_release do
      run_locally do
          execute :mkdir, '-p', :'tmp'
          execute "tar -cz --exclude tests --exclude vendor --exclude .git --exclude node_modules --exclude tmp/#{fetch(:release_timestamp)}.tar.gz -f tmp/#{fetch(:release_timestamp)}.tar.gz ."
      end
      on release_roles :all do
          execute :mkdir, '-p', release_path
          upload! "tmp/#{fetch(:release_timestamp)}.tar.gz", "#{release_path}/#{fetch(:release_timestamp)}.tar.gz"
          execute "tar -xvf #{release_path}/#{fetch(:release_timestamp)}.tar.gz --directory #{release_path}"
          execute "rm #{release_path}/#{fetch(:release_timestamp)}.tar.gz"
      end
      run_locally do
          execute "rm -rf tmp"
      end
  end

  desc 'Determine the revision that will be deployed'
  task :set_current_revision do
      run_locally do
          set :current_revision, capture(:git, "rev-parse --short #{fetch(:branch)}")
      end
  end

end

namespace :deploy do

  desc 'Use Travis'
  task :use_travis do
    set :scm, :travis
  end

  before :starting, :use_travis

end
like image 172
Stephen Watkins Avatar answered Oct 13 '22 11:10

Stephen Watkins