Example app using the Doge 🐕 workflow for continuous integration/deployment (CI/CD) to Digital Ocean.
- GNU Make
- terraform
- git >=2.28.0
- pre-commit
Optional:
- GitHub CLI (if you want to create the GitHub repository from the terminal).
You can install all the software requirements using conda (or mamba) and the environment.yaml
file provided in the root of the repository as follows:
conda env create -f environment.yaml
# and then work from the newly-created environment as in:
conda activate doge
- A DigitalOcean account. You can sign up using my referral link to get $100 in credit.
- A GitHub account.
- A Terraform Cloud account and a Terraform Cloud organization. With an active account, you can create an organization by navigating to app.terraform.io/app/organizations/new. You can also use an existing organization. This workflow is compatible with the free plan.
ACHTUNG
The Doge 🐕 workflow requires three access tokens, which must be set as terraform variables in the terraform/deploy/meta/vars.tfvars
file (note that to avoid disclosing sensitive information, this file is kept out of version control):
- DigitalOcean: navigate to cloud.digitalocean.com/account/api/token/new (you must be authenticated), choose a name and an expiration, click on "Generate Token" and copy the generated token as the value of the
do_token
variable. - GitHub: navigate to github.com/settings/tokens/new (you must be authenticated), choose a name, an expiration and select at least the
repo
andworkflow
permissions. Click on "Generate token" and copy the generated token as the value of thegh_token
variable. - Terraform Cloud: navigate to app.terraform.io/app/settings/tokens and click on "Create an API token", provide a description, click on "Create API token" and copy the generated token as the value of the
tf_api_token
variable.
The initial infrastructure provisioning in the Doge workflow is done by running Terraform locally with the help of GNU Make. This will set up the required GitHub infrastructure (notably repository secrets) so that the rest of the workflow is fully managed by GitHub Actions.
From the root of the generated project, use the following command to provision the meta workspace (i.e., a workspace to manage workspaces1, 2):
make init-meta
At this point, if you navigate to app.terraform.io/app/exaf-epfl/workspaces, a workspace named african-cities-journal-meta
should appear.
You can then plan and apply the Terraform setup as follows:
make plan-meta
make apply-meta
which will create three additional workspaces, named african-cities-journal-base
, african-cities-journal-stage
and african-cities-journal-prod
.
The GitHub repository can be created in two ways:
-
using the GitHub CLI (recommended): first, make sure that you are properly authenticated with the GitHub CLI (use the
gh auth login
command). Then, from the root of the generated project, runmake create-repo
, which will automatically initialize a git repository locally, add the first commit, and push it to a GitHub repository atmartibosch/african-cities-journal
. -
manually from the GitHub web interface: navigate to github.com/new, create a new empty repository at
martibosch/african-cities-journal
. Then, from the root of the generated project, initialize a git repository, setup pre-commit for the repository, add the first commit and push it to the new GitHub repository as follows:git init --initial-branch=main # this only works for git >= 2.28.0 pre-commit install git add . SKIP=terraform_validate git commit -m "first commit" git branch -M main git remote add origin [email protected]:martibosch/african-cities-journal git push -u origin main
Once the initial commit has been pushed to GitHub, use GNU Make to provision some base infrastructure:
make init-base
make plan-base
make apply-base
notably, a ssh key will be created and added to terraform, DigitalOcean (you can see a new item named african-cities-journal
at cloud.digitalocean.com/account/security, and repository secrets (you can see a repository secret named SSH_KEY
at github.com/martibosch/african-cities-journal/settings/secrets/actions). Additionally, a DigitalOcean project (an item named african-cities-journal
visible in the top-left "PROJECTS" menu of the web interface) will be created to group the resources used for this app.
The inital provisioning of the staging and production infrastructure must also be done using GNU Make following the Terraform init-plan-apply scheme, i.e., for the staging environment:
make init-stage
make plan-stage
make apply-stage
and for production:
make init-prod
make plan-prod
make apply-prod
If you navigate to cloud.digitalocean.com and select the african-cities-journal
project, you will see that droplets named african-cities-journal-stage
and african-cities-journal-prod
have been created for each environment respectively. Additionally, at github.com/martibosch/african-cities-journal/settings/secrets/actions), you will find an environment secret named DROPLET_HOST
, which contains the IPv4 address of the staging and production hosts respectively.
Once the initial infrastructure has been provisioned, CI/CD is ensured by the following GitOps workflow:
- New features are pushed into a dedicated feature branch.
- develop: a pull request (PR) to the
develop
branch is created, at which point CI workflow is run. If the CI workflow passes, the PR is merged, otherwise, fixes are provided in the feature branch until the CI workflow passes. - stage: once one or more feature PR are merged into the
develop
branch, they can be deployed to the staging environment by creating a PR to thestage
branch, which will trigger the "plan" workflow. If successful, the PR is merged, at which point the "deploy" workflow is run, which will deploy the branch contents to the staging environment. - main: after a successful deployment to staging, a PR from the stage to the main branch will trigger the "plan" workflow, yet this time for the production environment. Likewise, If the workflow passes, the PR can be merged, which will trigger the "deploy" workflow, which will deploy the branch contents to production.
Overall, the Doge 🐕 GitOps workflow can be represented as follows:
gitGraph:
commit id:"some commit"
branch stage
branch develop
branch some-feature
checkout some-feature
commit id:"add feature"
checkout develop
merge some-feature tag:"CI (lint, build)"
checkout stage
merge develop tag:"deploy stage"
checkout main
merge stage tag:"deploy prod"
The infrastructure provisioned by this setup can be destroyed using GNU Make as follows:
make destroy-prod
make destroy-stage
make destroy-base
make destroy-meta
1. "Managing Workspaces With the TFE Provider at Scale Factory"
2. response by chrisarcand in "Using variables with remote backend"