DevOps Discipline

Detailed & Complete Team

  • Seth Reeser and Steve Britton
  • Our related projects
    • vagrant-digitalocean
    • vagrant-hostmanager
  • Catapult
    • a website and workflow management platform

DevOps Discipline:
Detailed & Complete

  • Code samples and multimedia
  • Fast-paced, time-boxed topics
    • Source Code Management
    • Configuration Management
    • Development and Virtualization
    • Environment Management
    • DNS Management
    • Continuous Integration
    • Monitoring & Insights

What is Catapult?

  • Catapult is a website and workflow management platform
  • Catapult is an open source, complete, and distributed architecture
  • Catapult features Gitflow workflow while enforcing exactly matching, branch-driven environments

Source Code Management

Verify repository integrity

$(ls -afq .git/refs/heads | wc -l ) == "2"
$(git rev-list HEAD | tail -n 1) != $(git rev-list origin | tail -n 1)

SSH key scans for remote Git

until [ $i -ge 10; ]; do
    sudo ssh-keyscan > ~/.ssh/known_hosts
    if grep -q "bitbucket\.org" ~/.ssh/known_hosts; then
        echo "ssh-keyscan for successful"
        echo "ssh-keyscan for failed, retrying!"

Source Code Management

Confirm repository write access

if "#{repo_split_2[0]}" == ""
  uri = URI("{repo_split_3[0]}/collaborators/#{@configuration["company"]["github_username"]}")
  Net::HTTP.start(, uri.port, :use_ssl => uri.scheme == 'https') do |http|
    request = uri.request_uri
    request.basic_auth "#{@configuration["company"]["github_username"]}", "#{@configuration["company"]["github_password"]}"
    response = http.request request # Net::HTTPResponse object
    if response.code.to_f == 404
      catapult_exception("The GitHub repo #{instance["repo"]} does not exist")
    elsif response.code.to_f.between?(399,600)
      puts "   - The GitHub API seems to be down, skipping... (this may impact provisioning and automated deployments)".color(Colors::RED)
      if response.code.to_f == 204
        puts "   - Verified your GitHub user #{@configuration["company"]["github_username"]} has write access."
        catapult_exception("Your GitHub user #{@configuration["company"]["github_username"]} does not have write access to this repository.")

Configuration Management

Single repository for platform configuration

  name: ACME CO.
  newrelic_api_key: xxxxxxxxxxxxxxx
    branch: develop
    branch: develop
    branch: release
    branch: master
    - domain:

Configuration Management

Secrets are GPG AES 256 encrypted

Verification of encrypted Catapult configuration files:

 * GPG Edit Mode is enabled at secrets/configuration-user.yml["settings"]["gpg_edit"], if there are changes to secrets/configuration.yml, secrets/id_rsa, or secrets/, they will be re-encrypted.

gpg: original file name='configuration.yml'

 * There were no changes to secrets/configuration.yml, no need to encrypt as this would create a new cipher to commit.

gpg: original file name='id_rsa'

 * There were no changes to secrets/id_rsa, no need to encrypt as this would create a new cipher to commit.

gpg: original file name=''

 * There were no changes to secrets/, no need to encrypt as this would create a new cipher to commit.


Development & Virtualization

Exactly matching local development

# sync the repositories folder for local access from the host
config.vm.synced_folder "repositories", "/var/www/repositories", type: "nfs"
# configure the provisioner
config.vm.provision "shell", path: "provisioners/redhat/", args: ["dev","#{Catapult::Command.repo}","#{Catapult::Command.configuration_user["settings"]["gpg_key"]}","mysql","#{Catapult::Command.configuration_user["settings"]["software_validation"]}"]

Local separation and platform contribution

'#!/usr/bin/env ruby
if staged.include?("secrets/configuration.yml.gpg")
    puts "Please commit secrets/configuration.yml.gpg on the develop branch.
    You are on the develop-catapult branch, which is meant for contribution
    back to Catapult and should not contain your configuration files."
    exit 1

Environment Management

Vagrant driven by configuration

# dev => redhat
config.vm.define "#{Catapult::Command.configuration["company"]["name"].downcase}-dev-redhat" do |config|
  config.vm.provider :virtualbox do |provider|
# test => redhat
config.vm.define "#{Catapult::Command.configuration["company"]["name"].downcase}-test-redhat" do |config|
  config.vm.provider :digitalocean do |provider|
# qc => redhat
config.vm.define "#{Catapult::Command.configuration["company"]["name"].downcase}-qc-redhat" do |config|
  config.vm.provider :digitalocean do |provider|
# production => redhat
config.vm.define "#{Catapult::Command.configuration["company"]["name"].downcase}-production-redhat" do |config|
  config.vm.provider :digitalocean do |provider|

Environment Management

Branch driven with Git Flow

LocalDev   Test          QC          Production
develop   develop   release   master

Environment Management

Software workflow downstream and upstream

Replacing database website URLs

sed -r --expression="s/:\/\/(www\.)?(dev\.|test\.|qc\.)?(${domain_url_replace})/:\/\/\1${domain_url}/g" \
"/var/www/repositories/apache/${domain}/_sql/$(basename "$file")" > \
"/var/www/repositories/apache/${domain}/_sql/${1}.$(basename "$file")"

Updating the database from latest code base

php index.php migrate
drush updatedb -y
php wp-cli.phar core update-db

DNS Management

Domain name driven

* domain:
  * example:
* domain_tld_override:
  * example:
    * a domain name under your name server authority to append to the top-level-domain (e.g. .com)
    * appends the domain_tld_override for Environments

Local DNS management

# configure hosts file on both the host and guest
config.vm.provision :hostmanager
config.hostmanager.aliases = Catapult::Command.dev_redhat_hosts

DNS Management

Cloud DNS management

$(curl --silent --show-error --connect-timeout 5 --max-time 5 --write-out "HTTPSTATUS:%{http_code}" \
  --request POST "" \
  --header "X-Auth-Email: $(catapult company.cloudflare_email)" \
  --header "X-Auth-Key: $(catapult company.cloudflare_api_key)" \
  --data "{\"name\":\"${domain_levels[-2]}.${domain_levels[-1]}\",\"jump_start\":false}")

Continuous Integration

Commits to environment branches trigger deployments

Monitoring & Insights

Managed server monitoring

sudo rpm --hash --upgrade --verbose
sudo yum install -y newrelic-sysmond

Monitoring & Insights

Managed application performance monitoring

<IfModule php5_module>
  php_value newrelic.appname "${domain_environment};$(catapult | tr '[:upper:]' '[:lower:]')-${1}-redhat"

Monitoring & Insights

Managed browser performance monitoring

Monitoring & Insights

Managed synthetic monitoring

$(curl --silent --show-error --connect-timeout 10 --max-time 20 --write-out "HTTPSTATUS:%{http_code}" \
  --request GET "" \
  --header "X-Api-Key: $(catapult company.newrelic_admin_api_key)")

Catapult Dashboard

Catapult Dashboard

Catapult Dashboard

Thank You

  • Catapult is a complete website and workflow management platform built from leading and affordable technologies.
  • Our mission is to create a lean platform which orchestrates DevOps for website lifecycles with familiar technologies.
  • Our vision is to afford organizations reduced risk and improved performance while lowering barriers to entry.
  • Presentation:
  • Get started: