Skip to content

Latest commit

 

History

History
324 lines (259 loc) · 8.69 KB

2_building_running.adoc

File metadata and controls

324 lines (259 loc) · 8.69 KB

Step 2: Building Images & Running Containers

Namespaces

The resources (your apps) you create can be organized into namespaces which are particularly helpful when dealing with a larger team.

You can create a namespace via simple command

$ kubectl create namespace demo
$ kubectl get namespaces
NAME          STATUS    AGE
default       Active    22h
demo          Active    6m
kube-public   Active    21h
kube-system   Active    22h

The -o yaml trick is a great way to see what the command created

$ kubectl get namespace/demo -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: 2018-07-29T22:27:27Z
  name: demo
  resourceVersion: "21330"
  selfLink: /api/v1/namespaces/demo
  uid: 92a63dee-937e-11e8-9a0f-080027cd86aa
spec:
  finalizers:
  - kubernetes
status:
  phase: Active

You can also use the

kubectl get namespace/demo --export -o yaml

for something cleaner, something you might store and use later with kubectl apply -f

Deleting a Namespace is also available via command

$ kubectl delete namespace/demo

Your objects should be created via a file that can be checked into source control. Create a Namespace via yaml.

$ kubectl create -f kubefiles/myspace-namespace.yml # (1)
$ kubectl config set-context minikube --namespace=myspace # (2)
# or if you are using minishift and oc, there is a shortcut
$ oc project myspace
# or if you installed kubectx, try
# kubens myspace
  1. Using the yaml allows you to place this file in a source repository

  2. The setting of the context means you have to type -n myspace less often. Also, when using Minishift, "oc project myspace" is the equivalent command. In OpenShift projects = namespaces.

kubefiles/myspace-namespace.yml

You can confirm your context with

$ kubectl config view --minify --template '{{ index .contexts 0 "context" "namespace" }}'
# of if you are using minishift and oc then there is a handy shortcut
$ oc project
# or you can use kubens tool which comes with kubectx (brew install kubectx)
$ kubens

Code

Now that you have a Namespace, you need to craft some code

The "hello" directory contains several "hello world" style projects. Let’s use SpringBoot and run a quick test of the endpoint.

$ cd hello/springboot
$ mvn clean package
$ java -jar target/boot-demo-0.0.1.jar
$ curl localhost:8080

Next create the docker image, first double check that you are still connected to the correct Docker daemon.

Note : If using minikube, make sure you execute eval $(minikube docker-env) so docker knows to use the instance inside the minikube

$ eval $(minikube docker-env)
$ docker images | grep 9steps
$ docker build -t 9stepsawesome/myboot:v1 .

Test that docker image

$ minikube ip
$ docker run -it -p 8080:8080 9stepsawesome/myboot:v1
$ curl $(minikube ip):8080

Since the docker container is running "inside" the minikube/minishift VM, you need to use its IP address ctrl-c to terminate the Spring Boot process and its docker container.

Deployment

Next, deploy it as a pod inside of Kubernetes/OpenShift. You could use the "kubectl run" command but here we will use a Deployment

$ kubectl create -f kubefiles/myboot-deployment.yml

And then see what happened

$ kubectl get all
NAME                          READY     STATUS    RESTARTS   AGE
pod/myboot-79bfc988c8-ttz5r   1/1       Running   0          25s

NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/myboot   1         1         1            1           25s

NAME                                DESIRED   CURRENT   READY     AGE
replicaset.apps/myboot-79bfc988c8   1         1         1         25s

Service

Create a Service

$ kubectl create -f kubefiles/myboot-service.yml

Get the nodePort

$ kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}"

Curl that url + nodePort

$ curl $(minikube ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")

Perhaps build a little loop to curl that endpoint

while true
do
  curl $(minikube ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")
  sleep .5;
done

Scale

Let’s scale up the application to 3 replicas, there are several possible ways to achieve this result.

You can edit the myboot-deployment.yml, updating replicas to 3

$ kubectl replace -f kubefiles/myboot-deployment.yml

Or use the kubectl scale command

$ kubectl scale --replicas=3 deployment/myboot

Or you might patch it

$ kubectl patch deployment/myboot -p '{"spec":{"replicas":3}}'

Or use the kubectl edit command which essentially gives you "vi" for editing the deployment yaml

$ kubectl edit deployment/myboot
/replicas
esc-w-q

You can then use "kubectl get pods" to see the pods that have been created

$ kubectl get pods

Note: 3 pods might push you out of your memory limits for your VM. Check your memory usage with:

$ minishift ssh
# or
$ minikube ssh
$ free -m
$ top -o %MEM

Update

Update MyRESTController.java

greeting = environment.getProperty("GREETING","Bonjour");

Compile & Build the fat jar

mvn clean package

You can test with "java -jar target/boot-demo-0.0.1.jar" and "curl localhost:8080". Ideally, you would have unit tests executed with "mvn test" as well.

Build the new docker image with a v2 tag

$ docker build -t 9stepsawesome/myboot:v2 .
$ docker images | grep myboot

Rollout the update

$ kubectl set image deployment/myboot myboot=9stepsawesome/myboot:v2

And if you were running your polling curl command, you might see

Aloha from Spring Boot! 346 on myboot-79bfc988c8-ttz5r
Aloha from Spring Boot! 270 on myboot-79bfc988c8-ntb8d
Aloha from Spring Boot! 348 on myboot-79bfc988c8-ttz5r
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
curl: (7) Failed to connect to 192.168.99.105 port 31218: Connection refused
Bonjour from Spring Boot! 0 on myboot-757658fc4c-qnvqx
Bonjour from Spring Boot! 1 on myboot-5955897c9b-zthj9

We will be working on those errors when we address Liveness and Readiness probes in Step 7

For now, undo the update, going back to v1

$ kubectl rollout undo deployment/myboot

Scale to 1

$ kubectl scale --replicas=1 deployment/myboot

Hit the sysresources endpoint

$ curl $(minikube ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/sysresources
 Memory: 1324 Cores: 2

Note: you can use echo to see what this URL really looks like on your machine

$ echo $(minikube ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/sysresources
192.168.99.105:30479/sysresources

The results of the "sysresources" call should be about 1/4 memory and all the cores that were configured for the VM. You can double check this with the following command:

$ minikube config view
- cpus: 2
- memory: 6144
- vm-driver: virtualbox

Now, let’s apply resource contraints via Kubernetes & deployment yaml. Look at myboot-deployment-resources.yml

$ kubectl replace -f kubefiles/myboot-deployment-resources.yml

Curl sysresources again

$ curl $(minikube ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/sysresources
Memory: 1324 Cores: 2

In another terminal window, watch the pods

$ kubectl get pods -w

and now curl the consume endpoint

$ curl $(minikube ip):$(kubectl get service/myboot -o jsonpath="{.spec.ports[*].nodePort}")/consume

and you should see a OOMKilled

$ kubectl get pods -w
NAME                      READY     STATUS    RESTARTS   AGE
myboot-68d666dd8d-m9m5r   1/1       Running   0          1m
myboot-68d666dd8d-m9m5r   0/1       OOMKilled   0         2m
myboot-68d666dd8d-m9m5r   1/1       Running   1         2m

And you can also see the OOMKilled with the kubectl describe command

$ kubectl describe pod -l app=myboot
...
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Tue, 31 Jul 2018 13:42:18 -0400
      Finished:     Tue, 31 Jul 2018 13:44:24 -0400
    Ready:          True
    Restart Count:  1
...

Mystery to be solved in future steps!