kubectl: The Kubernetes Client

Talk to your Cluster

echo $KUBECONFIG
kubectl config view

View Nodes

kubectl get nodes
kubectl get nodes --show-labels
kubectl get namespaces

View out-of-the-box Pods

Your Kubernetes vendor likely includes many pods out-of-the-box:

kubectl get pods --all-namespaces
kubectl get pods --all-namespaces --show-labels
kubectl get pods --all-namespaces -o wide

Deploy Something

Create a Namespace and Deploy something:

kubectl create namespace mystuff
kubectl config set-context --current --namespace=mystuff

kubectl create deployment myapp --image=quay.io/rhdevelopers/quarkus-demo:v1

while monitoring Events

watch kubectl get events --sort-by=.metadata.creationTimestamp
LAST SEEN   TYPE     REASON              OBJECT                        MESSAGE
<unknown>   Normal   Scheduled           pod/myapp-5dcbf46dfc-ghrk4    Successfully assigned mystuff/myapp-5dcbf46dfc-ghrk4 to g
cp-5xldg-w-a-5ptpn.us-central1-a.c.ocp42project.internal
29s         Normal   SuccessfulCreate    replicaset/myapp-5dcbf46dfc   Created pod: myapp-5dcbf46dfc-ghrk4
29s         Normal   ScalingReplicaSet   deployment/myapp              Scaled up replica set myapp-5dcbf46dfc to 1
21s         Normal   Pulling             pod/myapp-5dcbf46dfc-ghrk4    Pulling image "quay.io/burrsutter/quarkus-demo:1.0.0"
15s         Normal   Pulled              pod/myapp-5dcbf46dfc-ghrk4    Successfully pulled image "quay.io/burrsutter/quarkus-dem
o:1.0.0"
15s         Normal   Created             pod/myapp-5dcbf46dfc-ghrk4    Created container quarkus-demo
15s         Normal   Started             pod/myapp-5dcbf46dfc-ghrk4    Started container quarkus-demo

Created Objects

Deployments

kubectl get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
myapp   1/1     1            1           95s

Replicasets

kubectl get replicasets
NAME               DESIRED   CURRENT   READY   AGE
myapp-5dcbf46dfc   1         1         1       2m1s

Pods

kubectl get pods --show-labels
NAME                     READY   STATUS    RESTARTS   AGE     LABELS
myapp-5dcbf46dfc-ghrk4   1/1     Running   0          2m18s   app=myapp,pod-template-hash=5dcbf46dfc

Logs

kubectl logs -l app=myapp
2020-03-22 14:41:30,497 INFO  [io.quarkus] (main) Quarkus 0.22.0 started in 0.021s. Listening on: http://0.0.0.0:8080
2020-03-22 14:41:30,497 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

Expose a Service

kubectl expose deployment myapp --port=8080 --type=LoadBalancer

while watching Services

watch kubectl get services
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
myapp   LoadBalancer   172.30.103.41   <pending>     8080:31974/TCP   4s

Wait until you see an external IP assigned.

On Minikube without an Ingress controller, <pending> will not become a real external IP. Optional: Setup Minikube Ingress
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
myapp   LoadBalancer   172.30.103.41   34.71.122.153   8080:31974/TCP   44s

Talk to the App

  • Minikube

  • Hosted

IP=$(minikube ip -p devnation)
PORT=$(kubectl get service/myapp -o jsonpath="{.spec.ports[*].nodePort}")

If using a hosted Kubernetes cluster like OpenShift then use curl and the EXTERNAL-IP address with port 8080 or get it using kubectl:

IP=$(kubectl get service myapp -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
PORT=$(kubectl get service myapp -o jsonpath="{.spec.ports[*].port}")
If you are in AWS, you need to get the hostname instead of ip.
IP=$(kubectl get service myapp -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")

Curl the Service:

curl $IP:$PORT

Scale the App

Open three Terminal Windows.

Terminal 1

watch kubectl get pods

Terminal 2

  • Minikube

  • Hosted

IP=$(minikube ip -p devnation)
PORT=$(kubectl get service/myapp -o jsonpath="{.spec.ports[*].nodePort}")

If using a hosted Kubernetes cluster like OpenShift then use curl and the EXTERNAL-IP address with port 8080 or get it using kubectl:

IP=$(kubectl get service myapp -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
PORT=$(kubectl get service myapp -o jsonpath="{.spec.ports[*].port}")
If you are in AWS, you need to get the hostname instead of ip.
IP=$(kubectl get service myapp -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")

Curl the Service:

curl $IP:$PORT

Poll the endpoint:

while true
do curl $IP:$PORT
sleep 0.8
done

Results of the polling:

Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-ghrk4:289
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-ghrk4:290
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-ghrk4:291
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-ghrk4:292
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-ghrk4:293

Terminal 3

Change replicas:

kubectl scale deployment myapp --replicas=3
NAME                     READY   STATUS              RESTARTS   AGE
myapp-5dcbf46dfc-6sn2s   0/1     ContainerCreating   0          4s
myapp-5dcbf46dfc-ghrk4   1/1     Running             0          5m32s
myapp-5dcbf46dfc-z6hqw   0/1     ContainerCreating   0          4s

Start a rolling update by changing the image:

kubectl set image deployment/myapp quarkus-demo=quay.io/rhdevelopers/myboot:v1
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-6sn2s:188
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-z6hqw:169
Aloha from Spring Boot! 0 on myapp-58b97dbd95-vxd87
Aloha from Spring Boot! 1 on myapp-58b97dbd95-vxd87
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-6sn2s:189
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-z6hqw:170
Aloha from Spring Boot! 2 on myapp-58b97dbd95-vxd87
kubectl set image deployment/myapp quarkus-demo=quay.io/rhdevelopers/myboot:v2
Bonjour from Spring Boot! 2 on myapp-7d58855c6b-6c8gd
Bonjour from Spring Boot! 3 on myapp-7d58855c6b-6c8gd
Aloha from Spring Boot! 7 on myapp-58b97dbd95-mjlwx
Bonjour from Spring Boot! 4 on myapp-7d58855c6b-6c8gd
Aloha from Spring Boot! 8 on myapp-58b97dbd95-mjlwx
Bonjour from Spring Boot! 5 on myapp-7d58855c6b-6c8gd
kubectl set image deployment/myapp quarkus-demo=quay.io/rhdevelopers/quarkus-demo:v1
Bonjour from Spring Boot! 14 on myapp-7d58855c6b-dw67s
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-tcfwp:3
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-tcfwp:4
Bonjour from Spring Boot! 15 on myapp-7d58855c6b-dw67s
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-tcfwp:5
Bonjour from Spring Boot! 13 on myapp-7d58855c6b-72wp8
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-7rkxj:1
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-7rkxj:2
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-7lf9t:1
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-7rkxj:3
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-7lf9t:2
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-7lf9t:3
Supersonic Subatomic Java with Quarkus myapp-5dcbf46dfc-tcfwp:6

Clean Up

kubectl delete namespace mystuff
kubectl config set-context --current --namespace=default