Skip to content

bspellacy/shipit-engine

 
 

Repository files navigation

Shipit - Documentation

Build Status Gem Version

Shipit is a deployment tool that makes shipping code better for everyone. It's especially great for large teams of developers and designers who work together to build and deploy GitHub repos. You can use it to:

  • add new applications to your deployment environment without having to change core configuration files repeatedly — shipit.yml is basically plug and play
  • control the pace of development by pushing, locking, and rolling back deploys from within Shipit
  • enforce checklists and provide monitoring right at the point of deployment.

Shipit is compatible with just about anything that you can deploy using a script. It natively detects stacks using bundler and Capistrano, and it has tools that make it easy to deploy to Heroku or RubyGems. At Shopify, we've used Shipit to synchronize and deploy hundreds of projects across dozens of teams, using Python, Rails, RubyGems, Java, and Go.

This guide aims to help you set up, use, and understand Shipit.

Shipit requires a database (MySQL, PostgreSQL or SQLite3), redis, and Ruby 2.1 or superior.


Table of contents

I. INSTALLATION & SETUP

II. USING SHIPIT

III. REFERENCE


I. INSTALLATION & SETUP

Installation

Shipit requires a database (MySQL, PostgreSQL or SQLite3), Redis, and Ruby 2.1 or superior.

Shipit provides you with a Rails template. To bootstrap your Shipit installation:

  1. If you don't have Rails installed, run this command: gem install rails -v 5.1
  2. Run this command: rails _5.1_ new shipit --skip-action-cable --skip-turbolinks --skip-action-mailer -m https://raw.githubusercontent.com/Shopify/shipit-engine/master/template.rb
  3. Enter your Client ID, Client Secret, and GitHub API access token when prompted. These can be found on your application's GitHub page.
  4. To setup the database, run this command: rake db:setup

Configuring shipit.yml and secrets.yml

Shipit should just work right out of the box — you probably won't need to alter its configuration files before getting it up and running. But if you want to customize Shipit for your own deployment environment, you'll need to edit the shipit.yml and secrets.yml files:

  • The settings in the shipit.yml file are related to the different things you can do within Shipit, such as handling deploys, performing custom tasks, and enforcing deployment checklists. If you want to edit these settings, start here.
  • The settings in the secrets.yml file are related to the ways that Shipit connects with GitHub. If you want to edit these settings, start here.

Updating an existing installation

  1. If you locked the gem to a specific version in your Gemfile, update it there.
  2. Update the shipit-engine gem with bundle update shipit-engine.
  3. Install new migrations with rake shipit:install:migrations db:migrate.

II. USING SHIPIT

The main workflows in Shipit are adding stacks, working on stacks, and configuring stacks.

A stack is composed of a GitHub repository, a branch, and a deployment environment. Shipit tracks the commits made to the branch, and then displays them in the stack overview. From there, you can deploy the branch to whatever environment you've chosen (some typical environments include production, staging, performance, etc.).

Add a new stack

  1. From the main page in Shipit, click Add a stack.
  2. On the Create a stack page, enter the required information:
    • Repo
    • Branch
    • Environment
    • Deploy URL
  3. When you're finished, click Create stack.

Work on an existing stack

  1. If you want to browse the list of available stacks, click Show all stacks on the main page in Shipit. If you know the name of the stack you're looking for, enter it in the search field.
  2. Click the name of the stack you want to open.
  3. From a stack's overview page, you can:
    • review previous deploys
    • deploy any undeployed commits by clicking Deploy
    • rollback to an earlier build by clicking Rollback to this deploy
    • adjust the stack's settings by clicking the gear icon in the page header
    • perform any custom tasks that are defined in the shipit.yml file
  4. When you're ready to deploy an undeployed commit, click the relevant Deploy button on the stack's overview page.
  5. From the Deploy page, complete the checklist, then click Create deploy.

Edit stack settings

To edit a stack's settings, open the stack in Shipit, then click the gear icon in the page header.

From a stack's Settings page, you can:

  • change the deploy URL
  • enable and disable continuous deployment
  • lock and unlock deploys through Shipit
  • resynchronize the stack with GitHub
  • delete the stack from Shipit

III. REFERENCE

Configuring shipit.yml

The settings in the shipit.yml file relate to the different things you can do with Shipit:

All the settings in shipit.yml are optional. Most applications can be deployed from Shipit without any configuration.

Also, if your repository is deployed different ways depending on the environment, you can have an alternative shipit.yml by including the environment name.

For example for a stack like: my-org/my-repo/staging, shipit.staging.yml will have priority over shipit.yml.


Installing dependencies

The dependencies step allows you to install all the packages your deploy script needs.

Bundler

If your application uses Bundler, Shipit will detect it automatically and take care of the bundle install and prefix your commands with bundle exec.

By default, the following gem groups will be ignored:

  • default
  • production
  • development
  • test
  • staging
  • benchmark
  • debug

The gems you need in order to deploy should be in a different group, such as deploy.

For example:

dependencies:
  bundler:
    without:
      - development
      - test
      - debug

Other dependencies

If your deploy script uses another tool to install dependencies, you can install them manually via dependencies.override:

dependencies:
  override:
    - npm install

dependencies.pre If you wish to execute commands before Shipit installs the dependencies, you can specify them here.

For example:

dependencies:
  pre:
    - mkdir tmp/
    - cp -R /var/cache/ tmp/cache

dependencies.post If you wish to execute commands after Shipit installed the dependencies, you can specify them here:

For example:

dependencies:
  post:
    - cp -R tmp/cache /var/cache/

Deployment

The deploy and rollback sections are the core of Shipit:

deploy.override contains an array of the shell commands required to deploy the application. Shipit will try to infer it from the repository structure, but you can change the default inference.

For example:

deploy:
  override:
    - ./script/deploy

deploy.pre If you wish to execute commands before Shipit executes your deploy script, you can specify them here.

For example:

deploy:
  pre:
    - ./script/notify_deploy_start

deploy.post If you wish to execute commands after Shipit executed your deploy script, you can specify them here.

For example:

deploy:
  post:
    - ./script/notify_deploy_end

You can also accept custom environment variables defined by the user that triggers the deploy:

deploy.variables contains an array of variable definitions.

For example:

deploy:
  variables:
    -
      name: RUN_MIGRATIONS
      title: Run database migrations on deploy
      default: 1

deploy.variables.select will turn the input into a <select> of values.

For example:

deploy:
  variables:
    -
      name: REGION
      title: Run a deploy in a given region
      select:
        - east
        - west
        - north

deploy.max_commits define the maximum number of commits that should be shipped per deploys. Defaults to 8.

Human users will be warned that they are not respecting the recommendation, but allowed to continue. However continuous delivery will respect this limit. If there is no deployable commits in this range, a human intervention will be required.

For example:

deploy:
  max_commits: 5

rollback.override contains an array of the shell commands required to rollback the application to a previous state. Shipit will try to infer it from the repository structure, but you can change the default inference. This key defaults to disabled unless Capistrano is detected.

For example:

rollback:
  override:
    - ./script/rollback

rollback.pre If you wish to execute commands before Shipit executes your rollback script, you can specify them here:

For example:

rollback:
  pre:
    - ./script/notify_rollback_start

rollback.post If you wish to execute commands after Shipit executed your rollback script, you can specify them here:

For example:

rollback:
  post:
    - ./script/notify_rollback_end

fetch contains an array of the shell commands that Shipit executes to check the revision of the currently-deployed version. This key defaults to disabled.

For example:

fetch:
  curl --silent https://app.example.com/services/ping/version

Kubernetes

kubernetes allows to specify a Kubernetes namespace and context to deploy to.

For example:

kubernetes:
  namespace: my-app-production
  context: tier4

kubernetes.template_dir allows to specify a Kubernetes template directory. It defaults to ./config/deploy/$ENVIRONMENT

Environment

machine.environment contains the extra environment variables that you want to provide during task execution.

For example:

machine:
  environment:
    key: val # things added as environment variables

Directory

machine.directory specifies a subfolder in which to execute all tasks. Useful for repositories containing multiple applications or if you don't want your deploy scripts to be located at the root.

For example:

machine:
  directory: scripts/deploy/

Cleanup

machine.cleanup specifies whether or not the deploy working directory should be cleaned up once the deploy completed. Defaults to true, but can be useful to disable temporarily to investigate bugs.

For example:

machine:
  cleanup: false

CI

ci.require contains an array of the statuses context you want Shipit to disallow deploys if any of them is missing.

For example:

ci:
  require:
    - ci/circleci

ci.hide contains an array of the statuses context you want Shipit to ignore.

For example:

ci:
  hide:
    - ci/circleci

ci.allow_failures contains an array of the statuses context you want to be visible but not to required for deploy.

For example:

ci:
  allow_failures:
    - ci/circleci

Merge Queue

The merge queue allow to register pull requests for them to be merged by Shipit once the stack is clear (no lock, no failing CI, no backlog). It can be enabled on a per stack basis via the settings page.

It can be customized via several shipit.yml properties:

merge.revalidate_after a duration after which pull requests that couldn't be merged are rejected from the queue. Defaults to unlimited.

For example:

merge:
  revalidate_after: 12m30s

merge.require contains an array of the statuses context that you want Shipit to consider as failing if they aren't present on the pull request. Defaults to ci.require if present, or empty otherwise.

For example:

merge:
  require:
    - continuous-integration/travis-ci/push

merge.ignore contains an array of the statuses context that you want Shipit not to consider when merging pull requests. Defaults to the union of ci.allow_failures and ci.hide if any is present or empty otherwise.

For example:

merge:
  ignore:
    - codeclimate

Custom tasks

You can create custom tasks that users execute directly from a stack's overview page in Shipit. To create a new custom task, specify its parameters in the tasks section of the shipit.yml file. For example:

tasks restarts the application.

tasks:
  restart:
    action: "Restart Application"
    description: "Sometimes needed if you want the application to restart but don't want to ship any new code."
    steps:
      - ssh [email protected] 'touch myapp/restart.txt'

By default, custom tasks are not allowed to be triggered while a deploy is running. But if it's safe for that specific task, you can change that behavior with the allow_concurrency attribute:

tasks:
  flush_cache:
    action: "Flush Cache"
    steps:
      - ssh [email protected] 'myapp/flush_cache.sh'
    allow_concurrency: true

Tasks like deploys can prompt for user defined environment variables:

tasks:
  restart:
    action: "Restart Application"
    description: "Sometimes needed if you want the application to restart but don't want to ship any new code."
    steps:
      - ssh [email protected] 'touch myapp/restart.txt'
    variables:
      -
        name: FORCE
        title: Restart server without waiting for in-flight requests to complete (Dangerous).
        default: 0

Review process

You can display review elements, such as monitoring data or a pre-deployment checklist, on the deployment page in Shipit:

review.checklist contains a pre-deploy checklist that appears on the deployment page in Shipit, with each item in the checklist as a separate string in the array. It can contain strong and a HTML tags. Users cannot deploy from Shipit until they have checked each item in the checklist.

For example:

review:
  checklist:
    - >
      Do you know if it is safe to revert the code being shipped? What happens if we need to undo this deploy?
    - Has the Docs team been notified of any major changes to the app?
    - Is the app stable right now?

review.monitoring contains a list of inclusions that appear on the deployment page in Shipit. Inclusions can either be images or iframes.

For example:

review:
  monitoring:
    - image: https://example.com/monitoring.png
    - iframe: https://example.com/monitoring.html

review.checks contains a list of commands that will be executed during the pre-deploy review step. Their output appears on the deployment page in Shipit, and if continuous delivery is enabled, deploys will only be triggered if those commands are successful.

For example:

review:
  checks:
    - bundle exec rake db:migrate:status

Shell commands timeout

All the shell commands can take an optional timeout parameter to limit their duration:

deploy:
  override:
    - ./script/deploy:
        timeout: 30
  post:
    - ./script/notify_deploy_end: { timeout: 15 }
review:
  checks:
    - bundle exec rake db:migrate:status:
        timeout: 60

See also commands_inactivity_timeout in secrets.yml for a global timeout setting.


Configuring secrets.yml

The settings in the secrets.yml file relate to the ways that GitHub connects with Shipit:

secret_key_base is used to verify the integrity of signed cookies.

For example:

production:
  secret_key_base: s3cr3t # This needs to be a very long, fully random

github_oauth contains the settings required to authenticate users through GitHub.

The value for id is your application's Client ID, and the value for secret is your application's Client Secret — both of these should appear on your application's GitHub page.

Note: When setting up your application in Github, set the Authorization callback URL to <yourdomain>/github/auth/github/callback.

The teams key is optional, and required only if you want to restrict access to a set of GitHub teams.

If it's missing, the Shipit installation will be public unless you setup another authentication method.

After you change the list of teams, you have to invoke bin/rake teams:fetch in production so that a webhook is setup to keep the list of members up to date.

For example:

production:
  github_oauth:
    id: (your application's Client ID)
    secret: (your application's Client Secret)
    teams:
      - Shipit/team
      - Shipit/another_team

github_api communicates with the GitHub API about the stacks and setup Hooks. It should reflect the guidelines at https://github.com/octokit/octokit.rb.

If you specify an access_token, you don't need a login and password. The opposite is also true: if you specify a login and password, then you don't need an access_token.

For example:

production:
  github_api:
    access_token: 10da65c687f6degaf5475ce12a980d5vd8c44d2a

host is the host that hosts Shipit. It's used to generate URLs, and it's the host that GitHub will try to talk to.

For example:

production:
  host: 'http://localhost:3000'

redis_url is the URL of the redis instance that Shipit uses.

For example:

production:
  redis_url: "redis://127.0.0.1:6379/7"

If you use GitHub Enterprise, you must also specify the github_domain.

For example:

production:
  github_domain: "github.example.com"

commands_inactivity_timeout is the duration after which Shipit will terminate a command if no ouput was received. Default is 300 (5 minutes).

For example:

production:
  commands_inactivity_timeout: 900 # 15 minutes

Script parameters

Your deploy scripts have access to the following environment variables:

  • SHIPIT: Set to 1 to allow your script to know it's executed by Shipit
  • SHIPIT_LINK: URL to the task output, useful to broadcast it in an IRC channel
  • SHIPIT_USER: Full name of the user that triggered the deploy/task
  • EMAIL: Email of the user that triggered the deploy/task (if available)
  • ENVIRONMENT: The stack environment (e.g production / staging)
  • BRANCH: The stack branch (e.g master)
  • LAST_DEPLOYED_SHA: The git SHA of the last deployed commit
  • DIFF_LINK: URL to the diff on GitHub.
  • TASK_ID: ID of the task that is running
  • All the content of the secrets.yml env key
  • All the content of the shipit.yml machine.environment key

These variables are accessible only during deploys and rollback:

  • REVISION: the git SHA of the revision that must be deployed in production
  • SHA: alias for REVISION

Configuring providers

Heroku

To use Heroku integration (lib/snippets/push-to-heroku), make sure that the environment has Heroku toolbelt available.

Kubernetes

For Kubernetes, you have to provision Shipit environment with the following tools:

  • kubectl
  • kubernetes-deploy gem

Packages

No packages published

Languages

  • Ruby 82.0%
  • HTML 8.2%
  • CSS 5.8%
  • CoffeeScript 2.8%
  • Shell 1.1%
  • JavaScript 0.1%