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

Stephen Watkins

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?

Stephen Watkins

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

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Continuous Deployment Using Travis CI and Docker

setting up continuous deployment via travis ci for docusaurus - what github scopes to use?

How to set flyway config in continuous deployment pipeline using Travis CI and Azure?

Continuous deployment using travis and heroku - preserving some kind of state

What do the symbols *1 or &2 mean in Travis CI deployment scripts?

Continuous deployment for node.js applications using CI and CodeDeploy

What is a good Databricks workflow

Using Travis CI with Android

Using nix in a continuous delivery workflow

What is a good way to deploy a distributed application using CodeDeploy and a CI tool?

What would be a good docker webdev workflow?

What is the workflow for using scssphp?

What is the purpose of a build agent in continuous integration and continuous deployment?

On Travis CI, At what point does "cleanup" occur?

Deployment in Travis-CI to GitHub Pages: which files will be uploaded?

Travis CI skip release deployment because this is not a tagged commit

PyPi deployment from Travis CI: Invalid or non-existent authentication

How is Travis-Ci's pypi deployment secure?

Travis-CI skipping deployment although Commit is tagged

Travis CI Scala Play Application Build & Deployment Optimization

Errors Using node.js CI workflow

What is the industry standard solution for creating a deployment using CI (Jenkins) using kubectl set image command in kubernetes

Using VSTS for Continuous Deployment, config transform not working

Continuous deployment from git using Cloud Build

Continuous Deployment of a NodeJS using GitLab Ask Question

Continuous Deployment of .net core using Jenkins

Travis CI - Using repository environment variables in .travis.yml

Sonarcloud is not authorized using Travis CI and Maven

using travis-ci with wxpython tests