Wednesday, 13 February 2019

Playing with Kubernetes deployments and NodePort services

Today I'm fiddling with nginx as a workload on my IBM Kubernetes Service (IKS) cluster.

My default process was this: -

kubectl create deployment nginx --image=nginx

...
deployment.extensions "nginx" created
...

kubectl get deployments

...
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     1         1         1            1           20s
...

kubectl describe pod `kubectl get pods | grep nginx | awk '{print $1}'`

...
Events:
  Type     Reason             Age                From                     Message
  ----     ------             ----               ----                     -------
  Normal   Scheduled          39m                default-scheduler        Successfully assigned default/nginx-78f5d695bd-jxfvm to 192.168.132.123
...

kubectl create service nodeport nginx --tcp=80:80

...
service "nginx" created
...

kubectl get services

...
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   172.21.0.1              443/TCP        14d
nginx        NodePort    172.21.113.167          80:30923/TCP   20s
...

kubectl get nodes

...
  ROLES     AGE       VERSION
...
192.168.132.123   Ready          13d       v1.11.5
...

and then combine the public IP address of the node ( 192.168.132.123 ) and the generated NodePort ( 30923 ) to allow me to access nginx: -

curl http://192.168.132.123:30923

...
Welcome to nginx!

Welcome to nginx!

If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.

For online documentation and support please refer to
Commercial support is available at

Thank you for using nginx.
...

I also realised that I could "debug" the pod hosting the nginx service: -

docker ps -a

...
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS               NAMES
fda90a370446        nginx                  "nginx -g 'daemon of…"   19 seconds ago      Up 18 seconds                           k8s_nginx_nginx-78f5d695bd-8vrgl_default_d39dad7e-2f79-11e9-9f99-1201bf98c5fb_0
...

docker logs fda90a370446

...
10.23.2.59 - - [13/Feb/2019:10:30:42 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.54.0" "-"
...

However, I also "discovered" that there seems to be a correlation between the NAME of the NodePort service and the NAME of the nginx deployment.

If I create a NodePort service with a different name: -

kubectl create service nodeport foobar --tcp=80:80

and then get the newly created service: -

kubectl get services

...
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
foobar       NodePort    172.21.0.34          80:30952/TCP   1m
kubernetes   ClusterIP   172.21.0.1            443/TCP        14d
...

I'm no longer able to hit nginx: -

curl http://192.168.132.123:30952

returns: -

...
curl: (7) Failed to connect to 192.168.132.123 port 30952: Connection refused
...

If I delete the service: -

kubectl delete service foobar

...
service "foobar" deleted
...

and recreate it with the SAME name as the deployment: -

kubectl create service nodeport nginx --tcp=80:80

...
service "nginx" created
...

I'm back in the game: -

kubectl get services

...
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   172.21.0.1            443/TCP        14d
nginx        NodePort    172.21.31.44          80:30281/TCP   33s
...

curl http://192.168.132.123:30281

...
Welcome to nginx!

Welcome to nginx!

If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.

For online documentation and support please refer to
Commercial support is available at

Thank you for using nginx.
...

So there does APPEAR to be a correlation between the deployment name and the service name.

Obviously, K8S provides tagging for this, but I don't believe that's applicable to a NodePort service.

However, there is a different way ....

It is possible to expose an existing deployment and create a NodePort service "on the fly", as per the following: -

kubectl expose deployment nginx --type=NodePort --name=my-nginx --port 80

This creates a NodePort service: -

kubectl get services

...
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   172.21.0.1            443/TCP        14d
my-nginx     NodePort    172.21.8.192          80:30628/TCP   39s
...

NOTE that the name of the service - my-nginx - does NOT tie up with the deployment per se and yet ....

curl http://192.168.132.123:30281

...
Welcome to nginx!

Welcome to nginx!

If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.

For online documentation and support please refer to
Commercial support is available at

Thank you for using nginx.
...

If I dig into the newly created service: -

kubectl describe service my-nginx

Name:                     my-nginx
Namespace:                default
Labels:                   app=nginx
Annotations:              
Selector:                 app=nginx
Type:                     NodePort
IP:                       172.21.8.192
Port:                      80/TCP
TargetPort:               80/TCP
NodePort:                  30628/TCP
Endpoints:                172.30.148.204:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                  

I can see that it's tagged against the deployment - nginx - using the Label and Selector; I suspect that it's the latter that made the difference.

If I revert back to my previous service: -

kubectl create service nodeport nginx --tcp=80:80

...
service "nginx" created
...

and dig into it: -

kubectl describe service nginx

Name:                     nginx
Namespace:                default
Labels:                   app=nginx
Annotations:              
Selector:                 app=nginx
Type:                     NodePort
IP:                       172.21.68.125
Port:                     80-80  80/TCP
TargetPort:               80/TCP
NodePort:                 80-80  31411/TCP
Endpoints:                172.30.148.204:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                  

So the name of the service IS used to "tag" the target deployment.

If I misname my service: -

kubectl create service nodeport foobar --tcp=80:80

service "foobar" created

kubectl describe service foobar

Name:                     foobar
Namespace:                default
Labels:                   app=foobar
Annotations:              
Selector:                 app=foobar
Type:                     NodePort
IP:                       172.21.232.250
Port:                     80-80  80/TCP
TargetPort:               80/TCP
NodePort:                 80-80  32146/TCP
Endpoints:                
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                  

which explains why this does not: -

curl http://192.168.132.123:32146

In other words, the name of the service DOES MATTER, but only where one specifically creates the service, as opposed to letting the kubectl expose deployment do it for one.


No comments:

Note to self - use kubectl to query images in a pod or deployment

In both cases, we use JSON ... For a deployment, we can do this: - kubectl get deployment foobar --namespace snafu --output jsonpath="{...