Code, Deploy and manage your first App on Kubernetes

Introduction

Creating a k8s cluster is a nice thing but it’s better to use it 🙂
Here is a simple tutorial where I demonstrate how to quickly code and test an app.

Code the application

For this example we’ll use a simple http server written in Python.

#!/usr/bin/python
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

PORT_NUMBER = 8080

#This class will handles any incoming request from
#the browser
class myHandler(BaseHTTPRequestHandler):

#Handler for the GET requests
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
# Send the html message
self.wfile.write("Hello World - This is http python node test app v1 !")
return

try:
#Create a web server and define the handler to manage the
#incoming request
server = HTTPServer(('', PORT_NUMBER), myHandler)
print 'Started httpserver on port ' , PORT_NUMBER

#Wait forever for incoming htto requests
server.serve_forever()

except KeyboardInterrupt:
print '^C received, shutting down the web server'
server.socket.close()

Source : http://www.acmesystems.it/python_httpd

Test your app

Now that we have our application we can test it locally

python httpython.py
Started httpserver on port 8080

Result

curl http://localhost:8080
Hello World - This is http python node test app v1 !%

It works !

Create the container

Now in order to put our application on a kubernetes cluster we first need to create a container that contains our code.

Create the docker file

To create the container we define it in a Dockerfile

 

FROM python:2-onbuild
EXPOSE 8080
COPY httpython.py .
ENTRYPOINT [ "python", "./httpython.py" ]

FROM : specify the source image name. https://store.docker.com
EXPOSE : make the container listen on the specified port
COPY : copy file to destination (copy src dst)
ENTRYPOINT : specify the executable to be run we you start the container

Create a Requierment filetouch requirements.txt

touch requirements.txt

Build your docker container

docker build -t gcr.io/techfulab-testk8s-01/hello-py-node:v1 .

-t, –tag value Name and optionally a tag in the ‘name:tag’ format (default [])

Name your container with

  • gcr.io = google container repo
  • techfulab-testk8s-01 = Name of your project on GCP
  • hello-py-node : name of the container
  • v1 = version number/id

At the moment the container is build locally but this naming will help us later

Test locally

docker run -d -p 8080:8080 --name hello_tutorial gcr.io/techfulab-testk8s-01/hello-py-node:v1
⇒ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e483b5998d71 gcr.io/techfulab-testk8s-01/hello-py-node:v3 "python ./httpython.p" 5 seconds ago Up 3 seconds 0.0.0.0:8080->8080/tcp hello_tutorial

Test with :

curl http://localhost:8080
Hello World - This is http python node test app v1 !%

It works !

Push to Google cloud registry

gcloud docker -- push gcr.io/techfulab-testk8s-01/hello-py-node:v1

Deploy your application on Kubernetes

Now that we have our application containerised and pushed to google container registry we can deploy it to kubernetes

Create namespace

kubectl create namespace "team-01"

Change your config to use this namespace (rather than puttin –namespace team-01 at the end of every command)

kubectl config get-contexts
kubectl config set-context gke_techfulab-testk8s-01_europe-west1-d_techful-kops-cluster01 --namespace team-01

Deploy the application :

kubectl run hello-py-app --image=gcr.io/techfulab-testk8s-01/hello-py-node:v1 --port=8080 --replicas=2 --namespace team-01
Check status :
watch -n 1 kubectl get deployments
watch -n 1 kubectl get pods

Expose it :

kubectl expose deployment hello-py-app --type="LoadBalancer"

Check status :

watch -n 1 kubectl get services

Retrieve the Public IP and :

watch -n 1 curl http://$PUBLIC_IP:8080

Modify your deployment – Change the number of replica

kubectl scale deployment hello-py-app --replicas=4

Modify your deployment – Edit the deployment file

kubectl edit deployment/hello-py-app

Modify your deployment -Update the version of your app

Edit the local code (httpython.py) and change the message to display

...
# Send the html message
self.wfile.write("Hello World - This is http python node test app v2 !")
return
...

Build a new version of the container

docker build -t gcr.io/techfulab-testk8s-01/hello-py-node:v2 .

Test it locally

docker run -d -p 8080:8080 --name hello_tutorial gcr.io/techfulab-testk8s-01/hello-py-node:v2
curl http://localhost:8080


Hello World - This is http python node test app v2 !%

Push to Google cloud registry

gcloud docker -- push gcr.io/techfulab-testk8s-01/hello-py-node:v2

Update the version deployed

kubectl set image deployment/hello-py-app hello-node=gcr.io/techfulab-testk8s-01/hello-py-node:v2

Rollback

kubectl set image deployment/hello-py-app hello-node=gcr.io/techfulab-testk8s-01/hello-py-node:v1

Delete your application

kubectl delete service,deployment hello-py-app

Documentation/sources :

https://kubernetes.io/docs/hellonode/#create-a-docker-container-image
https://kubernetes.io/docs/user-guide/kubectl/kubectl_run/

Docker snippet

List old docker containers :

 docker ps --no-trunc -aq

Delete them :

docker rm `docker ps --no-trunc -aq`
Delete image :
docker rmi climz/apache
or with the id
docker rmi f8bfe5f3d6e8
Run docker with tty :
docker run -i -t ubuntu /bin/bash
Run docker container interactive with port redirect :
docker run -i -p 8000:80 -t djangosrv/latest /bin/bash
Create an image from a running container :
docker commit -m "Create nginx, uwsgi, supervisord server" -a "Julien"  3d1645041d69 climz/djangosrv:v1

DockerFile example

# This is a comment
FROM climz/djangosrv:v2
MAINTAINER Julien
RUN apt-get update && apt-get install
ADD supervisord.conf /home/bada/mysite/supervisord.conf
CMD ["/usr/bin/supervisord"]
EXPOSE 8000
Create a container from a docker file
docker build -t climz/djangosrv:v2 .

Run docker container as daemon :

docker run -P -d climz/djangosrv:v3
Where
-P redirect all expose port
-d daemonise

Connect to running docker

bash-4.4$ docker exec -it e38de44945ab /bin/bash