Deploy a simple Python application with Kubernetes
Make sense of Kubernetes with a simple Python application that deploys to the IBM Cloud Kubernetes Service
Kubernetes has been out for a few years (its initial release was back in June 2014) and though the coding community is aware of and has heard about its greater capabilities, a lot of people still haven’t used it yet. If you’re not using Kubernetes yet, you’re not alone. Part of the hesitation stems from what I’ve heard a few developers say: that there is no proper guide available (meaning that there are such an overwhelming amount of articles out there, adding to the fact that they’re spread across multiple websites rather than in a single place) or they fear starting something new. In this tutorial, I aim to simplify things a bit for you by using the basic idea of building a Python application with Docker and deploying it to a Kubernetes service.
After completing this tutorial, you’ll be able to:
- Containerize a Flask application by using Docker and deploy it to the IBM Cloud Kubernetes Service.
In order to complete this tutorial, you’ll need the following prerequisites:
It should take around 45 minutes to complete this tutorial.
Create a Kubernetes cluster
- Sign in to your IBM Cloud Dashboard.
- Open IBM Kubernetes Service.
- Click Create Cluster.
- Select the Region where you want to deploy the cluster, type in a name for your cluster, then click Create Cluster.
- Depending on your account (Paid or Free), select the appropriate cluster type.
- It takes some time for the cluster to get ready (around 30 minutes).
- Once the cluster is ready, click on your cluster’s name and you will be redirected to a new page with information about your cluster and worker node.
- Click on the Worker Nodes tab to note the cluster’s Public IP.
Containerize your Flask application
- In your project directory, create a file named “Dockerfile.” Suggestion: Name your file exactly “Dockerfile,” nothing else.
A “Dockerfile” is used to indicate to Docker a base image, the Docker settings you need, and a list of commands you would like to have executed to prepare and start your new container.
In the file, paste this code:
FROM python:2.7 LABEL maintainer="Kunal Malhotra, firstname.lastname@example.org" RUN apt-get update RUN mkdir /app WORKDIR /app COPY . /app RUN pip install -r requirements.txt EXPOSE 5000 ENTRYPOINT [ "python" ] CMD [ "app.py" ]
Explanation and breakdown of the above Dockerfile code
The first part of the code above is:
Because this Flask application uses Python 2.7, we want an environment that supports it and already has it installed. Fortunately, DockerHub has an official image that’s installed on top of Ubuntu. In one line, we will have a base Ubuntu image with Python 2.7, virtualenv, and pip. There are tons of images on DockerHub, but if you would like to start off with a fresh Ubuntu image and build on top of it, you could do that.
Let’s look at the next part of the code:
LABEL maintainer="Kunal Malhotra, email@example.com" RUN apt-get update
Note the maintainer and update the Ubuntu package index. The command is
RUN, which is a function that runs the command after it.
RUN mkdir /app WORKDIR /app COPY . /app
Now it’s time to add the Flask application to the image. For simplicity, copy the application under the
/appdirectory on our Docker Image.
WORKDIRis essentially a cd in bash, and
COPYcopies a certain directory to the provided directory in an image.
ADDis another command that does the same thing as
COPY, but it also allows you to add a repository from a URL. Thus, if you want to clone your git repository instead of copying it from your local repository (for staging and production purposes), you can use that.
COPY, however, should be used most of the time unless you have a URL.
Now that we have our repository copied to the image, we will install all of our dependencies, which is defined in the
requirements.txtpart of the code.
RUN pip install --no-cache-dir -r requirements.txt
We want to expose the port(5000) the Flask application runs on, so we use
ENTRYPOINTspecifies the entrypoint of your application.
ENTRYPOINT [ "python" ] CMD [ "app.py" ]
Build an image from the Dockerfile
Open the terminal and type this command to build an image from your Dockerfile:
docker build -t <image_name>:<tag> . (note the period to indicate we’re in our apps top level directory). For example:
docker build -t app:latest .
Run your container locally and test
After you build your image succesfully, type:
docker run -d -p 5000:5000 app
This command will create a container that contains all the application code and dependencies from the image and runs it locally.
Push the image to the IBM Cloud Registry
- From your account dashboard, go to IBM Cloud Kubernetes Service.
From the left navigation menu, select Private Repositories.
Install the Container Registry plug-in.
ibmcloud plugin install container-registry -r "IBM Cloud"
Log in to your IBM Cloud account.
ibmcloud login -a <cloud_foundary_end_point_for_the_region>
Name and create your namespace. Use this namespace for the rest of the Quick Start.
ibmcloud cr namespace-add <namespace>
Log your local Docker daemon into the IBM Cloud Container Registry.
ibmcloud cr login
Choose a repository and tag by which you can identify the image.
docker tag <image_name> <region_url>/<namespace>/<image_name>:<tag>
Push the image.
docker push <region_url>/<namespace>/<image_name>:<tag>
Verify that your image is in your private registry.
ibmcloud cr image-list
Create configuration files for Kubernetes
Once the image is successfully uploaded to the private registry, go to your project directory and create two files: deployment.yaml and service.yaml.
In the deployment.yaml file, paste this code:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: flask-node-deployment spec: replicas: 1 selector: matchLabels: app: flasknode template: metadata: labels: app: flasknode spec: containers: - name: flasknode image: registry.ng.bluemix.net/flask-node/app imagePullPolicy: Always ports: - containerPort: 5000
In the service.yaml file, paste this code:
apiVersion: v1 kind: Service metadata: name: flask-node-deployment spec: ports: - port: 5000 targetPort: 5000 selector: app: flasknode
Explanation and breakdown of the deployment.yaml code
- A deployment named
flask-node-deploymentis created, indicated by the
- The deployment creates one replicated pod, indicated by the
- The selector field defines how the Deployment finds which Pods to manage. In this case, we simply select on one label defined in the Pod template (app:
flasknode). However, more sophisticated selection rules are possible, as long as the Pod template itself satisfies the rule.
- The pod template’s specification,
.template.spec, indicates that the pods run one container,
flasknode, which runs the app private registry image.
- The deployment opens
port 5000for use by the Pods.
Explanation and breakdown of the service.yaml code
service.yaml‘s specification will create a new service object named
flask-node-deploymentwhich targets TCP port 5000 on any Pod with the “app=flasknode” label. This Service will also be assigned an IP address (sometimes called the
cluster IP), which is used by the service proxies (see below). The Service’s selector will be evaluated continuously and the results will be POSTed to an Endpoints object also named
Note that a service can map an incoming port to any targetPort. By default the targetPort will be set to the same value as the port field. Perhaps more interesting is that targetPort can be a string, referring to the name of a port in the backend Pods. The actual port number assigned to that name can be different in each backend Pod. This offers a lot of flexibility for deploying and evolving your Services. For example, you can change the port number that pods expose in the next version of your backend software, without breaking clients.
Deploy your application to Kubernetes
Target the IBM Cloud Kubernetes Service region where you want to work.
ibmcloud cs region-set us-south
Set the context for the cluster in your CLI.
a. Get the command to set the environment variable and download the Kubernetes configuration files.
ibmcloud cs cluster-config cluster_kunal
b. Set the KUBECONFIG environment variable. Copy the output from the previous command and paste it in your terminal. The command output should look similar to the following.
> export KUBECONFIG=/Users/$USER/.bluemix/plugins/container-service/clusters/< cluster_name >/< cluster_configuration_file.yaml>
Verify that you can connect to your cluster by listing your worker nodes.
kubectl get nodes
Create the deployment.
kubectl create -f deployment.yaml
Create the service.
kubectl create -f service.yaml
Look at the Kubernetes dashboard from the IBM Kubernetes Service overview page.
Finally, go to your browser and ping the Public IP of your worker node.
Resources and references
- Kubernetes Documentation
- Deploy a microservices app on IBM Cloud by using Kubernetes
- Tutorial: Deploying apps into clusters