This Puppet module provide tooling for Continuous Delivery (CD) of applications in a Puppet managed environment by leveraging orchestration through Bolt or Choria.
Each application is declared as an application
resource. They are identified by a unique title
, an application
name, an environment
name and a path
:
application { 'acme':
application => 'acme',
environment => 'production',
path => '/opt/acme',
}
On disc, this will result in this directory hierarchy (assuming 3 deployments are created: d1
, d2
, d3
):
/opt/acme/
|-> current@ -> /opt/acme/d3
|-> d1/
|-> d2/
`-> d3/
Your profile is likely to declare an application
resource and additional resources that make it useful and point in the current
directory:
class profile::acme {
application { 'acme':
application => 'acme',
environment => 'production',
path => '/opt/acme',
}
file { '/usr/local/bin/acme-runner':
ensure => link,
target => '/opt/acme/current/bin/acme-runner',
}
apache::vhost { 'acme.example.com':
docroot => '/opt/acme/current/public',
}
}
Sometimes, some data must persist through deployments (e.g. uploaded files, logs). The application module install the mtree gem to manage symbolic links in the deployments directory and have them point to a persistent-data
directory if a .mtree
file is found at the root of a deployment.
Assuming a .mtree
file is added at the root of the previous project containing:
/set type=dir uname=deploy gname=deploy mode=0755
.
db uname=user
production.sqlite3 type=file uname=user mode=0640
..
..
config
database.yml type=file gname=user mode=0640
..
..
log
production.log type=file gname=user mode=0660
..
..
tmp uname=user gname=user
..
..
On the next deployment d4
, the described hierarchy tree will be created in the persistent-data
directory, and all files corresponding to leaves of this tree in the deployment will be removed and replaced by symbolic-links to the corresponding persistent-data file:
/opt/acme/
|-> current@ -> /opt/acme/d4
|-> d1/
|-> d2/
|-> d3/
|-> d4/
| |-> db/
| | `-> production.sqlite3@ -> /opt/acme/persistent-data/db/production.sqlite3
| |-> config/
| | `-> database.yml@ -> /opt/acme/persistent-data/config/database.yml
| |-> log/
| | `-> production.log@ -> /opt/acme/persistent-data/log/production.log
| `-> tmp@ -> /opt/acme/persistent-data/tmp/
`-> persistent-data/
|-> db/
| `-> production.sqlite3
|-> config/
| `-> database.yml
|-> log/
| `-> production.log
`-> tmp/
Actions that must be performed before / after deployment and activation can be registered in hooks that can be shared by multiple applications. Before hooks can abort an operation by exiting with a non-null exit code.
As an example, one may want to use the following to deploy Ruby on Rails applications:
application::kind { 'rails':
before_activate => @(SH),
#!/bin/sh
set -e
RAILS_ENV=$ENVIRONMENT bundle exec rails db:migrate
| SH
after_activate => @(SH),
#!/bin/sh
touch tmp/restart.txt
| SH
}
application { 'website':
# ...
kind => 'rails',
}
The goal of this module is to allow building custom CD using GitLab and Choria. The misc directory features templates to help setup a CD container. This allows you to rely on GitLab Generic Packages Repository to push the packages you buisd and deploy them using short lived CI/CD job tokens. The following example build and deploy a new version of an application each time a new tag is pushed:
variables:
URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${CI_PROJECT_NAME}/${CI_COMMIT_TAG}/artifact.tar.gz"
package:
stage: package
only:
- tags
script:
- tar zcf /tmp/artifact.tar.gz --exclude .git .
- curl --fail --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file /tmp/artifact.tar.gz "${URL}"'
deploy:
stage: deploy
only:
- tags
needs:
- package
image:
name: registry.example.com/image-builder/mco
script: 'mco tasks run application::deploy --application=${CI_PROJECT_NAME} --environment=production --url="${URL}" --deployment_name="${CI_COMMIT_TAG}" --header="{\"JOB-TOKEN\": \"${CI_JOB_TOKEN}\"}" -C profile::${CI_PROJECT_NAME}'