Deploy wagtail
Enable the Cloud APIs
Create a template project
You’ll use the default Wagtail project template as your sample Wagtail project. To do this, you’ll temporarily install Wagtail to generate the template.
To create this template project, use Cloud Shell to create a new directory named wagtail-cloudrun
and navigate to it:
mkdir ~/wagtail-cloudrun
cd ~/wagtail-cloudrun
Then, install Wagtail into a temporary virtual environment:
virtualenv venv
source venv/bin/activate
pip install wagtail
Then, create a new template project in the current folder:
wagtail start myproject .
You’ll now have a template Wagtail project in the current folder:
ls -F
Dockerfile home/ manage.py* myproject/ requirements.txt search/ venv/
You can now exit and remove your temporary virtual environment:
deactivate
rm -rf venv
From here, Wagtail will be called within the container.
Create the backing services
Create a service account
Create an Artifact Registry
Create the database
In that same instance, create a user:
Grant the service account permission to connect to the instance:
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:${SERVICE_ACCOUNT} \
--role roles/cloudsql.client
Create the storage bucket
Create a Cloud Storage bucket (noting the name must be globally unique):
GS_BUCKET_NAME=${PROJECT_ID}-media
gcloud storage buckets create gs://${GS_BUCKET_NAME} --location ${REGION}
Grant permissions for the service account to administer the bucket:
gcloud storage buckets add-iam-policy-binding gs://${GS_BUCKET_NAME} \
--member serviceAccount:${SERVICE_ACCOUNT} \
--role roles/storage.admin
Since objects stored in the bucket will have a different origin (a bucket URL rather than a Cloud Run URL), you need to configure the Cross Origin Resource Sharing (CORS) settings.
Create a new file called cors.json
, with the following contents:
touch cors.json
cloudshell edit cors.json
cors.json
Apply this CORS configuration to the newly created storage bucket:
gsutil cors set cors.json gs://$GS_BUCKET_NAME
Store configuration as secret
Having set up the backing services, you’ll now store these values in a file protected using Secret Manager.
Secret Manager allows you to store, manage, and access secrets as binary blobs or text strings. It works well for storing configuration information such as database passwords, API keys, or TLS certificates needed by an application at runtime.
First, create a file with the values for the database connection string, media bucket, a secret key for Django (used for cryptographic signing of sessions and tokens), and to enable debugging:
echo DATABASE_URL=\"postgres://djuser:${DJPASS}@//cloudsql/${PROJECT_ID}:${REGION}:myinstance/mydatabase\" > .env
echo GS_BUCKET_NAME=\"${GS_BUCKET_NAME}\" >> .env
echo SECRET_KEY=\"$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 50 | head -n 1)\" >> .env
echo DEBUG=True >> .env
Then, create a secret called application_settings
, using that file as the secret:
gcloud secrets create application_settings --data-file .env
Allow the service account access to this secret:
gcloud secrets add-iam-policy-binding application_settings \
--member serviceAccount:${SERVICE_ACCOUNT} --role roles/secretmanager.secretAccessor
Confirm the secret has been created by listing the secrets:
gcloud secrets versions list application_settings
After confirming the secret has been created, remove the local file:
rm .env
Configure settings
Find the generated base.py
settings file, and rename it to basesettings.py
in the main myproject
folder:
mv myproject/settings/base.py myproject/basesettings.py
Using the Cloud Shell web editor, create a new settings.py
file, with the following code:
touch myproject/settings.py cloudshell edit myproject/settings.py
myproject/settings.py
Take the time to read the commentary added about each configuration.
Note that you may see linting errors on this file. This is expected. Cloud Shell does not have context of the requirements for this project, and thus may report invalid imports, and unused imports.
Then, remove the old settings folder.
rm -rf myproject/settings/
You will then have two settings files: one from Wagtail, and one you just created that builds from these settings:
ls myproject/settings
myproject/basesettings.py myproject/settings.py
Finally, open the manage.py
settings file, and update the configuration to tell Wagtail to point to the main settings.py
file.
cloudshell edit manage.py
manage.py line (before)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings.dev")
manage.py line (after)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
Make the same configuration change for the myproject/wsgi.py
file:
cloudshell edit myproject/wsgi.py
myproject/wsgi.py line (before)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings.dev")
myproject/wsgi.py line (after)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
Remove the automatically created Dockerfile:
rm Dockerfile
Python dependencies
Locate the requirements.txt
file, and append the following packages:
cloudshell edit requirements.txt
requirements.txt (append)
gunicorn psycopg2-binary django-storages[google] django-environ
Define your application image
Cloud Run will run any container as long as it conforms to the Cloud Run Container Contract. This tutorial opts to omit a Dockerfile
, but instead use Cloud Native Buildpacks. Buildpacks assist in building containers for common languages, including Python.
This tutorial opts to customize the Procfile
used to start the web application.
To containerize the template project, first create a new file named Procfile
in the top level of your project (in the same directory as manage.py
), and copy the following content:
touch Procfile cloudshell edit Procfile
Procfile
web: gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 myproject.wsgi:application
Create Cloud Run jobs
Now that the image exists, you can create Cloud Run jobs using it.
These jobs use the image previously built, but use different command values. These map to the values in the Procfile.
Create a job for the migration:
gcloud run jobs create migrate \
--region $REGION \
--image ${ARTIFACT_REGISTRY}/myimage \
--set-cloudsql-instances ${PROJECT_ID}:${REGION}:myinstance \
--set-secrets APPLICATION_SETTINGS=application_settings:latest \
--service-account $SERVICE_ACCOUNT \
--command migrate
Create a job for the user creation:
gcloud run jobs create createuser \
--region $REGION \
--image ${ARTIFACT_REGISTRY}/myimage \
--set-cloudsql-instances ${PROJECT_ID}:${REGION}:myinstance \
--set-secrets APPLICATION_SETTINGS=application_settings:latest \
--set-secrets DJANGO_SUPERUSER_PASSWORD=django_superuser_password:latest \
--service-account $SERVICE_ACCOUNT \
--command createuser
Execute Cloud Run jobs
With the job configurations in place, run the migrations:
gcloud run jobs execute migrate --region $REGION --wait
Ensure this command output says the execution “successfully completed”.
You will run this command later when you make updates to your application.
With the database setup, create the user using the job:
gcloud run jobs execute createuser --region $REGION --wait
Ensure this command output says the execution “successfully completed”.
You will not have to run this command again.
Deploy to Cloud Run
With the backing services created and populated, you can now create the Cloud Run service to access them.
The initial deployment of your containerized application to Cloud Run is created using the following command:
gcloud run deploy wagtail-cloudrun \
--region $REGION \
--image ${ARTIFACT_REGISTRY}/myimage \
--set-cloudsql-instances ${PROJECT_ID}:${REGION}:myinstance \
--set-secrets APPLICATION_SETTINGS=application_settings:latest \
--service-account $SERVICE_ACCOUNT \
--allow-unauthenticated
Wait a few moments until the deployment is complete. On success, the command line displays the service URL:
Service [wagtail-cloudrun] revision [wagtail-cloudrun-00001-...] has been deployed and is serving 100 percent of traffic.
Service URL: https://wagtail-cloudrun-...run.app
Retrieve your service URL:
CLOUDRUN_SERVICE_URLS=$(gcloud run services describe wagtail-cloudrun \
--region $REGION \
--format "value(metadata.annotations[\"run.googleapis.com/urls\"])" | tr -d '"[]')
echo $CLOUDRUN_SERVICE_URLS
Set this value as an environment variable on your Cloud Run service:
gcloud run services update wagtail-cloudrun \
--region $REGION \
--update-env-vars "^##^CLOUDRUN_SERVICE_URLS=$CLOUDRUN_SERVICE_URLS"
Logging into the Django Admin To access the Django admin interface, append /admin to your service URL.
Now log in with the username “admin” and retrieve your password using the following command:
gcloud secrets versions access latest --secret django_superuser_password && echo ""