{"id":13449314,"url":"https://github.com/hnarayanan/kubernetes-django","last_synced_at":"2025-04-14T02:31:15.022Z","repository":{"id":149732910,"uuid":"51392248","full_name":"hnarayanan/kubernetes-django","owner":"hnarayanan","description":"Scalable and resilient Django with Kubernetes.","archived":false,"fork":false,"pushed_at":"2016-09-01T03:19:21.000Z","size":85,"stargazers_count":154,"open_issues_count":7,"forks_count":34,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-27T16:40:21.155Z","etag":null,"topics":["django","docker","kubernetes","tutorial"],"latest_commit_sha":null,"homepage":"http://harishnarayanan.org/writing/kubernetes-django/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hnarayanan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-02-09T19:16:06.000Z","updated_at":"2025-03-20T12:51:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"ce171aec-0c55-44e0-ad26-6d6f9d674249","html_url":"https://github.com/hnarayanan/kubernetes-django","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnarayanan%2Fkubernetes-django","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnarayanan%2Fkubernetes-django/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnarayanan%2Fkubernetes-django/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnarayanan%2Fkubernetes-django/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hnarayanan","download_url":"https://codeload.github.com/hnarayanan/kubernetes-django/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248810883,"owners_count":21165195,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","docker","kubernetes","tutorial"],"created_at":"2024-07-31T06:00:35.475Z","updated_at":"2025-04-14T02:31:14.755Z","avatar_url":"https://github.com/hnarayanan.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Scalable and resilient Django with Kubernetes\n\nThis repository contains code and notes to get a sample Django\napplication running on a Kubernetes cluster. It is meant to go along\nwith a [related blog post][blog-post] that provides more context and\nexplains some of the theory behind the steps that follow.\n\n## Preliminary steps\n\n1. Fetch the source code for this example.\n   ````\n   git clone https://github.com/hnarayanan/kubernetes-django.git\n   ````\n\n2. [Install Docker][docker-install].\n\n3. Take a look at and get a feel for the [example Django\napplication][example-app] used in this repository. It is a simple blog\nthat’s built following the excellent [Django Girls\nTutorial][django-girls-tutorial].\n\n4. [Setup a cluster managed by Kubernetes][kubernetes-install]. The\neffort required to do this can be substantial, so one easy way to get\nstarted is to sign up (for free) on Google Cloud Platform and use a\nmanaged version of Kubernetes called [Google Container Engine][GKE]\n(GKE).\n\n   1. Create an account on Google Cloud Platform and update your\n      billing information.\n\n   2. Install the [command line interface][gcp-sdk].\n\n   3. Create a project (that we'll refer to henceforth as\n      `$GCP_PROJECT`) using the web interface.\n\n   4. Now, we're ready to set some basic configuration.\n      ````\n      gcloud config set project $GCP_PROJECT\n      gcloud config set compute/zone europe-west1-d\n      ````\n\n   5. Then we create the cluster itself.\n      ````\n      gcloud container clusters create demo\n      gcloud container clusters list\n      ````\n\n   6. Finally, we configure `kubectl` to talk to the cluster.\n      ````\n      gcloud container clusters get-credentials demo\n      kubectl get nodes\n      ````\n\n## Create and publish Docker containers\n\nFor this example, we'll be using [Docker Hub](https://hub.docker.com/)\nto host and deliver our containers. And since we're not working with\nany sensitive information, we'll expose these containers to the\npublic.\n\n### PostgreSQL\n\nBuild the container, remembering to use your own username on Docker\nHub instead of `hnarayanan`:\n\n````\ncd containers/database\ndocker build -t hnarayanan/postgresql:9.5 .\n````\n\nYou can check it out locally if you want:\n\n````\ndocker run --name database -e POSTGRES_DB=app_db -e POSTGRES_PASSWORD=app_db_pw -e POSTGRES_USER=app_db_user -d hnarayanan/postgresql:9.5\n# Echoes $PROCESS_ID to the screen\ndocker exec -i -t $PROCESS_ID bash\n````\n\nPush it to a repository:\n\n````\ndocker login\ndocker push hnarayanan/postgresql:9.5\n````\n\n### Django app running within Gunicorn\n\nBuild the container:\n\n````\ncd containers/app\ndocker build -t hnarayanan/djangogirls-app:1.2-orange .\n````\n\nPush it to a repository:\n\n````\ndocker push hnarayanan/djangogirls-app:1.2-orange\n````\n\nWe're going to see how to perform rolling updates later in this\nexample. For this, let's create an alternative version of our app that\nsimply has a different header colour, build a new container app and\npush that too to the container repository.\n\n````\ncd containers/app\nemacs blog/templates/blog/base.html\n\n# Add the following just before the closing \u003c/head\u003e tag\n    \u003cstyle\u003e\n      .page-header {\n        background-color: #ac4142;\n      }\n    \u003c/style\u003e\n\ndocker build -t hnarayanan/djangogirls-app:1.2-maroon .\ndocker push hnarayanan/djangogirls-app:1.2-maroon\n````\n\n## Deploy these containers to the Kubernetes cluster\n\n### PostgreSQL\n\nEven though our application only requires a single PostgreSQL instance\nrunning, we still run it under a (pod) replication controller. This\nway, we have a service that monitors our database pod and ensures that\none instance is running even if something weird happens, such as the\nunderlying node fails.\n\n````\ncd  kubernetes/database\nkubectl create -f replication-controller.yaml\n\nkubectl get rc\nkubectl get pods\n\nkubectl describe pod \u003cpod-id\u003e\nkubectl logs \u003cpod-id\u003e\n````\n\nNow we start a service to point to the pod.\n\n````\ncd  kubernetes/database\nkubectl create -f service.yaml\n\nkubectl get svc\nkubectl describe svc database\n````\n\n### Django app running within Gunicorn\n\nWe begin with three app pods (copies of the orange app container)\ntalking to the single database.\n\n````\ncd kubernetes/app\nkubectl create -f replication-controller-orange.yaml\nkubectl get pods\n\nkubectl describe pod \u003cpod-id\u003e\nkubectl logs \u003cpod-id\u003e\n````\n\nThen we start a service to point to the pod. This is a load-balancer\nwith an external IP so we can access the site.\n\n````\ncd kubernetes/app\nkubectl create -f service.yaml\nkubectl get svc\n````\n\nBefore we access the website using the external IP presented by\n`kubectl get svc`, we need to do a few things:\n\n1. Perform initial migrations:\n   ````\n   kubectl exec \u003csome-app-orange-pod-id\u003e -- python /app/manage.py migrate\n   ````\n\n2. Create an intial user for the blog:\n   ````\n   kubectl exec -it \u003csome-app-orange-pod-id\u003e -- python /app/manage.py createsuperuser\n   ````\n\n3. Have a CDN host static files since we don't want to use Gunicorn\n   for serving these. This demo uses Google Cloud storage, but you're\n   free to use whatever you want. Just make sure `STATIC_URL` in\n   `containers/app/mysite/settings.py` reflects where the files are.\n   ````\n   gsutil mb gs://demo-assets\n   gsutil defacl set public-read gs://demo-assets\n\n   cd django-k8s/containers/app\n   virtualenv --distribute --no-site-packages venv\n   source venv/bin/activate\n   pip install Django==1.9.5\n   export DATABASE_ENGINE='django.db.backends.sqlite3'\n   ./manage.py collectstatic --noinput\n   gsutil -m cp -r static/* gs://demo-assets\n   ````\n\nAt this point you should be able to load up the website by visiting\nthe external IP for the app service (obtained by running `kubectl get\nsvc`) in your browser.\n\nGo to `http://app-service-external-ip/admin/` to login using the\ncredentials you setup earlier (while creating a super user), and\nreturn to the site to add some blog posts. Notice that as you refresh\nthe site, the name of the app pod serving the site changes, while the\ncontent stays the same.\n\n## Play around to get a feeling for Kubernetes' API\n\nNow, suppose your site isn't getting much traffic, you can gracefully\n*scale* down the number of running application pods to one. (Similarly\nyou can increase the number of pods if your traffic starts to grow!)\n\n````\nkubectl scale rc app-orange --replicas=1\nkubectl get pods\n````\n\nYou can check *resiliency* by deleting one or more app pods and see it\nrespawn.\n\n````\nkubectl delete pod \u003cpod-id\u003e\nkubectl get pods\n````\n\nNotice Kubernetes will spin up the appropriate number of pods to match\nthe last known state of the replication controller.\n\nFinally, to show how we can migrate from one version of the site to\nthe next, we'll move from the existing orange version of the\napplication to another version that's maroon.\n\nFirst we scale down the orange version to just one copy:\n\n````\nkubectl scale rc app-orange --replicas=1\nkubectl get pods\n````\n\nThen we spin up some copies of the new maroon version:\n\n````\ncd kubernetes/app\nkubectl create -f replication-controller-maroon.yaml\nkubectl get pods\n````\n\nNotice that because the app service is pointing simply to the label\n`name: app`, both the one orange and the three maroon apps respond to\nhttp requests to the external IP.\n\nWhen you're happy that the maroon version is working, you can spin\ndown all remaining orange versions, and delete its replication\ncontroller.\n\n````\nkubectl scale rc app-orange --replicas=0\nkubectl delete rc app-orange\n````\n\n## Cleaning up\n\nAfter you're done playing around with this example, remember to\ncleanly discard the compute resources we spun up for it.\n\n````\ngcloud container clusters delete demo\ngsutil -m rm -r gs://demo-assets\n````\n\n## And coming in the future\n\nFuture iterations of this demo will have additional enhancements, such\nas using a Persistent Volume for PostgreSQL data and learning to use\nKubernetes' Secrets API to handle secret passwords. Keep an eye on\n[the issues for this project][issues] to find out more. And you're\nfree to help out too!\n\n[blog-post]: https://harishnarayanan.org/writing/kubernetes-django/\n[docker-install]: https://docs.docker.com/engine/installation/\n[kubernetes-install]: http://kubernetes.io/docs/getting-started-guides/\n[example-app]: https://github.com/hnarayanan/kubernetes-django/tree/master/containers/app\n[django-girls-tutorial]: http://tutorial.djangogirls.org\n[GKE]: https://cloud.google.com/container-engine/\n[gcp-sdk]: https://cloud.google.com/sdk/\n[issues]: https://github.com/hnarayanan/kubernetes-django/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhnarayanan%2Fkubernetes-django","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhnarayanan%2Fkubernetes-django","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhnarayanan%2Fkubernetes-django/lists"}