Deploy Flask app to Kubernetes using Skaffold on Zarvis

In this post, we’ll deploy a simple Flask application.

  • Create a simple Flask application.
  • Build image and deploy to local kubernetes environment (minikube) using Skaffold.
  • Deploy the project to free hosted Kubernetes service Z.A.R.V.I.S. and get public URL endpoint.

TLDR

See complete example project here and follow the instructuions in README.md

https://github.com/zarvis-ai/zarvis-example-flask-skaffold

‘Hello world’ Flask application

Flask is a lightweight web application framework for Python.

Let’s create a simple Hello world Flask application.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello world!'

Save it in hello.py and let’s run locally.

FLASK_APP=hello.py flask run

The application will run on port 5000. Open your web browser and conncet http://localhost:5000. Let’s remember this port number to define Kubernetes Service later.

We’ll not go deep into Flask here while tons of good tutorials are on the internet.

Create Dockerfile

To deploy Hello world application on Kubernetes, we need to create a docker image. Let’s create a Dockerfile as follows.

FROM ubuntu:latest
RUN apt-get update -y
RUN apt-get install -y python-pip python-dev build-essential
RUN pip install Flask==1.0.2

ENV FLASK_APP hello.py

COPY . /app
WORKDIR /app

ENTRYPOINT ["flask"]
CMD ["run", "--host=0.0.0.0"]

The Dockerfile above is basically baking hello.py into the image and run flask run command. When this docker image is running on the container, Flask app will listen the default port 5000.

Create Kubernetes manifests

Now, we can create a Deployment and a Service to deploy docker image to Kubernetes cluster.

Let’s create a Deployment manifest yaml.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: flask-hello-world-deployment
spec:
  selector:
    matchLabels:
      app: flask-hello-world-app
  replicas: 2
  template:
    metadata:
      labels:
        app: flask-hello-world-app
    spec:
      containers:
      - name: flask-hello-world
        image: flask-hello-world-img

and save it in k8s-deployment.yaml.

Create a Service manifest. This file defines how kubernetes expose service ports of

kind: Service
apiVersion: v1
metadata:
  name: service       # Zarvis ingress looking for name 'service' by default
spec:
  ports:
  - name: http
    port: 8080        # Zarvis ingress looking for port '8080' by default
    targetPort: 5000  # Flask application default port
  selector:
    app: flask-hello-world-app

and save it in k8s-service.yaml file.

targetPort is 5000, because our Flask app is running on port 5000 inside the container. port is 8080, because Zarvis ingress connect ‘8080’ port of the Service by default.

Service name and port number that Zarvis ingress connect is configurable through zarvis.yaml. But we’ll use ‘service’ and ‘8080’ to use default configuration.

Create skaffold.yaml

Now, we can create a skaffold.yaml file as follows

apiVersion: skaffold/v1beta13
kind: Config
build:
  artifacts:
  - image: flask-hello-world-img # the same image name that is used in Deployment manifest
deploy:
  kubectl:
    manifests:
      - k8s-*

Run everything locally.

First, install and start minikube. And then, run

$ skaffold dev --port-forward

This command will build docker image, deploy it to local kubernetes cluster (minikube) and port forward to connect Service.

It’ll take some time for the first time to build image. After few minutes you’ll see outputs such as

Port forwarding service/flask-service in namespace default, remote port 8080 -> local port 8080
Watching for changes...
[flask-hello-world-deployment-5c59fcf987-pv5nl flask-hello-world]  * Serving Flask app "hello.py"
[flask-hello-world-deployment-5c59fcf987-pv5nl flask-hello-world]  * Environment: production
[flask-hello-world-deployment-5c59fcf987-pv5nl flask-hello-world]    WARNING: Do not use the development server in a production environment.
[flask-hello-world-deployment-5c59fcf987-pv5nl flask-hello-world]    Use a production WSGI server instead.
[flask-hello-world-deployment-5c59fcf987-pv5nl flask-hello-world]  * Debug mode: off
[flask-hello-world-deployment-5c59fcf987-pv5nl flask-hello-world]  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Let’s check Pods are deployed in the minikube. You’ll see two Pods are running, something similar to

$ kubectl get pods
NAME                                            READY   STATUS    RESTARTS   AGE
flask-hello-world-deployment-6845c6b646-bns6b   1/1     Running   0          11m
flask-hello-world-deployment-6845c6b646-lnpzx   1/1     Running   0          11m

Also check Service. You’ll see something like

$ kubectl get services
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
flask-service   ClusterIP   10.107.185.136   <none>        8080/TCP   16m

Looks like everything is up and running. Let’s browse http://localhost:8080.

Update your code

Skaffold automatically detect changes, rebuild and deploy. Let’s change Hello world! to Hello Skaffold! in hello.py and save.

You’ll see Skaffold rebuild docker image and deploy to minikube again. This time, rebuilding docker image is much faster.

To terminate, press <Ctrl> + C. Skaffold will delete Pods and Sevice from minikube.

Deploy to Zarvis.

Zarvis provides free Kubernetes namespace for all Github projects. Zarvis automatically deploys project with skaffold.yaml file.

First, let’s create a github repository and push all the files.

hello.py
Dockerfile
k8s-deployment.yaml
k8s-service.yaml
skaffold.yaml

And then sign in https://zarvis.ai

drawing

Press “Connect” button to connect the repository.

drawing

Deploy to Staging

Once your project is connected, select your project and click ‘Deploy’ button in the ‘Deploy’ tab.

drawing

Select branch (‘master’ in our case) and click ‘Deploy to Staging’ button. You’ll see Zarvis is building selected branch in Staging area.

Staging area is accessible only from Github members who has access to the repository. This is useful for development versions and release candidates.

drawing

In this step, Zarvis clone and build the docker image, push image to private registry hosted in Zarvis, and deploy the project to Kubernetes cluster hosted in Zarvis. After build & deploy complete, Zarvis removes cloned repository from its system.

drawing

Once the project is successfully deployed, you’ll see green check icon. Zarvis provides unique URL for each branch in the project. Click Then you can click the url and see your application running. Great!

Promote to production

You can promote multiple branches to productino area and get production URL. Requests to the production URL are distributed to branches in Production area.

To promote, click ‘Promote to production’ icon next to your branch name in Staging area.

drawing

You can get production URL from “Endpoints” section. Note that this production URL is still accessible only from Github members.

Make service public

To make production URL publicly accessible, select ‘Anonymous’ in ‘settings’ tab.

drawing

Your proudction URL is now publicly accessible!

Source codes

Example code in this article is in following github repository. Please fork and deploy to Zarvis!

https://github.com/zarvis-ai/zarvis-example-flask-skaffold