Search code examples
djangokubernetesmicrok8s

Django App not accessible on host machine when deployed on microk8s environment


I have a Django app that i previously was running using docker-compose that I am trying to test on MicroK8s. I used kompose to convert the docker-compose config to kubernetes.

This is the deployment definition.

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: kompose convert -f ../docker-compose.yml
    kompose.version: 1.31.2 (a92241f79)
  creationTimestamp: null
  labels:
    io.kompose.service: app
  name: app
spec:
  replicas: 1
  selector:
    matchLabels:
      io.kompose.service: app
  strategy:
    type: Recreate
  template:
    metadata:
      annotations:
        kompose.cmd: kompose convert -f ../docker-compose.yml
        kompose.version: 1.31.2 (a92241f79)
      creationTimestamp: null
      labels:
        io.kompose.network/bulabuy-build-default: "true"
        io.kompose.service: app
    spec:
      containers:
        - args:
            - sh
            - -c
            - |-
              python manage.py wait_for_db &&
                     python manage.py migrate &&
                     python manage.py runserver 0.0.0.0:8000
          env:
            - name: DB_HOST
              value: db
            - name: DB_NAME
              value: devdb
            - name: DB_PASSWORD
              value: password
            - name: DB_USER
              value: devuser
            - name: SELENIUM_HOST
              value: selenium-custom
            - name: SELENIUM_PORT
              value: "5000"
          image: bulabuy-build-app
          imagePullPolicy: Never
          name: app
          ports:
            - containerPort: 8000
              hostPort: 8000
              protocol: TCP
          resources: {}
          volumeMounts:
            - mountPath: /vol/web
              name: dev-static-data
      restartPolicy: Always
      volumes:
        - name: dev-static-data
          persistentVolumeClaim:
            claimName: dev-static-data
status: {}

This is the service definition:

apiVersion: v1
kind: Service
metadata:
  annotations:
    kompose.cmd: kompose convert -f ../docker-compose.yml
    kompose.version: 1.31.2 (a92241f79)
  creationTimestamp: null
  labels:
    io.kompose.service: app
  name: app
spec:
  ports:
    - name: "8000"
      port: 8000
      targetPort: 8000
  selector:
    io.kompose.service: app
status:
  loadBalancer: {}

This the output from the pods status (app-577dc6d4f4-cjcdw is the django app):

!Pods status: (https://i.sstatic.net/O3mpU.png)

This is the output from the service status: !Services status: (https://i.sstatic.net/iv6nh.png)

I tried to access the pod to run some checks on the app.. microk8s kubectl exec app-577dc6d4f4-cjcdw -- bash

This resulted in the following error:

Error from server: error dialing backend: tls: failed to verify certificate: x509: certificate is valid for 192.168.1.72, 172.20.0.1, 172.17.0.1, 172.18.0.1, 172.23.0.1, 172.22.0.1, 172.19.0.1, not 192.168.192.225

I also changed the service definition in the spec section to set type to NodePort and still could not access the app on the ip address listed in services.

I am not too sure what I am missing!. Any help with directions is appreciated.


Solution

  • I managed to get it to work. I cleaned up the deployment manifest for the django app.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: build-api
    spec:
      selector:
        matchLabels:
          app: build-api
      replicas: 1
      template:
        metadata:
          labels:
            app: build-api
        spec:
          containers:
            - name: build-api
              image: bulabuy-api
              imagePullPolicy: Never
              ports:
                - containerPort: 8000
              env:
                - name: DB_HOST
                  value: $(DEV_DB_SERVICE_SERVICE_HOST)
                - name: DB_NAME
                  value: devdb
                - name: DB_USER
                  value: devuser
                - name: DB_PASSWORD
                  value: password
                - name: SELENIUM_HOST
                  value: selenium-custom
                - name: SELENIUM_PORT
                  value: "5000"
                - name: DB_PORT
                  value: "5432"
    

    The django app pod was not able to connect to the database pod because the environment variable for DB_HOST was not reflecting the db pods actual ip. Kubernetes injects service environment variable for each service in the format <SERVICE NAME..>_SERVICE_HOST and so since my db service was named dev_db_service, kubernetes automatically injected an environment variable DEV_DB_SERVICE_SERVICE_HOST into my django-app deployment. And so in my django app deployment manifest, the value of the environment variiable DB_HOST references the injected environment variable which had the db host ip address.

    I also found out that I had to manually create the user for the database. In docker-compose simply setting the POSTGRES_USER and POSTGRES_PASSWORD created the db user but this did not work for me in microk8s. I had to access the pod via microk8s kubectl exec -it <db-pod-name..> -- bash and create the user manually. Once the db deployment and service manifests were correctly configured, I then applied the deployment for the django-app.

    This is the deployment manifest for the db.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: dev-db
    spec:
      selector:
        matchLabels:
          app: dev-db
      template:
        metadata:
          labels:
            app: dev-db
        spec:
          containers:
            - name: dev-db
              image: postgres:13-alpine
              ports:
                - containerPort: 5432
                  name: postgres
              volumeMounts:
                - mountPath: "/var/lib/postgresql/data"
                  name: dev-db-data-storage
              env:
                - name: POSTGRES_DB
                  value: devdb
                - name: POSTGRES_USER
                  value: devuser
                - name: POSTGRES_PASSWORD
                  value: password
          
          volumes:
            - name: dev-db-data-storage
              persistentVolumeClaim:
                claimName: dev-db-persistent-volume-claim
    

    This is the service manifest for the db..

    apiVersion: v1
    kind: Service
    metadata:
      name: dev-db-service
    spec:
      type: NodePort
      selector:
        app: dev-db
      ports:
        - name: "postgres"
          protocol: TCP
          port: 5432
          targetPort: 5432
          nodePort: 30432 
    

    Hope it helps someone facing the same issue..