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
-
Using the yaml allows you to place this file in a source repository
-
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
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.
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
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
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 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!