Skip to content

Publishing

This SOP guides you through publishing the Cannlytics platform to the web.

First, you will need to save your environment variables as a secret. Then, you may want to walk through the build process one time manually. Afterwards, publishing the website is done with one command:

npm run website:publish

Note, ensure that you have Docker running when you are publishing the website. You can check this by running docker ps in the command line. If you do not have Docker running, then you will see an error like:

error during connect: This error may indicate that the docker daemon is not running.

You will also need to authenticate with Google Cloud:

gcloud auth login
gcloud auth configure-docker

Create your secret environment variables

Open Google Cloud Shell and run the following command to ensure that you are working under the correct email and with the correct project:

gcloud init

Next, ensure that your project has billing enabled, then enable the Cloud APIs that are used:

gcloud services enable \
  run.googleapis.com \
  sql-component.googleapis.com \
  sqladmin.googleapis.com \
  compute.googleapis.com \
  cloudbuild.googleapis.com \
  secretmanager.googleapis.com

Create a secret with:

gcloud secrets create \
  cannlytics_lims_settings \
  --replication-policy automatic

Allow Cloud Run access to access this secret:

PROJECT_ID=$(gcloud config get-value project)
PROJECTNUM=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
CLOUDRUN=${PROJECTNUM}-compute@developer.gserviceaccount.com

gcloud secrets add-iam-policy-binding \
  cannlytics_lims_settings \
  --member serviceAccount:${CLOUDRUN} \
  --role roles/secretmanager.secretAccessor

Cloud Build will run Django commands, so Cloud Build will also need access to this secret:

PROJECT_ID=$(gcloud config get-value project)
PROJECTNUM=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
CLOUDBUILD=${PROJECTNUM}@cloudbuild.gserviceaccount.com

gcloud secrets add-iam-policy-binding \
  cannlytics_lims_settings \
  --member serviceAccount:${CLOUDBUILD} \
  --role roles/secretmanager.secretAccessor

Create a Cloud Storage bucket with a globally unique name:

REGION=us-central1
GS_BUCKET_NAME=${PROJECT_ID}-media
gsutil mb -l ${REGION} gs://${GS_BUCKET_NAME}

Then create your environment variables and save them to the secret in the Secret Manager console or with:

APP_ID=cannlytics
REGION=us-central1
DJPASS="$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 30 | head -n 1)"
echo DATABASE_URL=\"postgres://djuser:${DJPASS}@//cloudsql/${APP_ID}:${REGION}:cannlytics-sql/cannlytics-sql-database\" > .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=\"False\" >> .env
echo EMAIL_HOST_USER=\"your-email\" >> .env
echo EMAIL_HOST_PASSWORD=\"your-email-password\" >> .env
gcloud secrets versions add cannlytics_settings --data-file .env
rm .env

Set EMAIL_HOST_USER and EMAIL_HOST_PASSWORD with your email and app password. If you do not plan to use Django's email interface, then you exclude EMAIL_HOST_USER and EMAIL_HOST_PASSWORD.

You can confirm that the secret was created or updated with:

gcloud secrets versions list cannlytics_lims_settings

Finally, update your IAM policy for all project users to invoke cloud run:

gcloud beta run services add-iam-policy-binding --region=us-central1 --member=allUsers --role=roles/run.invoker your-lims

Helpful resources:

Deploying

The deployment contains three steps:

1. The app is containerized and uploaded to Container Registry.

First, set the project you want to work with:

gcloud config set project your-lims

You can build your container image using Cloud Build by running the following command from the directory containing the Dockerfile:

set PROJECT_ID=your-lims
set APP_ID=cannlytics
gcloud config set project %PROJECT_ID%
gcloud builds submit --tag gcr.io/%PROJECT_ID%/%APP_ID%

Note that your APP_ID must be in snake case.

You can list all the container images associated with your current project using this command:

gcloud container images list

2. The container image is deployed to Cloud Run.

Cannlytics uses a fully managed Cloud Run platform. Deploy the container to Cloud Run with:

set REGION=us-central1
gcloud run deploy %PROJECT_ID% --image gcr.io/%PROJECT_ID%/%APP_ID% --region %REGION% --allow-unauthenticated --platform managed

You can retrieve the service URL with:

gcloud run services describe your-lims \
  --platform managed \
  --region $REGION  \
  --format "value(status.url)"

Note, you will probably want to Configure cleanup policies for repositories to remove old images to save on cloud storage costs.

3. Hosting requests are directed to the containerized app.

This step provides access to this containerized app from a Firebase Hosting URL, so that the app can generate dynamic content for the Firebase-hosted site. You will need to have Firebase's command line tool installed:

npm install -g firebase-tools

Afterwards, you can login to Firebase in the command line with:

firebase login --reauth

Then, you can deploy the site with:

firebase deploy --project %PROJECT_ID% --only hosting:production

or

npm run deploy

Security rules

You can deploy a new set of security rules with the Firebase CLI.

firebase deploy --only firestore:rules

Monitoring

You can now monitor your app with the following tools.

Resource Description
Cloud Run Console Manage your app's container.
Logs Explorer Realtime logs for your app.
Error Reporting Provides detailed historic errors that occurred when running your app.

(Optional) Setup a Custom Domain

You can register a domain with Google Domains. You can then add a custom domain in the Firebase Hosting console.

If you are using Google Domains, then use '@' for your root domain name and 'www' or 'www.domain.com' for your subdomains when registering your DNS A records.

Conclusion

You now have a simple, yet complex, website running on Cloud Run, which will automatically scale to handle your website's traffic, optimizing CPU and memory so that your website runs with the smallest footprint possible, saving you money. If you desire, you can now seamlessly integrate services such as Cloud Storage into your Django website. You can now plug and play and tinker to your heart's content while your users enjoy your beautiful material!

Helpful Resources