Kubernetes/Kubernetes Workshop/Step 2
Step 2 Outcomes
- Run a webserver application on kubernetes/minikube and the k8s networking concept of a service
- Learn about replicas - multiple instances of the application
- Entering a pod and logging
At the end you should known how to run a service on minikube.
Step 2 - Run a service application on k8s
K8s has extensive support for running service applications such as a web server, for example automated restarts, load balancing, dynamic scaling and others.
Let’s use a simple web server to explore some of the options.
Hands on: Make a docker image that serves a simple “Hello World” webpage.
Here is a step by step that uses the apache web server in the docker interactive mode.
We will base it on the ubuntu docker image.
- Bring up a base ubuntu image and log into the shell
docker run -it ubuntu /bin/bash
- Install apache
apt-get update && apt-get install apache2
- Replace index.html with Hello World or
apt-get install vim vi /var/www/html/index.html
echo "<HTML><BODY>Hello World</BODY></HTML>" > /var/www/html/index.html
- Start Apache - in Docker we typically want to run the server binary in the foreground and not exit as it will terminate the container, so:
apachectl -DFOREGROUND
- If you exit the shell on the docker container it stops running and you lose all work. You can save the progress by running the command docker commit in another window:
docker ps
# to find the id of the containerdocker commit <id> <name of new image>
docker image ls
# to check
- docker commit is also used to specify what binary to run on startup. In addition we need to tell the container what port is to be exposed to the outside world. See https://docs.docker.com/engine/reference/commandline/commit/ for more info.
docker commit --change='CMD ["/usr/sbin/apachectl", "-DFOREGROUND"]' --change='EXPOSE 80' <id> <name of new image>
- Finally run the container and map the network port to a local port
docker run -p 80:80 <name of new image>
- On the host machine:
curl http://localhost
will now get the page from the apache running in the container - One can “shell” into the container (for debugging for example, check the logs, etc) by
- docker exec -it <id> /bin/bash
- Debug, etc
- Ctrl-d or exit to leave the container
docker ps
to see what is runningdocker kill <id>
to terminate the container
Hands-on: make a Dockerfile for apache
Dockerfile:
FROM ubuntu
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y apache2
RUN echo '<HTML><BODY>Hello World</BODY></HTML>' >/var/www/html/index.html
EXPOSE 80
CMD ["apachectl","-DFOREGROUND"]
docker build .
builds the image- ENV noninteractive avoids the prompt for location
docker run -p 80:80 <container id>
- (If you have previously started a container using port 80 you will get an error that the
port is already allocated. In that case use “docker ps” and then “docker kill <id>” to shut it down.)
curl http://localhost
Hands-on: run service on minikube
Now let’s follow the same workflow on our k8s. We will publish the image on dockerhub, run it as a pod on the only node on minikube and then make it accessible from the outside by creating a service.
Copy the image to the docker hub and launch it in the local minikube.
- Create a repository “simpleapache” (by clicking the button on hub.docker.com)
- Tag the build:
docker tag <id> <your user>/simpleapache
- Upload
docker push <your user>/simpleapache
Sample output with user wkandek:
docker push wkandek/simpleapache:latest
The push refers to repository [docker.io/wkandek/simpleapache]
05ef66164473: Pushed
ab4765c94154: Pushed
5c7eeb133ba5: Pushed
095624243293: Mounted from library/ubuntu
a37e74863e72: Mounted from library/ubuntu
8eeb4a14bcb4: Mounted from library/ubuntu
ce3011290956: Mounted from library/ubuntu
latest: digest: sha256:84987f5e8d8fb51506fb0f8c3202b63e07409c8f9c3000a5e66eeced1c2ecda0 size: 1783
- minikube start to bring up minikube
kubectl run sa --image=<userid>/simpleapache --port=80
kubectl expose pod sa --type=LoadBalancer --port=80
- The pod named “sa” is exposed.
minikube service sa --url
- curl to the url given
To find out more information about the pods and the service, try these commands and see if the returned information makes sense.
kubectl get pods
kubectl get pods -o wide
kubectl get service
kubectl get service -o wide
kubectl describe pod sa
kubectl describe service sa
Hands-on: more replicas on minikube
To assure high availability we typically want to run more than one instance of a service. K8s makes that pretty easy. We have to use a new k8s object called a deployment and can then set the number of replicas we want, i.e. where before we just instructed K8s to run an image, we will now create a deployment object for the image and define its parameters, including the number of replicas.
kubectl create deployment <name> --image=<userid>/simpleapache
kubectl get pods
kubectl get deployments
kubectl describe deployment <name>
- Look for replicas for example
kubectl scale --current-replicas=1 --replicas=2 deployment sa
kubectl get pods
kubectl describe deployment <name>
- Look for replicas for example
And expose the web servers on the pods through a service
kubectl expose deployment sa --type=LoadBalancer --port=80
minikube service sa --url
- Curl on the URL returned to verify functioning
How can we enassure that both pods get exercised? Let’s change the page served on on of the pods
kubectl get pods
kubectl exec -it <one of the pods> -- /bin/bash
cd /var/www/html
echo "<HTML><BODY>Hello 2nd World</BODY></HTML>" > ./index.html
exit
minikube service sa --url
- Multiple curls on the URL executed to verify functioning. Sample Output:
$ curl http://172.17.0.2:30024
<HTML><BODY>Hello 2nd World</BODY></HTML>
$ curl http://172.17.0.2:30024
<HTML><BODY>Hello 2nd World</BODY></HTML>
$ curl http://172.17.0.2:30024
<HTML><BODY>Hello 2nd World</BODY></HTML>
$ curl http://172.17.0.2:30024
<HTML><BODY>Hello World</BODY></HTML
$ curl http://172.17.0.2:30024
<HTML><BODY>Hello 2nd World</BODY></HTML>
We could also look at the apache log files to see if both servers get hit. K8s has a way to look at the stdout of the pods by using the command kubectl logs, so if we configure apache to log to stdout we can use that to see the log files.
Here is a Dockerfile that redirects the access.log to stdout (the RUN for sed is 1 line including the /etc/apache/sites-available… So exercise a docker build ., local test with docker, docker logs to check, then tag, push to repo, and test on k8s:
kubectl get pods
kubectl logs <name of pod>
Dockerfile for apache with stdout instead of access log:
FROM ubuntu
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y apache2
RUN echo '<HTML><BODY>Hello World</BODY></HTML' >/var/www/html/index.html
RUN sed -r -i 's?\$\{APACHE_LOG_DIR\}/access.log?/dev/stdout?' /etc/apache2/sites-available/000-default.conf
EXPOSE 80
CMD ["apachectl","-DFOREGROUND"]
Once done, minikube can be shutdown with minikube stop.