How to use git push-to-deploy

Note: git push-to-deploy is optional. Let us know if you would like us to install it.

We offer a deployment workflow that makes it very easy to deploy your code to MedStack. You can use almost any deployment method you like with your MedStack servers, but the git push-to-deploy (GPTD) workflow allows you to easily deploy in a manner similar to using Heroku.

What is git push-to-deploy?

With GPTD, you simply git push your code to a remote and it will deploy your app.

Note: If you've used Heroku, you are already familiar with using git push to deploy your code.

You use your existing git repository with a few simple changes that we will walk through below.

Note: If you're interested in how it works under the hood, check out the official documentation on git hooks. In a manner similar to Heroku, we have created a simple system to allow you to easily deploy your code onto a MedStack server

Overview

Everything is done on your local development machine. 

These are the steps that set up git push-to-deploy:

  1. In your existing source repository, create a deployment script. This script will be run on the MedStack server each time you push to the server. You can have multiple scripts if you like.
  2. Add a special remote to git on your development machine, one for each MedStack server you want to deploy to.

These are the steps that use GPTD to deploy to your MedStack server:

  1. Make some changes, commit them, and then git push to the special remote.
  2. The deployment scripts will run automatically and the output will appear in your git log.

If you need to roll back, just use git revert or git reset on your local machine, and then git push again.

Now we will walk through the steps in detail. This document has examples for Ruby on Rails, but git push-to-deploy works with any runtime.

Create one or more deployment scripts

GPTD deployment scripts are created on your development machine and committed to your repository. Each time you deploy, they are automatically pushed to the MedStack server and run.

In this step we will create those scripts.

On your development machine, cd to the root of your repository. Then create a directory structure .medstack/deploy.d which is a so-called run-parts directory (see below for details). Inside create a file called 10-deploy. Commit this file to the repo.

$ cd path/to/my/repository
$ mkdir -p .medstack/deploy.d
$ cd .medstack/deploy.d
$ cat > 10-deploy
true
^D
$ git add 10-deploy
$ git commit -m "Add git push to deploy script"

We have created a script which runs the true command, which always returns true. ^D means type control-D on the keyboard.

The name of the script, 10-deploy, is an example. As long as your script names follow the rules of run-parts, you can put as many scripts in this directory as you want and they will all be run in order each time you push.

You most likely already have a deployment script, which you should move into the file 10-deploy. 10-deploy will be your deployment script that is run automatically every time you push to deploy. In this script you will do things like migrate your database, rebuild your assets, and so on.

run-parts runs all scripts in a directory (depending on the name)

As noted above, we use run-parts on your deploy.d directory. This allows you to have any number of executables and scripts run automatically when deployment is performed.

run-parts is a useful tool that will run certain executable files (including any kind of scripts, like bash scripts) in the directory that you specify. It selects which executables to run based on the rules below.

The rule that most commonly catches people out is that the scripts can't have an extension like .sh because it ignores files that have dots (and many other characters) in the names.

What scripts/executables will run-parts run:

  1. It must meet the filename requirements: letters, numbers, underscores and hyphens only—no periods.
  2. The file must be either a binary executable, or text-based script with a shebang (like #!/usr/bin/env bash) to tell the OS what interpreter to use for the script.
  3. The file must have executable permissions. On a posix system this is applied with chmod +x <filename>.

So, rename your scripts to exclude the extension, make sure they have a shebang and are set to executable, and they will run.

A couple of other useful notes about run-parts:

  • The executables will be run in lexical order (sorted alpha-numerically with numbers first).
  • If you want to know what files will be run: run-parts --test path/to/directory will show you the files and the order.

Configure your local SSH to prepare for the git remote

On your local development machine, create a new Host block in your .ssh/config file. This will make it easy to set up git in the next step.

Suppose your server is called example.medstack.net. In that case, you will add a new Host block to your .ssh/config file (See also How to SSH to your deploy user).

On your local development machine:

cd .ssh
nano config # or use your favourite editor

Then add this below anything that's currently in the file:

Host git-example.medstack.net
  HostName example.medstack.net
  IdentityFile credentials/example/ssh/example.medstack.net-git_ssh_key
  User git
  IdentitiesOnly yes

Add a new remote to git for the MedStack server

Git has the concept of remotes. A typical remote to use is origin which is often configured to refer to GitHub. You can list all of your remotes with git remote or git remote -v. We are going to add a new remote that will refer to a MedStack server.

On your development machine, cd to the root of your repository. Then add a new git remote called medstack that refers to your MedStack server. Specifically, it uses the git-example.medstack.net name that we previously defined in your SSH configuration file.

$ cd path/to/my/repository
$ git remote add medstack git-example.medstack.net:app.git

If you have multiple MedStack servers, you can add multiple remotes, each with a different name.

Deploy the code using git push

Each time you push to the new medstack remote, it will execute git push-to-deploy. It will push your code and run the deployment scripts that you previously created.

On your development machine, cd to the root of your repository, and execute git push with your choice of branch. This example pushes the master branch, but you can push any branch you like.

$ cd path/to/my/repository
$ git push medstack master

This will push your code to the server, and run the scripts in .medstack/deploy.d.

Git will output all of the standard output from the server onto your development machine terminal window.

You're done setting up and testing GPTD

That completes setup and testing. You'll want to enhance your deployment scripts as needed, for example to rebuild assets and perhaps to restart an app server.

(optional) Create a supervisord configuration

We support Supervisord as a general purpose process-management system. It works well with git push-to-deploy. Follow the instructions in our supervisor documentation to set it up.

You can still perform manual testing

Although push-to-deploy is awesome, it's sometimes helpful to be able to manually test and run your scripts. Even if you are using push-to-deploy, you can always log into your deploy account using SSH and run your deployment scripts manually.

Appendix: Example deploy script for Ruby on Rails

If you are using Ruby on Rails, these example files can give you an idea of how to use supervisord and push-to-deploy in practice.

If you aren't using Rails, you still might find it helpful to look over these examples for some ideas about how you can apply this process to other runtimes.

This example also uses our MedStack supervisor setup for process management to keep the app running.

This example performs the following tasks each time the app is deployed:

  • Load the environment from rbenv.
  • Set the number of cores used by bundle install to the recommended value, number of CPUs -1.
  • Rehash the rbenv environment based on updated bundle.
  • Loads Rails environment variables from .env.production and creates it if needed.
  • Creates the database if needed.
  • Precompiles assets.
  • Creates a log directory for supervisor.
  • Reloads supervisor.

Example deployment script

Place this script in your app repository under .medstack/deploy.d/10-deploy-rails.

#!/usr/bin/env bash

# Exit if there's an error, a pipe error, or an unset variable:
set -e
set -o pipefail
set -u
# Show all commands being executed with fully expanded arguments
set -x

export RAILS_ENV=production

# Load ruby environment with rbenv
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
rbenv install 2.3.3 --skip-existing
gem install --conservative --no-document bundler

# Bundle (set the number of jobs to (number of cores) - 1)
CORES=$(grep -c ^processor /proc/cpuinfo)
bundle install --deployment --jobs $((CORES - 1))
rbenv rehash

# Environment
productionRailsEnvironmentFile='.env.production'
if [ ! -e $productionRailsEnvironmentFile ]
then
  echo SECRET_KEY_BASE=`bundle exec rake secret` > $productionRailsEnvironmentFile
fi

# Database
ranDBSetupFile='.ran.db.setup'
if [ ! -e $ranDBSetupFile ]
then
  bundle exec rake db:schema:load
  bundle exec rake db:seed
  touch $ranDBSetupFile
fi
bundle exec rake db:migrate

# Assets
bundle exec rake assets:precompile

# Log directory for supervisor-run processes
mkdir -p log

### Let supervisor run rails and clockwork ###
# reads update config
supervisorctl reread
# applies updated config to running apps
supervisorctl update
supervisorctl start all

Still need help? Contact Us Contact Us