Join us for an upcoming webinar on January 16, Get Started with Containers and Kubernetes, which will go through this exact content.
Getting Started with Containers and Kubernetes Workshop Kit Materials
This meetup kit is designed to help a technical audience become familiar with core Kubernetes concepts and practices.
The aim is to provide a complete set of resources for a speaker to host an event and deliver an introductory talk on containers and Kubernetes. It includes:
This tutorial is intended to supplement the talk demo with additional detail and elucidation. It also serves as a reference for readers seeking to get a minimal containerized Flask app up and running on DigitalOcean Kubernetes.
In the past decade, containerized applications and container clusters have rapidly replaced the old paradigm of scaling applications using virtual machines. Containers offer the same process isolation, but are generally more lightweight, portable, and performant than full virtualization. Container clusters, which can be used to manage thousands of running containers across a set of physical machines, abstract away much of the work of rolling out new versions of applications, scaling them, and efficiently scheduling workloads. Out of these, Kubernetes has emerged as a mature, production-ready system. It provides a rich set of features like rolling deployments, health checking, self-monitoring, workload autoscaling, and much, much more.
This tutorial, designed to accompany the Slides and speaker notes for the Getting Started with Kubernetes Meetup Kit, will show you how to harness these technologies and deploy the “Hello World” Flask app onto a DigitalOcean Kubernetes cluster.
To follow this tutorial, you will need:
- A Kubernetes 1.10+ cluster with role-based access control (RBAC) enabled. This setup will use a DigitalOcean Kubernetes cluster
kubectlcommand-line tool installed on your local machine or development server and configured to connect to your cluster. You can read more about installing
kubectlin the official documentation.
- Docker installed on your local machine or development server. If you are working with Ubuntu 18.04, follow Steps 1 and 2 of How To Install and Use Docker on Ubuntu 18.04; otherwise, follow the official documentation for information about installing on other operating systems. Be sure to add your non-root user to the
dockergroup, as described in Step 2 of the linked tutorial.
- A Docker Hub account (optional). For an overview of how to set this up, refer to this introduction to Docker Hub. You’ll only need a Docker Hub account if you plan on modifying the Flask Docker image described in this tutorial.
Step 1 — Cloning the App Repository and Building the Flask Image
To begin, clone the demo Flask app repo onto your machine, navigate into the directory, and list the directory contents:
- git clone https://github.com/do-community/k8s-intro-meetup-kit.git
- cd k8s-intro-meetup-kit
OutputLICENSE README.md app k8s
app directory contains the Flask demo app code, as well as the Dockerfile for building its container image. The
k8s directory contains Kubernetes manifest files for a Pod, Deployment, and Service. To learn more about these Kubernetes objects, consult the slide deck or An Introduction to Kubernetes.
Navigate into the
app directory and print out the contents of the
Outputfrom flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == "__main__": app.run(debug=True, host='0.0.0.0')
This code defines a single default route that will print “Hello World.” Additionally, the apps runs in debug mode to enable verbose output.
In a similar fashion,
cat out the contents of the app’s
OutputFROM python:3-alpine WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . EXPOSE 5000 CMD ["python", "app.py"]
This Dockerfile first sources a lightweight Alpine Linux Python parent image. It then copies in the Python requirements file, installs Flask, copies the app code into the container image, defines port
5000 as the container port, and finally sets the default command to
Next, build the app image:
- cd app
- docker build -t flask_demo:v0 .
We give the image a name,
flask_demo, and tag,
v0 using the
After Docker finishes the build, run the container using
- docker run -p 5000:5000 flask_demo:v0
This command runs a container using the
flask:v0 image, and forwards local port
5000 to container port
If you’re running Docker on your local machine, navigate to
http://localhost:5000 in your web browser. You should see “Hello World,” generated by the dockerized Flask app.
If you’re running Docker on a dev server, navigate instead to
http://dev_server_external_IP:5000. If you’re running a firewall like UFW, be sure to allow external access on port
5000. To learn more about doing this with UFW, consult UFW Essentials: Common Firewall Rules and Commands.
At this point you can experiment with Docker commands like
docker top, and
docker images to practice working with images and containers on your system.
In the next step, we’ll deploy this demo app to your Kubernetes cluster. We’ll use a prebuilt image shared publicly on Docker Hub. If you’d like to customize the Flask app and use your own image, you should create a Docker Hub account and follow the steps in this introduction to push your image to a public repository. From there, Kubernetes will be able to pull and deploy the container image into your cluster.
Step 2 — Deploying the Flask App on Kubernetes
The app and Docker image described in the previous step have already been built and made publicly available in the flask-helloworld Docker Hub repository. You can optionally create your own repository for the app and substitute it for
flask-helloworld throughout this step.
We’ll first deploy this demo “Hello World” app into our cluster as a standalone Pod, then as a multi-pod Deployment, which we’ll finally expose as a LoadBalancer Service. At the end of this tutorial, the “Hello World” app will be publicly accessible from outside of the Kubernetes cluster.
Before we launch any workloads into the cluster, we’ll create a Namespace in which the objects will run. Namespaces allow you to segment your cluster and limit scope for running workloads.
Create a Namespace called
- kubectl create namespace flask
Now, list all the Namespaces in your cluster:
You should see your new Namespace as well as some default Namespaces like
default. In this tutorial, we are going to exclusively work within the
Navigate back out to the
k8s directory in the demo repo:
In this directory, you’ll see three Kubernetes manifest files:
flask-pod.yaml: The app Pod manifest
flask-deployment.yaml: The app Deployment manifest
flask-service.yaml: The app LoadBalancer Service manifest
Let’s take a look at the Pod manifest:
OutputapiVersion: v1 kind: Pod metadata: name: flask-pod labels: app: flask-helloworld spec: containers: - name: flask image: hjdo/flask-helloworld:latest ports: - containerPort: 5000
Here, we define a minimal Pod called
flask-pod and label it with the
app: flask-helloworld key-value pair.
We then name the single container
flask and set the image to
flask-helloworld:latest from the
hjdo/flask-helloworld Docker Hub repository. If you’re using an image stored in a different Docker Hub repo, you can reference it using the
image field here. Finally, we open up port
5000 to accept incoming connections.
Deploy this Pod into the
flask Namespace using
kubectl apply -f and the
-n Namespace flag:
- kubectl apply -f flask-pod.yaml -n flask
After ten or so seconds, the Pod should be up and running in your cluster:
OutputNAME READY STATUS RESTARTS AGE flask-pod 1/1 Running 0 4s
Since this Pod is running inside of the Kubernetes cluster, we need to forward a local port to the Pod’s
containerPort to access the running app locally:
- kubectl port-forward pods/flask-pod -n flask 5000:5000
Here we use
port-forward to forward local port
5000 to the Pod’s
http://localhost:5000, where you should once again see the “Hello World” text generated by the Flask app. If you’re running
kubectl on a remote dev server, replace
localhost with your dev server’s external IP address.
Feel free to play around with
kubectl commands like
kubectl describe to explore the Pod resource. When you’re done, delete the Pod using
- kubectl delete pod flask-pod -n flask
Next, we’ll roll out this Pod in a scalable fashion using the Deployment resource. Print out the contents of the
flask-deployment.yaml manifest file:
- cat flask-deployment.yaml
OutputapiVersion: apps/v1 kind: Deployment metadata: name: flask-dep labels: app: flask-helloworld spec: replicas: 2 selector: matchLabels: app: flask-helloworld template: metadata: labels: app: flask-helloworld spec: containers: - name: flask image: hjdo/flask-helloworld:latest ports: - containerPort: 5000
Here, we define a Deployment called
flask-dep with an
app: flask-helloworld Label. Next, we request 2 replicas of a Pod template identical to the template we previously used to deploy the Flask app Pod. The
selector field matches the
app: flask-helloworld Pod template to the Deployment.
Roll out the Deployment using
kubectl apply -f:
- kubectl apply -f flask-deployment.yaml -n flask
After a brief moment, the Deployment should be up and running in your cluster:
- kubectl get deploy -n flask
OutputNAME READY UP-TO-DATE AVAILABLE AGE flask-dep 2/2 2 2 5s
You can also pull up the individual Pods that are managed by the Deployment controller:
OutputNAME READY STATUS RESTARTS AGE flask-dep-876bd7677-bl4lg 1/1 Running 0 76s flask-dep-876bd7677-jbfpb 1/1 Running 0 76s
To access the app, we have to forward a port inside of the cluster:
- kubectl port-forward deployment/flask-dep -n flask 5000:5000
This will forward local port
5000 to containerPort
5000 on one of the running Pods.
You should be able to access the app at
http://localhost:5000. If you’re running
kubectl on a remote dev server, replace
localhost with your dev server’s external IP address.
At this point you can play around with commands like
kubectl rollout and
kubectl scale to experiment with rolling back Deployments and scaling them. To learn more about these and other kubectl commands, consult a kubectl Cheat Sheet.
In the final step, we’ll expose this app to outside users using the LoadBalancer Service type, which will automatically provision a DigitalOcean cloud Load Balancer for the Flask app Service.
Step 3 — Creating the App Service
A Kubernetes Deployment allows the operator to flexibly scale a Pod template up or down, as well as manage rollouts and template updates. To create a stable network endpoint for this set of running Pod replicas, you can create a Kubernetes Service, which we’ll do here.
Begin by inspecting the Service manifest file:
OutputapiVersion: v1 kind: Service metadata: name: flask-svc labels: app: flask-helloworld spec: type: LoadBalancer ports: - port: 80 targetPort: 5000 protocol: TCP selector: app: flask-helloworld
This manifest defines a Service called
flask-svc. We set the type to
LoadBalancer to provision a DigitalOcean cloud Load Balancer that will route traffic to the Deployment Pods. To select the already running Deployment, the
selector field is set to the Deployment’s
app: flask-helloworld Label. Finally, we open up port
80 on the Load Balancer and instruct it to route traffic to the Pods’ containerPort
To create the Service, use
kubectl apply -f:
- kubectl apply -f flask-service.yaml -n flask
It may take a bit of time for Kubernetes to provision the cloud Load Balancer. You can track progress using the
-w watch flag:
Once you see an external IP for the
flask-svc Service, navigate to it using your web browser. You should see the “Hello World” Flask app page.