Skip to content

How to Create a Service in Kubernetes

Introduction

Kubernetes Services provide a stable, permanent network address for accessing a set of Pods. Since Pods are ephemeral (they can be created and destroyed dynamically), Services ensure consistent access to your application regardless of Pod lifecycle changes. This guide will walk you through creating different types of Services with practical examples and outputs.

Prerequisites

  • Kubernetes cluster (v1.20 or later)
  • kubectl CLI configured to access your cluster
  • Basic knowledge of Pods and Deployments
  • Appropriate RBAC permissions to create Services

What is a Kubernetes Service?

A Service is an abstract way to expose applications running on Pods. It provides: - Stable IP address - doesn't change even if Pods are recreated - DNS name - can be accessed using a DNS hostname - Load balancing - distributes traffic across multiple Pods - Service discovery - enables Pods to find each other - Decoupling - clients don't need to know individual Pod IPs

Service Types

1. ClusterIP (Default)

Internal-only access within the cluster. Used for inter-pod communication.

2. NodePort

Exposes the Service on a port on every Node. Traffic can reach it from outside the cluster through <NodeIP>:<NodePort>.

3. LoadBalancer

Requests a cloud provider's load balancer to expose the Service externally with a stable IP.

4. ExternalName

Maps the Service to an external DNS name (CNAME record).

Creating Services with Imperative Commands

Create a ClusterIP Service

Step 1: Create a Deployment

kubectl create deployment nginx --image=nginx --replicas=3

Output:

deployment.apps/nginx created

Step 2: Create a ClusterIP Service

kubectl expose deployment nginx --port=80 --target-port=80 --type=ClusterIP --name=nginx-service

Output:

service/nginx-service exposed

Step 3: Verify the Service

kubectl get svc nginx-service

Output:

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-service   ClusterIP   10.96.123.45    <none>        80/TCP    10s

Step 4: Get Detailed Information

kubectl describe svc nginx-service

Output:

Name:              nginx-service
Namespace:         default
Labels:            app=nginx
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP:                10.96.123.45
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.0.2:80,10.244.0.3:80,10.244.0.4:80
Session Affinity:  None
Events:            <none>

Create a NodePort Service

kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort --name=nginx-nodeport

Output:

service/nginx-nodeport exposed

Verify NodePort Service

kubectl get svc nginx-nodeport

Output:

NAME              TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx-nodeport    NodePort   10.96.234.56    <none>        80:30080/TCP   5s

Access the service:

curl http://<NODE-IP>:30080

Create a LoadBalancer Service

kubectl expose deployment nginx --port=80 --target-port=80 --type=LoadBalancer --name=nginx-lb

Output:

service/nginx-lb exposed

Verify LoadBalancer Service

kubectl get svc nginx-lb

Output:

NAME       TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
nginx-lb   LoadBalancer   10.96.45.67    34.123.456.789   80:30456/TCP   10s

Creating Services with YAML

ClusterIP Service YAML

apiVersion: v1
kind: Service
metadata:
  name: nginx-clusterip
  namespace: default
  labels:
    app: nginx
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http

Create the service:

kubectl apply -f clusterip-service.yaml

Output:

service/nginx-clusterip created

NodePort Service YAML

apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
  namespace: default
  labels:
    app: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30080
      protocol: TCP
      name: http

Create the service:

kubectl apply -f nodeport-service.yaml

Output:

service/nginx-nodeport created

LoadBalancer Service YAML

apiVersion: v1
kind: Service
metadata:
  name: nginx-loadbalancer
  namespace: default
  labels:
    app: nginx
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http

Create the service:

kubectl apply -f loadbalancer-service.yaml

Output:

service/nginx-loadbalancer created

ExternalName Service YAML

apiVersion: v1
kind: Service
metadata:
  name: external-api
  namespace: default
spec:
  type: ExternalName
  externalName: api.example.com

Create the service:

kubectl apply -f externalname-service.yaml

Output:

service/external-api created

Service Management Commands

List Services

# List services in default namespace
kubectl get svc

# List services in all namespaces
kubectl get svc --all-namespaces

# List services in specific namespace
kubectl get svc -n kube-system

# Get detailed view
kubectl get svc -o wide

Output:

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP   5d
nginx-service   ClusterIP   10.96.123.45    <none>        80/TCP    2m
nginx-nodeport  NodePort    10.96.234.56    <none>        80:30080  1m

Get Service Details

kubectl describe svc nginx-service

Output:

Name:              nginx-service
Namespace:         default
Labels:            app=nginx
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP:                10.96.123.45
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.0.2:80,10.244.0.3:80,10.244.0.4:80
Session Affinity:  None
Events:            <none>

Edit Service

kubectl edit svc nginx-service

Delete Service

kubectl delete svc nginx-service

Output:

service "nginx-service" deleted

Advanced Service Configuration

Service with Multiple Ports

apiVersion: v1
kind: Service
metadata:
  name: multi-port-service
spec:
  selector:
    app: webapp
  ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP
    - name: https
      port: 443
      targetPort: 8443
      protocol: TCP

Service with Session Affinity

apiVersion: v1
kind: Service
metadata:
  name: sticky-session-service
spec:
  selector:
    app: app
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  ports:
    - port: 80
      targetPort: 8080

Service with External IPs

apiVersion: v1
kind: Service
metadata:
  name: external-ip-service
spec:
  selector:
    app: app
  type: ClusterIP
  externalIPs:
    - 192.168.1.100
  ports:
    - port: 80
      targetPort: 8080

Accessing Services

From Within the Cluster

# Using DNS name
curl http://nginx-service:80

# Using FQDN
curl http://nginx-service.default.svc.cluster.local:80

# Using Cluster IP
curl http://10.96.123.45:80

From Outside the Cluster

# For NodePort services
curl http://<NODE-IP>:<NODE-PORT>

# For LoadBalancer services
curl http://<EXTERNAL-IP>:<PORT>

Port Forwarding

kubectl port-forward svc/nginx-service 8080:80

Output:

Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

Then access at: http://localhost:8080

Troubleshooting Services

Check Endpoints

kubectl get endpoints nginx-service

Output:

NAME            ENDPOINTS                                     AGE
nginx-service   10.244.0.2:80,10.244.0.3:80,10.244.0.4:80   2m

Check Service Logs

kubectl logs -l app=nginx -n default

Test Service Connectivity

# Create a test pod
kubectl run -it --rm test-pod --image=busybox --restart=Never -- sh

# Inside the pod, test connectivity
wget -O- http://nginx-service:80

Describe Events

kubectl describe svc nginx-service | grep -A 5 Events

Best Practices

  1. Always use labels and selectors - Ensure accurate Pod-to-Service mapping
  2. Use ClusterIP for internal services - Reduces exposure
  3. Specify ports explicitly - Use named ports for clarity
  4. Use appropriate service types - Choose the right type for your use case
  5. Implement health checks - Use readiness and liveness probes
  6. Monitor service endpoints - Ensure Pods are registered correctly
  7. Use namespaces - Organize services logically
  8. Document port mappings - Maintain clarity for your team

Common Issues and Solutions

Issue Solution
Service has no endpoints Check Pod labels and selector match
Cannot connect to service Verify network policies and firewall rules
LoadBalancer pending Check cloud provider integration
NodePort not accessible Ensure node security groups allow traffic
DNS resolution fails Verify CoreDNS is running

Summary

Kubernetes Services are essential for networking and service discovery. They provide: - Stable network identity for Pods - Load balancing capabilities - Internal and external access patterns - Service discovery through DNS

Choose the appropriate service type based on your use case: - ClusterIP for internal communication - NodePort for testing and simple external access - LoadBalancer for production external access - ExternalName for external service integration

Next Steps