You are browsing a read-only backup copy of Wikitech. The live site can be found at wikitech.wikimedia.org

Difference between revisions of "Kubernetes/Kubernetes Workshop/Step 2"

From Wikitech-static
Jump to navigation Jump to search
imported>Wolfgang Kandek
 
imported>Quiddity
m (lang="text")
 
(3 intermediate revisions by one other user not shown)
Line 1: Line 1:
== 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 ==
== Step 2 - Run a service application on k8s ==
Line 4: Line 11:


Let’s use a simple web server to explore some of the options.
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. ====
==== 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.
Here is a step by step that uses the apache web server in the docker interactive mode.
Line 10: Line 16:
We will base it on the ubuntu docker image.
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
* Bring up a base ubuntu image and log into the shell<syntaxhighlight lang="bash">
* Install apache  apt-get update && apt-get install apache2
docker run -it ubuntu /bin/bash
* Replace index.html with Hello World vi /var/www/html/index.html - vi not installed: apt-get install vim or maybe  echo "<HTML><BODY>Hello World</BODY></HTML>" > /var/www/html/index.html
</syntaxhighlight>
* 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:
* Install apache  <syntaxhighlight lang="bash">
** apachectl -DFOREGROUND
apt-get update && apt-get install apache2
</syntaxhighlight>
* Replace index.html with Hello World <syntaxhighlight lang="bash">
apt-get install vim
vi /var/www/html/index.html
 
 
</syntaxhighlight>or<syntaxhighlight lang="bash">
echo "<HTML><BODY>Hello World</BODY></HTML>" > /var/www/html/index.html
</syntaxhighlight>
* 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:<syntaxhighlight lang="bash">
apachectl -DFOREGROUND
</syntaxhighlight>


* 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:
* 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 container
** <code>docker ps</code> # to find the id of the container
** docker commit <id> <name of new image>
** <code>docker commit <id> <name of new image></code>
** docker image ls to check  
** <code>docker image ls</code> # 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.  <nowiki>https://docs.docker.com/engine/reference/commandline/commit/</nowiki>
* 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.
 
<syntaxhighlight lang="bash">docker commit --change='CMD ["/usr/sbin/apachectl", "-DFOREGROUND"]' --change='EXPOSE 80' <id> <name of new image></syntaxhighlight>
docker commit --change='CMD ["/usr/sbin/apachectl", "-D FOREGROUND"]' --change='EXPOSE 80'<id> <name of new image>


* Finally run the container and map the network port to a local port
* Finally run the container and map the network port to a local port
** docker run -p 80:80 <name of new image>
** <code>docker run -p 80:80 <name of new image></code>
** On the host machine: curl <nowiki>http://localhost</nowiki> will now get the page from the apache running in the container
** On the host machine: <code>curl <nowiki>http://localhost</nowiki></code> 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  
** One can “shell” into the container (for debugging for example, check the logs, etc) by  
*** docker exec -it <id> /bin/bash
*** docker exec -it <id> /bin/bash
*** Debug, etc
*** Debug, etc
*** Ctrl-d or exit to leave the container
*** Ctrl-d or exit to leave the container
** docker ps to see what is running
** <code>docker ps</code> to see what is running
** docker kill to terminate the container
** <code>docker kill <id></code>to terminate the container


==== Hands-on: make a Dockerfile for apache ====
==== Hands-on: make a Dockerfile for apache ====
Dockerfile:<syntaxhighlight lang="yaml">
Dockerfile:<syntaxhighlight lang="dockerfile">
FROM ubuntu
FROM ubuntu
ENV DEBIAN_FRONTEND=noninteractive
ENV DEBIAN_FRONTEND=noninteractive
Line 44: Line 61:
CMD ["apachectl","-DFOREGROUND"]
CMD ["apachectl","-DFOREGROUND"]
</syntaxhighlight>
</syntaxhighlight>
* docker build . builds the image
* <code>docker build .</code> builds the image
** ENV noninteractive avoids the prompt for location
** ENV noninteractive avoids the prompt for location
* docker run -p 80:80 <container id>
* <code>docker run -p 80:80 <container id></code>
* (If you have previously started a container using port 80 you will get an error that the
* (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.)
port is already allocated. In that case use “docker ps” and then “docker kill <id>” to shut it down.)


* curl <nowiki>http://localhost</nowiki>
* <code>curl <nowiki>http://localhost</nowiki></code>


==== Hands-on: run service on minikube ====
==== Hands-on: run service on minikube ====
Line 59: Line 76:


* Create a repository “simpleapache” (by clicking the button on hub.docker.com)
* Create a repository “simpleapache” (by clicking the button on hub.docker.com)
* Tag the build: docker tag <id> <your user>/simpleapache
* Tag the build: <code>docker tag <id> <your user>/simpleapache</code>
* Upload docker push <your user>/simpleapache:latest
* Upload <code>docker push <your user>/simpleapache</code>
 
 
Sample output with user wkandek:<syntaxhighlight lang="text">
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
</syntaxhighlight>
* minikube start to bring up minikube
* minikube start to bring up minikube
FROM ubuntu ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update RUN apt-get install -y apache2 RUN echo '<nowiki><HTML><BODY>Hello World</BODY></nowiki></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"]
* <code>kubectl run sa --image=<userid>/simpleapache --port=80</code>
* kubectl run sa --image=<userid>/simpleapache --port=80
* <code>kubectl expose pod sa --type=LoadBalancer --port=80</code>
* kubectl expose pod sa --type=LoadBalancer --port=80
** The pod named “sa” is exposed.
** The pod named “sa” is exposed.
* minikube service sa --url
* <code>minikube service sa --url</code>
* curl to the url given
* 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.
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  
* <code>kubectl get pods</code>
** kubectl get pods -o wide
** <code>kubectl get pods -o wide</code>
* kubectl get service
* <code>kubectl get service</code>
** kubectl get service -o wide
** <code>kubectl get service -o wide</code>
* kubectl describe pod sa
* <code>kubectl describe pod sa</code>
* kubectl describe service sa
* <code>kubectl describe service sa</code>


==== Hands-on: more replicas on minikube ====
==== 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.
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
* <code>kubectl create deployment <name> --image=<userid>/simpleapache</code>
* kubectl get pods
* <code>kubectl get pods</code>
* kubectl get deployments
* <code>kubectl get deployments</code>
* kubectl describe deployment <name>
* <code>kubectl describe deployment <name></code>
** Look for replicas for example
** Look for replicas for example
* kubectl scale --current-replicas=1 --replicas=2 deployment sa
* <code>kubectl scale --current-replicas=1 --replicas=2 deployment sa</code>
** kubectl get pods
** <code>kubectl get pods</code>
** kubectl describe deployment <name>
** <code>kubectl describe deployment <name></code>
*** Look for replicas for example
*** Look for replicas for example


And expose the web servers on the pods through a service
And expose the web servers on the pods through a service


* kubectl expose deployment sa --type=LoadBalancer --port=80
* <code>kubectl expose deployment sa --type=LoadBalancer --port=80</code>
* minikube service sa --url
* <code>minikube service sa --url</code>
* Curl on the URL returned to verify functioning
* 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
How can we enassure that both pods get exercised? Let’s change the page served on on of the pods


* kubectl get pods
* <code>kubectl get pods</code>
* kubectl exec -it <one of the pods> -- /bin/bash
* <code>kubectl exec -it <one of the pods> -- /bin/bash</code>
** cd /var/www/html
** <code>cd /var/www/html</code>
** echo "<HTML><BODY>Hello 2nd World</BODY></HTML>" > ./index.html
** <code>echo "<HTML><BODY>Hello 2nd World</BODY></HTML>" > ./index.html</code>
** exit
** <code>exit</code>
* minikube service sa --url
* <code>minikube service sa --url</code>
* Multiple curls on the URL executed to verify functioning. Sample Output:
* Multiple curls on the URL executed to verify functioning. Sample Output:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 125: Line 155:
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:
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
* <code>kubectl get pods</code>
* kubectl logs <name of pod>.
* <code>kubectl logs <name of pod></code>


Dockerfile for apache with stdout instead of access log:<syntaxhighlight lang="dockerfile">
Dockerfile for apache with stdout instead of access log:<syntaxhighlight lang="dockerfile">

Latest revision as of 02:09, 8 August 2021

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
    apt-get install vim
    vi /var/www/html/index.html
    
    or
    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 container
    • docker 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 running
    • docker 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.