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
Everything is done on your local development machine.
These are the steps that set up git push-to-deploy:
- 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.
- Add a special
remoteto 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:
- Make some changes, commit them, and then
git pushto the special remote.
- 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 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:
- It must meet the filename requirements: letters, numbers, underscores and hyphens only—no periods.
- 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.
- 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/directorywill 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
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.productionand 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
#!/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