qmkiwi
qmkiwi

Reputation: 135

Django deployed on GKE with Load Balancer cannot be accessed use External IP and Exposed Port

Basically I have this django app which has the pods and loadbalancer services running successfully in GKE. But I cannot access the app through the external IP in load balancer with the port.

Firstly here is my pods and load balancer status:

Justins-MacBook-Pro-166:Django-RealEstate qingyuan$ kubectl get svc polls
NAME    TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)          AGE
polls   LoadBalancer   10.108.2.157   104.155.130.204   8000:30575/TCP   3m24s
Justins-MacBook-Pro-166:Django-RealEstate qingyuan$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
polls-db68f9d76-8mgrw   2/2     Running   0          3m43s
polls-db68f9d76-k85rw   2/2     Running   0          3m43s
polls-db68f9d76-qjsbt   2/2     Running   0          3m43s

And here is my dockerfile:


FROM gcr.io/google_appengine/python
LABEL maintainer [email protected]

# Create a virtualenv for the application dependencies.
RUN virtualenv -p python3 /env
ENV PATH /env/bin:$PATH

#Prevents Python from writing pyc files to disc (equivalent to python -B option)#
ENV PYTHONDONTWRITEBYTECODE 1
# So the logs can always write to container logs and not get buffered at first place
ENV PYTHONUNBUFFERED 1

WORKDIR /app
ADD requirements.txt /app/requirements.txt
RUN /env/bin/pip install --upgrade pip && /env/bin/pip install -r /app/requirements.txt
ADD . /app

CMD gunicorn realestate.wsgi:application --bind 0.0.0.0:8000

here is my yml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: polls
  labels:
    app: polls
spec:
  replicas: 3
  # selector: when deployment create the pods, it will actually created by the kubernetes master
  # After the master create the pods, the deployment will ask: 'how do I know which of the pods are
  # the one I want?' Then the match label here tells the deployment object which pods belong to it
  selector:
    matchLabels:
      app: polls
  template:
    metadata:
      labels:
        app: polls
    spec:
      containers:
        - name: polls-app
          image: gcr.io/django-realestate/polls
          imagePullPolicy: Always
          env:
            - name: DATABASE_USER
              valueFrom:
                secretKeyRef:
                  name: cloudsql
                  key: username
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: cloudsql
                  key: password
          ports:
            - containerPort: 8080
        
        # container for cloudsql proxy
        - image: gcr.io/cloudsql-docker/gce-proxy:1.16
          name: cloudsql-proxy
          command: ["/cloud_sql_proxy", "--dir=/cloudsql",
                    "-instances=django-realestate:us-central1:myinstance=tcp:5432",
                    "-credential_file=/secrets/cloudsql/credentials.json"]
          # mount the volume from pods to container file system
          volumeMounts:
            - name: cloudsql-oauth-credentials
              mountPath: /secrets/cloudsql
              readOnly: true
            - name: ssl-certs
              mountPath: /etc/ssl/certs
            - name: cloudsql
              mountPath: /cloudsql
 
      volumes:
        - name: cloudsql-oauth-credentials
          secret:
            secretName: cloudsql-oauth-credentials
        - name: ssl-certs
          hostPath:
            path: /etc/ssl/certs
        - name: cloudsql
          emptyDir: {}

---
apiVersion: v1
kind: Service
metadata:
  name: polls
  labels:
    app: polls
spec:
  type: LoadBalancer
  selector:
    app: polls
  ports:
  # here I use the name to expose the port 8080 to 80
    - port: 8000
      targetPort: 8080
      protocol: TCP

Anyone can give some solutions or guidance I will be really appreciated! I have stuck this whole day finding solutions and test...

Upvotes: 3

Views: 475

Answers (1)

Dawid Kruk
Dawid Kruk

Reputation: 9905

TL;DR

You have a mismatch between the:

  • gunicorn on port 8000
    • CMD gunicorn realestate.wsgi:application --bind 0.0.0.0:8000
  • targetPort on port 8080
    • targetPort: 8080

To fix that you will need to change one of them to match the second one like:

  • gunicorn on port 8000
  • targetPort on port 8000 # <-- changed from 8080 to 8000.

I've included more explanation below.


Explanation

Focusing on the part of a YAML definition used to expose the app:

  type: LoadBalancer
  ports:
    - port: 8000 # <-- PORT TO CONNECT TO
      targetPort: 8080 # <-- PORT LISTENING ON POD 
      protocol: TCP

More on:

  • port - it's the port you need to send the traffic to when using a service (internally and externally).
  • targetPort - it's the port that a Pod is listening on (in your case 8000 from gunicorn)

Example:

Assuming that you have:

  • nginx pod listening on port 80
  • service associated with nginx pod with following parameters:
    • name: nginx-service
    • type: LoadBalancer
    • port: 1234
    • targetPort: 80

To access it from externals sources you would need to run:

  • $ curl EXTERNAL_IP:1234 - it will route the requests to the nginx pod to port 80.

A tip!

You could also connect to this service from internal sources by running:

  • $ curl nginx-service:1234

I also encourage you to check the additional resources:

Upvotes: 2

Related Questions