Deploying Django on Google Kubernetes Engine - Lessons learned

In general it is quite easy to deploy a django web application on Google Cloud Platform using Google Kubernetes Engine (GKE). Google provides a very good tutorial on getting started with Django on GKE.

The tutorial covers all the basic aspects, gives you a sample application and explains the deployment step by step including how to use a cloud SQL instance as database backend and how to serve static files from a cloud storage bucket.

However, when deploying Django on Google Kubernetes Engine we encountered a few subtle issues which we would like to cover in this blog post.

GCE Ingress vs Nginx Ingress

In your kubernetes setup, an ingress object might be used to route external traffic to services in your cluster. An ingress also provides load balancing and SSL termination. When following along the tutorials on Google Cloud Platform you will find that a GCE ingress is used as a default.

However, there are certain limitations with the GCE ingress and depending on the situation it might be beneficial to use nginx ingress instead: The nginx ingress is more cloud agnostic and also offers a wider range of settings (e.g. authentication). For each GCE ingress a new load balancer is created which might result in higher cost compared to a nginx-based controller where you have only one service of type LoadBalancer.

If you come to the conclusion that the nginx ingress better suits your need than an installation of nginx-ingress using helm is probably the simplest solution.

Setting up Logging for Django using Stackdriver on GCP

In order to efficiently monitor microservices on Kubernetes it is required to collect logs from running containers. Google Cloud Platform offers a tool called Stackdriver that aggregates logs from containers, stores them in a single location, allows searching logs and even creates simple dahsboard. Strackdriver also integrates well with Django logging.

A typical entry in the settings.py file of your Django project could look like the following code snippet:

 

from google.cloud import logging as google_cloud_logging
log_client = google_cloud_logging.Client()
log_client.setup_logging()

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'stackdriver': {
            'class': 'google.cloud.logging.handlers.CloudLoggingHandler',
            'client': log_client,
        }
    },
    'loggers': {
        '': {
            'handlers': ['stackdriver'],
            'level': 'INFO',
        }
    },
}

 

Depending on the situation you might want to use a environment variable that switches between different logging handlers. This would allow you to use console logging for the application when you run it locally, using docker-compose for instance. When the application runs in the cloud, logging would then switch to Stackdriver.