πŸš€ My First Real K8s Deploy! Getting the Django Notes App Live (and Troubleshooting!)

Hritik RajHritik Raj
10 min read

Hey Hashnode fam! πŸ‘‹

There's nothing quite like that "Eureka!" moment when you deploy your first actual application to Kubernetes. All that YAML, all those concepts... suddenly, it just clicks! For me, that moment came when I decided to take a beloved simple project and launch it into the K8s universe.

I chose the fantastic LondheShubham153/django-notes-app! πŸ“ It's a straightforward Django app for managing notes – perfect for focusing on the Kubernetes side without getting bogged down in app complexity.

A huge shoutout to Shubham Londhe for creating this wonderfully clear repository and for his excellent way of teaching. It made this learning journey genuinely enjoyable! πŸ™

In this post, I'll walk you through how I got this app up and running using just three core Kubernetes YAMLs: namespace.yml, deployment.yml, and service.yml. And because learning means facing hiccups, I'll also share some common issues you might face and how to fix them! Let's get that app online! 🌐


Why Kubernetes for a Simple App? πŸ€”

You might be thinking, "K8s for a tiny notes app? Isn't that like using a rocket launcher to swat a fly?" πŸš€πŸ¦Ÿ

And yes, for a production scenario without complex needs, it might be overkill. But for learning, it's phenomenal! It forces you to understand:

  • How your app fits into a container.

  • How Kubernetes magically keeps it running.

  • How to expose it to the world.

  • The foundations of scalability and resilience (even if we're not fully showing it off here!).

It's like getting behind the wheel of a high-performance car on a simple track – you really get a feel for what it can do! πŸŽοΈπŸ’¨


The Project: LondheShubham153/django-notes-app πŸ“

Again, a big thank you to LondheShubham153 for this awesome little Django app!

  • What it is: A basic CRUD (Create, Read, Update, Delete) notes application built with Django.

  • Why it's great for K8s learning: It's simple, well-structured, and easy to containerize. For this initial deployment, we'll run it with its default SQLite database (which means notes won't stick around if your Pod restarts – but that's a "next step" to tackle!).

Before we deploy: You need to have this Django app in a Docker image and pushed to a registry (like Docker Hub) that your Kubernetes cluster can access.

You'd typically do: docker build -t yourdockerhubusername/django-notes-app:latest . then docker push yourdockerhubusername/django-notes-app:latest.


Our Kubernetes Building Blocks (The YAML Files)! 🧱

Let's peek into the magic spellbooks (YAML files) we'll use!

1. The Private Sandbox: namespace.yml πŸ–οΈ

First, a Namespace. Think of it as creating a dedicated, clean playroom for your app within the big Kubernetes house. It keeps your app's resources separate from others, preventing clutter and conflicts.

YAML

# namespace.yml
apiVersion: v1
kind: Namespace
metadata:
  name: django-notes-app-ns # Our dedicated sandbox for the notes app!

Why a Namespace? Good practice! It's like having separate folders for different projects on your computer. Keeps things tidy and easy to manage! πŸ“

2. The App Manager: deployment.yml πŸ§‘β€πŸ’»

This is where the real work happens! A Deployment tells Kubernetes: "Hey, run this specific app, always make sure you have X copies of it, and if one copy goes down, spin up a new one!"

YAML

# deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: notes-app-deployment
  namespace: django-notes-app-ns # Deploy this into our sandbox!
  labels:
    app: django-notes-app # A label for our app, used by the Service
spec:
  replicas: 1 # For simplicity, let's start with one copy of our app
  selector:
    matchLabels:
      app: django-notes-app # This Deployment will manage Pods with this label
  template: # This describes the Pods that the Deployment will create
    metadata:
      labels:
        app: django-notes-app # Assign this label to our Pods
    spec:
      containers:
      - name: django-notes-app-container
        image: yourdockerhubusername/django-notes-app:latest # 🚨 IMPORTANT: REPLACE WITH YOUR DOCKER IMAGE!
        ports:
        - containerPort: 8000 # Django's default development server port
        env: # Basic environment variables Django might need
        - name: DEBUG
          value: "True" # Set to "False" for production and configure ALLOWED_HOSTS!
        - name: DJANGO_SETTINGS_MODULE
          value: "notes_app.settings"
        # For production, you'd also need SECRET_KEY here (consider using a Kubernetes Secret!)

What's happening here?

  • We're defining a Deployment for our notes app inside the django-notes-app-ns Namespace.

  • We're asking for 1 replica (copy) of our app Pod. Kubernetes will ensure this copy is always running.

  • It pulls your Docker image (don't forget to replace the placeholder!).

  • Our Django app listens on port: 8000 inside its container.

3. The Stable Address: service.yml πŸ“ž

Pods are like nomads with ever-changing IPs. A Service gives them a stable, unchanging address and intelligently balances traffic if you have multiple copies. For this quick test, we'll use a NodePort Service to access our app from outside the cluster.

YAML

# service.yml
apiVersion: v1
kind: Service
metadata:
  name: notes-app-service
  namespace: django-notes-app-ns # Our Service lives in the same sandbox!
spec:
  selector:
    app: django-notes-app # This Service will route traffic to Pods with this label
  ports:
    - protocol: TCP
      port: 80 # The port the Service itself will listen on (clients will connect to this)
      targetPort: 8000 # The port our Django app is actually listening on inside the Pod
      nodePort: 30080 # (Optional) Kubernetes will open this specific port on EACH Node (range 30000-32767). Pick one not in use!
  type: NodePort # This type exposes our app via the Node's IP and a specific port

Why NodePort? For learning and quick demos, NodePort is super convenient! Kubernetes will open port 30080 (or another random one if you omit nodePort) on every server (Node) in your cluster. You can then access your app via ANY_NODE_IP:30080! 🌐


Let's Deploy! The Simple Steps! πŸš€

Before you start, make sure you have:

  • A running Kubernetes cluster (Minikube, Kind, Docker Desktop K8s, or a cloud cluster).

  • kubectl configured to connect to your cluster.

  • Your django-notes-app Docker image built and pushed to a public (or accessible) registry.

  1. Save the YAMLs: Copy the YAML snippets above into files named namespace.yml, deployment.yml, and service.yml in a dedicated directory.

  2. Create the Namespace:

    Bash

     kubectl apply -f namespace.yml
     # Expected Output: namespace/django-notes-app-ns created
    
  3. Deploy Your Application:

    Bash

     kubectl apply -f deployment.yml
     # Expected Output: deployment.apps/notes-app-deployment created
    

    Give it a few moments for Kubernetes to pull the image and create the Pod!

  4. Expose Your Application:

    Bash

     kubectl apply -f service.yml
     # Expected Output: service/notes-app-service created
    

Verify & Access Your App! πŸŽ‰

  1. Check all resources in your namespace:

    Bash

     kubectl get all -n django-notes-app-ns
    

    You should see your Pod(s), Deployment, and Service! All looking Running or Ready!

  2. Get your Service details (find that NodePort!):

    Bash

     kubectl get service notes-app-service -n django-notes-app-ns
    

    Look for the PORT(S) column. It should show something like 80:30080/TCP. The 30080 (or whatever nodePort was assigned) is your external port!

  3. Find your Node's IP:

    • If you're using Minikube: minikube ip

    • If you're using Docker Desktop K8s: Your Node IP is usually localhost or 127.0.0.1.

    • For cloud clusters: Get the public IP of any worker node (e.g., via kubectl get nodes -o wide).

  4. Access your app! Open your browser and go to:

    http://<YOUR_NODE_IP>:<NODE_PORT> (e.g., http://192.168.49.2:30080 or http://localhost:30080)

    Congratulations! You should see the Django Notes App running! πŸš€πŸ“


πŸ’₯ Common Issues You Might Face & How to Fix Them! 🩹

It's rare for a first deploy to go perfectly smooth. Here are some common hiccups and how to debug them! Don't get discouraged! πŸ’ͺ

1. ImagePullBackOff or ErrImagePull πŸ–ΌοΈβŒ

  • What it means: Kubernetes tried to pull your Docker image but failed.

  • Common Causes:

    • Typo in image name: You spelled yourdockerhubusername/django-notes-app:latest wrong.

    • Image not found: You didn't push the image, or it's a private registry and Kubernetes doesn't have credentials.

    • Incorrect tag: You used latest but pushed with v1.0.

  • How to Fix:

    1. Check Pod events: kubectl describe pod <pod-name> -n django-notes-app-ns (Look under "Events" section).

    2. Verify image name: Double-check your deployment.yml image field.

    3. Check registry: Is the image public? If private, you'll need a imagePullSecrets in your Deployment.

2. CrashLoopBackOff πŸ”„πŸ’₯

  • What it means: Your Pod started, but the container inside immediately crashed and Kubernetes is trying to restart it repeatedly.

  • Common Causes:

    • Application error: Your Django app has a bug that prevents it from starting.

    • Incorrect CMD or ENTRYPOINT in Dockerfile: The container isn't running the right command.

    • Missing environment variables: Your app needs specific env vars (SECRET_KEY, database URL) to start.

    • Port mismatch: Your app expects a different port than you exposed.

  • How to Fix:

    1. Check Pod logs: kubectl logs <pod-name> -n django-notes-app-ns (This is your #1 debugging tool!). Look for error messages from your Django app.

    2. Check Pod events: kubectl describe pod <pod-name> -n django-notes-app-ns (Look for "Liveness probe failed" or other errors).

    3. Review Dockerfile: Ensure your CMD or ENTRYPOINT correctly runs the Django development server (e.g., python manage.py runserver 0.0.0.0:8000).

    4. Environment Variables: For Django, make sure DEBUG is True for dev, and you set a SECRET_KEY (even a dummy one for local testing).

3. Service Not Accessible / No Endpoints πŸš«πŸ”—

  • What it means: Your Service is running, but it's not routing traffic to any Pods, or you can't access it from outside.

  • Common Causes:

    • Label mismatch: The selector in your service.yml doesn't exactly match the labels in your deployment.yml (or your Pods). This is a very common one!

    • targetPort incorrect: The targetPort in your Service doesn't match the containerPort your app is listening on.

    • Firewall/Security Group: Your cloud provider's firewall might be blocking the NodePort.

    • No running Pods: The Pods linked to the Service are in Pending or CrashLoopBackOff state.

  • How to Fix:

    1. Check Service Endpoints: kubectl get endpoints notes-app-service -n django-notes-app-ns. If the list is empty, no Pods are connected!

    2. Verify Labels: Triple-check that spec.selector.app in service.yml exactly matches spec.template.metadata.labels.app in deployment.yml.

    3. Verify Ports: Ensure service.yml targetPort matches deployment.yml containerPort.

    4. Check Pod Status: Use kubectl get pods -n django-notes-app-ns. Are they Running and Ready? If not, fix those first (see issues above).

    5. Firewall: If on a cloud VM, ensure the NodePort (e.g., 30080) is open in your VM's security group/firewall rules.

4. Pending Pods ⏳

  • What it means: Your Pods are stuck, waiting to be scheduled onto a Node.

  • Common Causes:

    • Not enough resources: The cluster doesn't have enough CPU or memory for your Pod.

    • Node Taints/Tolerations: Nodes might have specific restrictions your Pod can't meet.

    • Volume issues: If you were using Persistent Volumes (not in this simple deploy, but good to know!), storage might not be available.

  • How to Fix:

    1. Describe Pod: kubectl describe pod <pod-name> -n django-notes-app-ns. Look for messages like "Insufficient cpu" or "Insufficient memory" in the "Events" section.

    2. Check Node Resources: kubectl top nodes (if metrics server is installed) or kubectl describe node <node-name>.


What's Next? My K8s Learning Journey Continues! ⏭️

This deploy was just the start! For a production-ready Django app, you'd definitely want to explore:

  • Persistent Storage (Crucial for Django!): Using PersistentVolumeClaims and PersistentVolumes for your PostgreSQL/MySQL database so your notes actually stick around across Pod restarts! πŸ’Ύ

  • Database Deployment: Running a proper database (like PostgreSQL) also in Kubernetes (often using StatefulSets).

  • Ingress: Using an Ingress controller to expose your app on a proper domain name (e.g., notes.yourdomain.com) with HTTPS, instead of a raw IP and port.

  • Secrets & ConfigMaps: Securely managing database credentials, API keys, and other configurations. πŸ”‘

  • CI/CD: Automating the build, push, and deploy process! πŸ—οΈβž‘οΈπŸš€

  • Health Checks: Adding livenessProbe and readinessProbe to your Deployment to make it even more resilient.


This simple deployment was incredibly rewarding and clarified so many core Kubernetes concepts. If you're new to Kubernetes, I highly recommend picking a small, familiar app and trying to deploy it end-to-end. It makes all the theory truly click!

Have you had similar "A-Ha!" moments or faced other common K8s deployment issues? Share your experiences and tips in the comments below! πŸ‘‡ Let's learn and build awesome things together!


0
Subscribe to my newsletter

Read articles from Hritik Raj directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hritik Raj
Hritik Raj

πŸ‘‹ Hey there! I'm a university student currently diving into the world of DevOps. I'm passionate about building efficient, scalable systems and love exploring how things work behind the scenes. My areas of interest include: ☁️ Cloud Computing πŸ”§ Networking & Infrastructure πŸ›’οΈ Databases βš™οΈ Automation & CI/CD Currently learning tools like Docker, Kubernetes, and exploring various cloud platforms. Here to learn, build, and share my journey. Let’s connect and grow together! πŸš€