Continuously Deploying DNS records with DnsControl and CircleCI
In the previous post, I gave a quick introduction to DnsControl, what it does and how it works. In this post, I'll show you how to continuously deploy your changes to Google Cloud DNS using CircleCI.
The goal is to have a Pipeline that works like this: On each push, run dnscontrol check to verify the file is valid, dnscontrol preview to make sure all configuration is correct (credentials, zones, ...). And if we're on the master branch (and the previous steps were succesful) dnscontrol push the changes to our DNS provider.
First, we need a container containing dnscontrol to run on CircleCI. Luckily for us there is an official one on Docker Hub: stackexchange/dnscontrol.
Next we need a .circleci/config.yml file:
version: 2
# Job definitions
jobs:
check:
docker:
- image: stackexchange/dnscontrol
steps:
- checkout
- run: dnscontrol check
preview:
docker:
- image: stackexchange/dnscontrol
steps:
- checkout
- run: dnscontrol preview
deploy:
docker:
- image: stackexchange/dnscontrol
steps:
- checkout
- run: dnscontrol push
# Definitions of the Workflow, our "Pipeline"
workflows:
version: 2
check-preview-deploy:
jobs:
- check
- preview
- deploy:
requires:
- check
- preview
filters: # only deploy from master branch
branches:
only: master
Now we have one problem left: We have to provide the credentials. Fortunately enough, the values in creds.json can contain ENV var names which dnscontrol then properly reads from the environment:
{
"gcloud": {
"type": "service_account",
"project_id": "$GCLOUD_PROJECT_ID",
"private_key": "$GCLOUD_PRIVATE_KEY",
"client_email": "$GCLOUD_CLIENT_EMAIL"
}
}
Unfortunately this did not work as expected. Google Cloud uses Private Key authentication for their service accounts, and I was not able to properly set an env var with the key in a for that dnscontrol could understand.
So instead I came up with something else:
- Create the
creds.jsonfile locally base64encode the file- On CircleCI, set an env var
$CREDSto the encoded string - During builds, decode and write the data to
creds.json
As only the preview and push commands require authentication, we only have to write the file during the preview and deploy jobs, for example:
# ...
deploy:
docker:
- image: stackexchange/dnscontrol
steps:
- checkout
- run: echo "$CREDS" | base64 -d > creds.json
- run: dnscontrol push
# ...
Bonus
Some people like to be a bit more careful, so they want to manually confirm a deployment. This can be done with a "hold" step in our workflow. Adjust the workflows section of the config.yml like this:
workflows:
version: 2
check-preview-hold-deploy:
jobs:
- check
- preview
- hold:
type: approval
requires:
- check
- preview
filters:
branches:
only: master
- deploy:
filters:
branches:
only: master
Now the workflow will pause after the check and preview steps.
Happy deploying continuously!