Search code examples
nginxflaskkubernetesgunicorn

Deploying Flask app with Gunicorn behind Nginx on Kubernetes cluster


Is there any standard to deploy flask app with gunicorn and nginx on kubernetes cluster because I am trying to it by on dockerfile like below:

FROM nginx:latest as base-image
RUN apt update
RUN apt -y install python3 python3-pip
RUN apt -y install build-essential 

RUN mkdir /app
WORKDIR /app
COPY src src/
COPY src/.nginx/config /etc/nginx/conf.d/default.conf
COPY requirements.txt ./
RUN pip3 install -r requirements.txt

RUN pip3 install -e ./src
RUN pwd
RUN ls -l /app/src

# RUN pytest

EXPOSE 80

WORKDIR /app/src
CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT ["gunicorn" , "--bind","0.0.0.0:8000", "wsgi:app"]

Is the solution is to run two containers for each of gunicorn and nginx inside one pod of kubernetes?


Solution

  • Is the solution is to run two containers for each of gunicorn and nginx inside one pod of kubernetes?

    Yes. In Kubernetes or when simply running Docker on your local machine, it is always better to compose multiple containers rather than trying to stuff everything into a single container.

    This part of your your Dockerfile:

    CMD ["nginx", "-g", "daemon off;"]
    ENTRYPOINT ["gunicorn" , "--bind","0.0.0.0:8000", "wsgi:app"]
    

    Isn't doing what you seem to expect. These two directives operate in concert:

    • If defined, ENTRYPOINT is the command run by the container when it starts up.
    • The value of CMD is provided as an argument to the ENTRYPOINT script.

    You can read more about ENTRYPOINT in the official documentation.

    A better design would be to use the official Python image for your Python app:

    FROM python:3.10
    
    WORKDIR /app
    
    COPY src src/
    COPY requirements.txt ./
    RUN pip3 install -r requirements.txt
    RUN pip3 install -e ./src
    
    WORKDIR /app/src
    CMD ["gunicorn" , "--bind","0.0.0.0:8000", "wsgi:app"]
    

    And then use the official nginx image to run the nginx service.


    An example deployment that uses two containers, one for your Python app and one for Nginx, might look like:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: flask-example
      name: flask-example
    spec:
      selector:
        matchLabels:
          app: flask-example
      template:
        metadata:
          labels:
            app: flask-example
        spec:
          containers:
          - image: quay.io/larsks/example:flaskapp
            name: app
          - image: docker.io/nginx:mainline
            name: nginx
            ports:
            - containerPort: 80
              name: http
            volumeMounts:
            - mountPath: /etc/nginx/conf.d
              name: nginx-config
          volumes:
          - configMap:
              name: nginx-config-c65tttk45k
            name: nginx-config
    

    In the above deployment, we're mounting the configuration for nginx from a ConfigMap.

    You can find a complete deployable example of the above here.