Working With Services

Kubernetes Services

Here are more notes while learning Kubernetes, now it is about Services:


Imperative Way

Given the following manifest for a Deployment:

❯ cat deploy.yml
apiVersion: apps/v1
kind: Deployment  <<<======
metadata:
  name: svc-test  <<<<=====
spec:
  replicas: 10
  selector:
    matchLabels:
      chapter: services
  template:
    metadata:
      labels:
        chapter: services
    spec:
      containers:
      - name: hello-ctr
        image: nigelpoulton/k8sbook:1.0
        ports:
        - containerPort: 8080

First, we will create this one in a declarative way:
❯ kubectl apply -f deploy.yml
deployment.apps/svc-test created
❯ kubectl get deployment
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
hello-deploy   10/10   10           10          8d
svc-test       10/10   10           10          5m30s <<<======= 

Now that the “svc-test” Deployment is running, we can add a Service for it. (Again, in a imperative way):

❯ kubectl expose deployment svc-test --type=NodePort
service/svc-test exposed
❯ kubectl get svc -o wide
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE     SELECTOR
kubernetes       ClusterIP   10.96.0.1      <none>        443/TCP          38d     <none>
svc-test         NodePort    10.96.46.88    <none>        8080:34937/TCP   2m35s   chapter=services  

From the previous output we can interpret the following:

  • The firt line, “kubernetes” service is a system Service that exposes the Kubernetes API on the cluster.
  • svc-test is our Service. Notice how this took the name of the Deployment.
  • Notice that the label was also taken from the svc-test Deployment.

If we want more details about the Service, we can use the following:

❯ kubectl describe svc svc-test
Name:                     svc-test
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 chapter=services
Type:                     NodePort   
IP Families:              <none>
IP:                       10.96.46.88 <<==== Internal ClusterIP
IPs:                      10.96.46.88
Port:                     <unset>  8080/TCP   <<<====== Listening port on ClusterIP.
TargetPort:               8080/TCP            <<<====== Listening port on application
NodePort:                 <unset>  34937/TCP  <<<====== Listening port on Node.
Endpoints:                192.168.255.77:8080,192.168.255.79:8080,192.168.255.80:8080 + 7 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Additionally, if we want to check the list of endpoints available for this Service:

❯ kubectl get endpoints
NAME         ENDPOINTS                                                                 AGE
kubernetes   10.0.112.3:12388,10.0.115.129:12388,10.0.142.193:12388                    38d
svc-test     192.168.255.77:8080,192.168.255.79:8080,192.168.255.80:8080 + 7 more...   21m
❯ kubectl get endpointslices
NAME             ADDRESSTYPE   PORTS   ENDPOINTS                                                  AGE
kubernetes       IPv4          12388   10.0.112.3,10.0.115.129,10.0.142.193                       38d
svc-test-2kmq8   IPv4          8080    192.168.255.82,192.168.255.83,192.168.255.79 + 7 more...   21m

Notice how the second output provides the PORTS column.


Declarative Way (Kubernetes prefered way)

Given the following Service manifest:

❯ cat svc.yml
apiVersion: v1
kind: Service  <<<=======
metadata:
  name: svc-test
  labels:
    chapter: services
spec:
  type: NodePort  <<<=====
  ports:
  - port: 8080
    nodePort: 32768
    targetPort: 8080
    protocol: TCP
  selector:
    chapter: services

We can create the Service which includes an exposed port already, so no need to use “kubectl expose” as we did previously:

❯ kubectl apply -f svc.yml
service/svc-test created
❯ kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP          38d
svc-test     NodePort    10.96.41.50   <none>        8080:32768/TCP   9s

Notice the PORT column listing the available port on the node where we could externally (coming outside the cluster, via Internet) access the applicationn.


Last, we can take a look at the endpoints associated to this Service:
❯ kubectl describe endpointslices svc-test-zsqnf
Name:         svc-test-zsqnf
Namespace:    default
Labels:       chapter=services
              endpointslice.kubernetes.io/managed-by=endpointslice-controller.k8s.io
              kubernetes.io/service-name=svc-test
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2022-03-25T13:49:13Z
AddressType:  IPv4
Ports:
  Name     Port  Protocol
  ----     ----  --------
  <unset>  8080  TCP
Endpoints:
  - Addresses:  192.168.64.80 
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/svc-test-84db6ff656-fmccs
    Topology:   kubernetes.io/hostname=mke-node-1
  - Addresses:  192.168.255.80 
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/svc-test-84db6ff656-ccxzb
    Topology:   kubernetes.io/hostname=mke-node-0
  - Addresses:  192.168.64.81
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/svc-test-84db6ff656-j7frk
    Topology:   kubernetes.io/hostname=mke-node-1
    .
    .
    (TRUNCATED OUTPUT)
    .

LoadBalancer Services

Given the below manifest, we can create the cloud-lb Service (LoadBalance type):

❯ cat lb.yml
apiVersion: v1
kind: Service
metadata:
  name: cloud-lb
spec:
  type: LoadBalancer  <<<======
  ports:
  - port: 9000
    targetPort: 8080
  selector:
    chapter: services
❯ kubectl apply -f lb.yml
service/cloud-lb created
❯ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
cloud-lb     LoadBalancer   10.96.213.57   <pending>     9000:33351/TCP   37s   <<<====
kubernetes   ClusterIP      10.96.0.1      <none>        443/TCP          38d
svc-test     NodePort       10.96.41.50    <none>        8080:32768/TCP   27m

The EXTERNAL-IP colum should show the public IP for the load balancer cloud to access. In my case, it seems there is something pending to fix.

 Share!

 
comments powered by Disqus