DevOps Discipline

Detailed & Complete

devopsgroup.io

devopsgroup.io 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

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

Source Code Management

Confirm repository write access

                        
if "#{repo_split_2[0]}" == "github.com"
  uri = URI("https://api.github.com/repos/#{repo_split_3[0]}/collaborators/#{@configuration["company"]["github_username"]}")
  Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
    request = Net::HTTP::Get.new 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)
    else
      if response.code.to_f == 204
        puts "   - Verified your GitHub user #{@configuration["company"]["github_username"]} has write access."
      else
        catapult_exception("Your GitHub user #{@configuration["company"]["github_username"]} does not have write access to this repository.")
      end
    end
  end
end
                        
                    

Configuration Management

Single repository for platform configuration

                        
company:
  name: ACME CO.
  newrelic_api_key: xxxxxxxxxxxxxxx
environments:
  dev:
    branch: develop
  test:
    branch: develop
  qc:
    branch: release
  production:
    branch: master
websites:
  apache:
    - domain: acmeco.com
      repo: git@github.com:acmeco/wiley.coyote.git
                        
                    

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/id_rsa.pub, 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='id_rsa.pub'

 * There were no changes to secrets/id_rsa.pub, 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/provision.sh", 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

                        
File.write('.git/hooks/pre-commit',
'#!/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
end'
                        
                    

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: example.com
    * dev.example.com, test.example.com, qc.example.com, example.com
* domain_tld_override:
  * example: mycompany.com
    * 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
      * dev.example.com.mycompany.com, test.example.com.mycompany.com,
        qc.example.com.mycompany.com, example.com.mycompany.com
                        
                    

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 "https://api.cloudflare.com/client/v4/zones" \
  --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 https://download.newrelic.com/pub/newrelic/el5/i386/newrelic-repo-5-3.noarch.rpm
sudo yum install -y newrelic-sysmond
                        
                    

Monitoring & Insights

Managed application performance monitoring

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

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 "https://synthetics.newrelic.com/synthetics/api/v1/monitors" \
  --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: devopsgroup.io/conference-session
  • Get started: github.com/devopsgroup-io/catapult