<leftside.dev>
<menu>
</menu>
<title>
WordPress CDN - Django Cloud Deployment
</title>
<content>

This post will cover the steps I went through to get my django docker app deployed to the cloud infrastructure.

I've decided to try Google Cloud for this project, so I'll be using Google Cloud Run to run my containerised application.

I began with the getting started guide, using a containerised version of the Google Cloud SDK.

Following the Google recommendation regarding project authentication, I ran the following command:

docker run -it --name volume-name gcr.io/google.com/cloudsdktool/google-cloud-cli gcloud auth login

and used the interactive terminal to complete login for the project. This creates a container volume named volume-name which will contain the authenticated Google Cloud credentials. I can then use that volume to attach to containers in the future and run commands that are automatically authenticated with my project.

I then created a quick helper script gcloud.sh to assist in running the various cloud commands:

#!/usr/bin/env bash

docker run -it \
  --platform linux/amd64 \
  --volumes-from volume-name \
  -v "`pwd`":/app \
  -w /app \
  gcr.io/google.com/cloudsdktool/google-cloud-cli \
  gcloud "$@"

This meant I could run commands such as ./gcloud.sh run deploy to deploy my container, instead of having to remember the above command, and mounting that volume, all the time.

You probably want to change volume-name for each project, so you can isolate all settings related to your project within that volume.

I came across the usual hiccups you might expect when first attempting to deploy. Namely, Cloud Run had permission to build the container and upload it to a Cloud Storage bucket, but didn't have permissions to then pull that image in order to deploy it. Fixing up some service account permissions took care of all of that, and I was able to deploy.

In the future, I'll need to figure out how to automate all of that so it isn't a manual step I need to perform, but for now I'll just use the manual steps to get it running.

Environment Variables and Secrets

The next hurdle is environment variables. I've written the django application to expect certain variables, such as the domain of the instance and the database connection details, to be present. For local development, I use docker compose, which allows me to set the environment configuration key against the django container to control the environment. When running in the Google Cloud, I need to use a combination of environment variables and secrets to control these variables.

This process has also highlighted a number of settings that I'll need to control via environment variables that are currently hard-coded:

  • ALLOWED_HOSTS
  • SECRET_KEY
  • DEBUG

The list of allowed hosts and the debug flag can both be easily set via environment variables, but the secret key for the site must be introduced via a secret (duh).

Adding environment variables and secrets to the project was another painless exercise, as each container has an Environment Variables section where you can directly enter key-value pairs (such as DEBUG=False) which are then available within the container at runtime.
Secrets are (necessarily) slightly more complicated than environment variables, but still painless. To add secrets you can upload an environment variable file into the Secret Manager, and then load that file "into" the containter, by selecting it as an available secret. With secrets, you can either mount the file as a volume, or expose the secrets as environment variables. I chose the second option for my secrets. The file format is as follows:

SECRET_KEY=...
DATABASE_URL=...
...

Then you simply need to give your container service user permission to read this secret file, and you're off to the races.

This pretty much finishes off this part of the article. At this point, I can deploy my container to the Cloud and get it running. Next steps require configuring a database, running manage.py commands, mounting a cloud filesystem, continuous deployment through git integration. I have separate articles for each of those.

</content>
</leftside.dev>