Certified Kubernetes Application Developer - CKAD

Services Networking

Solution Services optional

In this article, we walk through a practical lab solution for managing Kubernetes services. We cover listing services, inspecting service details, reviewing deployments, and exposing a web application using a NodePort service. This guide is ideal for Kubernetes administrators and developers looking to understand service management in-depth.

Listing Kubernetes Services

To determine how many services exist on the system, run the following commands:

kubectl get service

You can also use the shorthand:

kubectl get svc

The output is similar to:

kubectl get service
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.43.0.1     <none>        443/TCP    10m

This output confirms that only one service exists—the default Kubernetes service. You can verify this with both commands:

controlplane ~ ⟩ kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.43.0.1     <none>       443/TCP    10m

controlplane ~ ⟩ kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.43.0.1     <none>       443/TCP    10m

controlplane ~ ⟩

Note

The default service is automatically created by Kubernetes and represents the API server.

Checking the Service Type

From the output, you can observe that the service type is ClusterIP:

controlplane ~ ¬ kubectl get service
NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes  ClusterIP   10.43.0.1     <none>        443/TCP    10m

controlplane ~ ¬ kubectl get svc
NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes  ClusterIP   10.43.0.1     <none>        443/TCP    10m

controlplane ~ ¬

Later, we will explore the role of the API server in more detail. For now, think of this service like any other Kubernetes service you create.

Determining the Target Port

Next, we determine the target port configured on the Kubernetes service by using the kubectl describe command:

controlplane ~ ⚡ kubectl get service
NAME        TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes  ClusterIP  10.43.0.1    <none>        443/TCP    10m

controlplane ~ ⚡ kubectl get svc
NAME        TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes  ClusterIP  10.43.0.1    <none>        443/TCP    10m

controlplane ~ ⚡ kubectl describe svc kubernetes
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.43.0.1
IPs:               10.43.0.1
Port:              <unset>
TargetPort:        6443/TCP
Endpoints:         10.53.180.9:6443
Session Affinity:  None
Events:            <none>

controlplane ~  ↣

This output shows that the service receives traffic on port 443 and forwards it to the target port 6443.

Examining Service Labels

Review the labels configured on the Kubernetes service by examining its description. You will see two labels:

  • component: apiserver
  • provider: kubernetes

These labels confirm that this service is associated with the Kubernetes API server. For more detailed insights, especially in preparation for the Certified Kubernetes Application Developer (CKAD) exam, further examination of the API server is recommended.

Inspecting Service Endpoints

Endpoints represent the Pod IPs where the service directs traffic. To inspect them, run:

controlplane ~ ⚡ kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.43.0.1     <none>        443/TCP    10m

controlplane ~ ⚡ kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.43.0.1     <none>        443/TCP    10m

controlplane ~ ⚡ kubectl describe svc kubernetes
Name:                     kubernetes
Namespace:                default
Labels:                   component=apiserver
                          provider=kubernetes
Annotations:              <none>
Selector:                 <none>
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.43.0.1
IPs:                      10.43.0.1
Port:                     https 443/TCP
TargetPort:               6443/TCP
Endpoints:                10.53.180.9:6443
Session Affinity:         None
Events:                   <none>

controlplane ~ ✗

The output confirms there is one endpoint: 10.53.180.9:6443.

Understanding Endpoints

Endpoints are dynamically determined based on the labels and selectors defined in a service specification. When a service is created, it monitors Pods that match its specified selector. If there is a misconfiguration, the service could unintentionally attach extra endpoints, or conversely, none at all if labels are mismatched.

In our example, the service directs traffic to a single endpoint.

Exploring Deployments

Next, let's examine the deployments in the default namespace.

Counting Deployments

List the deployments with:

kubectl get deploy

The output shows that there is one deployment deployed.

Checking the Container Image

To verify the container image used within the deployment, inspect the deployment details:

controlplane ~ ➜ kubectl get deploy
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
simple-webapp-deployment   0/4     4            0           15s

controlplane ~ ➜ kubectl describe deploy simple-webapp-deployment
Name:                   simple-webapp-deployment
Namespace:              default
CreationTimestamp:      Fri, 15 Apr 2022 20:35:47 +0000
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               name=simple-webapp
Replicas:               4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  name=simple-webapp
  Containers:
    simple-webapp:
      Image: kodekloud/simple-webapp:red
      Port: 8080/TCP
      Host Port: 0/TCP
      Environment: <none>
      Mounts: <none>
      Volumes: <none>
Conditions:
  Type               Status  Reason
  ----               ------  ------
  Available          True    MinimumReplicasAvailable
  Progressing        True    NewReplicaSetAvailable
OldReplicaSet:      <none>
NewReplicaSet:      simple-webapp-deployment-7b59598d59 (4/4 replicas created)
Events:
  Type    Reason              Age   From                     Message
  ----    ------              ----  ----                     ------
  Normal  ScalingReplicaSet   63s   deployment-controller    Scaled up replica set simple-webapp-deployment-7b59598d59 to 4

The container image used is kodekloud/simple-webapp:red.

Accessing the Web Application UI

Attempting to access the web application UI may result in a "bad gateway" error. This occurs because there is no service defined to expose the web application.

Warning

Without a proper service configuration, your web application will remain inaccessible externally.

To resolve this, you need to create a new service using a service definition file.

Creating a Service for the Web Application

Below is a template for a service definition:

apiVersion: v1
kind: Service
metadata:
  name: 
spec:
  type: 
  ports:
    - targetPort: 
      port: 
      nodePort: 
  selector:
    name:

For reference, the Kubernetes documentation offers sample YAML definitions. An example is:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

For our web application, update the service definition with the following parameters:

  • Name: webapp-service
  • Type: NodePort
  • Port: 8080
  • TargetPort: 8080
  • NodePort: 30080
  • Selector: name: simple-webapp

The complete YAML definition is:

apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: NodePort
  ports:
    - targetPort: 8080
      port: 8080
      nodePort: 30080
  selector:
    name: simple-webapp

After saving this definition (for example, as service-definition-1.yaml), verify the file content:

controlplane ~ → ls
service-definition-1.yaml

controlplane ~ → cat service-definition-1.yaml
---
apiVersion: v1
kind: Service
metadata:
  name:
spec:
  type:
  ports:
    - targetPort:
      port:
      nodePort:
  selector:
    name:

Open the file with your preferred editor:

controlplane ~ → vi service-definition-1.yaml

Create the service with:

controlplane ~ → kubectl create -f service-definition-1.yaml
service/webapp-service created

controlplane ~ →

Now, you can access the web application using the newly created service. In future lessons, we will also explore imperative commands to create services. For example, try the following commands:

kubectl expose pod redis --port=6379 --name=redis-service --dry-run=client -o yaml
kubectl create service clustip redis --tcp=6379:6379 --dry-run=client -o yaml
kubectl expose pod nginx --type=NodePort --port=80 --name=nginx-service --dry-run=client -o yaml
kubectl create service nodeport nginx --tcp=80:80 --node-port=30080 --dry-run=client -o yaml

Visualizing Service Endpoints

For a better understanding of how services direct traffic to Pods, consider the following hand-drawn diagram. It illustrates a service directing traffic to three distinct Pods labeled "app: FE" and "app: FG":

A hand-drawn diagram with a triangle connected to three circles, labeled "app: FE" and "app: FG" on the side.

This visual representation reinforces how the service uses endpoints to direct incoming traffic to the correct Pods.

That concludes this lab. By following these steps, you now know how to list services, inspect service configurations and endpoints, review deployments, and expose a web application via a NodePort service in Kubernetes.

Watch Video

Watch video content

Previous
Services Cluster IP