Kubernetes 05 - Exposing Kubernetes Ports
In Kubernetes, exposing ports is a fundamental aspect of managing and accessing applications running within your cluster. Whether you’re aiming to connect internally within the cluster or expose your services to the outside world, Kubernetes offers a variety of methods to do so.
Exposing Containers with kubectl expose
To start with, kubectl expose
is a command that creates a service for existing pods. But what exactly does this mean?
A service in Kubernetes is essentially a stable endpoint that provides access to a set of pods. These pods are dynamic and can change over time, but the service provides a consistent way to reach them. This is crucial because, in a Kubernetes environment, pods may come and go, scale up or down, and the service ensures that your applications can reliably communicate with these pods.
Kubernetes uses CoreDNS to resolve these services by name, allowing applications to connect to services seamlessly.
There are several types of services in Kubernetes.
Basic Service Types
ClusterIP (default)
- Description: Allocates a single internal virtual IP address that is only reachable from within the cluster.
- Use Case: Suitable for internal communication between applications running within the cluster.
NodePort
- Description: Designed for external access to the cluster. It allocates a high port on each node, making it accessible on every node’s IP address.
- Use Case: Allows external clients to connect to a specific port on the nodes to access the service.
LoadBalancer
- Description: Creates an external load balancer that distributes traffic across multiple nodes and pods. It relies on an infrastructure provider that supports load balancers, such as AWS ELB (Elastic Load Balancer) or Azure Load Balancer.
- Use Case: Used for distributing external traffic across multiple pods and nodes, ensuring high availability.
ExternalName
- Description: Maps a service to a DNS name. It adds a CNAME record to CoreDNS, pointing to an external DNS name.
- Use Case: Used when you want to give pods a DNS name to use for an external service that resides outside the Kubernetes cluster.
Creating a ClusterIP Service
Let’s walk through the steps to create a ClusterIP service.
Step 1: Monitor the Pods
Open a terminal and run the following command to monitor the pods.
kubectl get pods -w
Step 2: Create a Deployment
In another terminal, create a deployment with the following command.
First run kubectl get pods -w
on one terminal.
kubectl create deployment httpenv --image=bretfisher/httpenv
Step 3: Scale the Deployment
Scale the deployment to five replicas.
kubectl scale deployment/httpenv --replicas=5
Step 4: Create a ClusterIP Service
Create a ClusterIP service to expose the deployment.
kubectl expose deployment/httpenv --port=8888
Let’s break down this command:
-
kubectl
: This is the command-line tool for interacting with your Kubernetes cluster. -
expose
: This subcommand creates a new Kubernetes service based on a specified resource. -
deployment/httpenv
: This specifies the resource that you want to expose. In this case, it is a deployment namedhttpenv
. -
--port=8888
: This flag specifies the port on which the service will be exposed. It tells Kubernetes to create a service that listens on port 8888 and routes traffic to the corresponding port on the pods managed by the httpenv deployment.
When you run this command, Kubernetes performs the following actions:
- Service Creation: Kubernetes creates a new service resource. This service has a stable IP address within the cluster (known as ClusterIP) that can be used by other pods to communicate with the
httpenv
pods. - Port Mapping: The service listens on port 8888 and forwards traffic to port 8888 on the pods selected by the
httpenv
deployment.
Listing the ClusterIP Services
Verify that the ClusterIP service was created by running:
kubectl get service
The output should be similar to:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpenv ClusterIP 10.111.103.37 <none> 8888/TCP 92s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d1h
Remember, the ClusterIP is internal only. To test the service from within the cluster, follow these steps:
Step 1: Create a Temporary Shell
To interact with your Kubernetes services and test their connectivity, you often need a pod with a variety of networking tools. The bretfisher/netshoot
image has pre-installed with network tools.
kubectl run tmp-shell --rm -it --image bretfisher/netshoot -- bash
Let’s break down this command:
-
kubectl run
: This command creates a new pod or deployment. -
tmp-shell
: The name of the pod. In this case, it’s namedtmp-shell
to indicate that it’s a temporary shell. -
--rm
: Automatically removes the pod once it exits. This is useful for temporary pods that you don’t want lingering around. -
-it
: Stands for interactive terminal. It allows you to interact with the pod in real-time. -
--image bretfisher/netshoot
: Specifies the container image to use for the pod. -
-- bash
: Specifies the command to run in the container. In this case, it starts a bash shell, giving you an interactive terminal session inside the pod.
When you run this command, Kubernetes starts a new pod with the bretfisher/netshoot
image and provides you with a bash shell. This environment is ideal for testing network connectivity and troubleshooting within the cluster.
Step 2: Test the Service
Once inside the temporary shell pod, you can test the connectivity to your Kubernetes service using the curl
command:
curl httpenv:8888
When you run this command, curl
sends an HTTP request to the httpenv
service on port 8888
. If the service is correctly set up and the pods are running as expected, you should receive a response. This confirms that the service is reachable and functioning properly.
Creating a NodePort Service
Now that we’ve covered how to create a ClusterIP service, let’s move on to creating a NodePort service. This service type is designed for external access, allowing clients outside the cluster to communicate with the pods.
Step 1: Exposing the Deployment with a NodePort
Let’s check the current services:
kubectl get service
This command lists all the services in the cluster. You should see the httpenv
service with the ClusterIP
type.
NAME READY STATUS RESTARTS AGE
pod/httpenv-6cc7f7986f-28zvb 1/1 Running 0 5m34s
pod/httpenv-6cc7f7986f-6xf7m 1/1 Running 0 5m34s
pod/httpenv-6cc7f7986f-czxjv 1/1 Running 0 5m34s
pod/httpenv-6cc7f7986f-n74lb 1/1 Running 0 5m40s
pod/httpenv-6cc7f7986f-vgbbn 1/1 Running 0 5m34s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/httpenv ClusterIP 10.105.5.251 <none> 8888/TCP 5m29s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d10h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/httpenv 5/5 5 5 5m40s
NAME DESIRED CURRENT READY AGE
replicaset.apps/httpenv-6cc7f7986f 5 5 5 5m40s
To expose your deployment using a NodePort service, use the following command:
kubectl expose deployment/httpenv --port 8888 --name httpenv-np --type NodePort
Let’s break down this command:
-
kubectl expose
: This command exposes a resource as a new Kubernetes service. -
deployment/httpenv
: This specifies the deployment that you want to expose. -
--port 8888
: This flag specifies the port on which the service will be exposed. -
--name httpenv-np
: Names the service httpenv-np for easier identification. -
--type NodePort
: Specifies that this service should be a NodePort service.
When you run this command, Kubernetes creates a service that is accessible externally on a high port (in the range 30000-32767) on each node in the cluster.
Step 2: Verify the NodePort Service
Check the services in your cluster to see the details of the newly created NodePort service:
kubectl get service
The output should show something similar to this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpenv ClusterIP 10.105.5.251 <none> 8888/TCP 8m41s
httpenv-np NodePort 10.106.203.2 <none> 8888:32725/TCP 6s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d10h
For the service httpenv-np
, the PORT(S)
column shows 8888:32725/TCP
.
-
8888
: This is the internal port on which the service is accessible within the cluster. Traffic directed to this service will be forwarded to port 8888 on the pods selected by the service. -
32725
: This is the external port assigned by Kubernetes for the NodePort service. This port can be used to access the service from outside the cluster. Any traffic sent to any node in the cluster on port 32725 will be routed to the internal port 8888 of the service.
Step 3: Access the NodePort Service
To access the service from outside the cluster, use the external IP address of any node in your cluster and the NodePort assigned to the service. For example, if you are running Kubernetes on your local machine or using a cloud provider, you can access the service using localhost
and the NodePort.
curl localhost:32725
This command sends an HTTP request to localhost
on port 32725
, which is then routed to the httpenv
deployment pods on port 8888
.
Note that a NodePort service also creates a ClusterIP service, making the service accessible within the cluster.
Adding a LoadBalancer Service
If you need to expose your service to the outside world and distribute traffic across multiple nodes and pods, you can use a LoadBalancer service. This service type relies on an infrastructure provider that supports load balancers, such as AWS ELB (Elastic Load Balancer) or Azure Load Balancer.
Step 1: Expose the Deployment with a LoadBalancer
If you are on Docker Desktop, it provides a built-in LoadBalancer service that publishes the --port
on local host.
kubectl expose deployment/httpenv --port=8888 --name=httpenv-lb --type=LoadBalancer
Step 2: Verify the LoadBalancer Service
Check the services in your cluster to see the details of the newly created LoadBalancer service:
kubectl get service
The output should look like this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpenv ClusterIP 10.105.5.251 <none> 8888/TCP 41m
httpenv-lb LoadBalancer 10.97.126.49 localhost 8888:32066/TCP 2s
httpenv-np NodePort 10.106.203.2 <none> 8888:32725/TCP 32m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d11h
In this example, the httpenv-lb
service is of type LoadBalancer.
If you are on kubeadm, minikube, or microk8s, there is no built-in LoadBalancer. You can still run the command, but it will just stay in pending state.
Step 3: Access the LoadBalancer Service
To access the service, use the external IP address of the LoadBalancer and the specified port:
curl localhost:8888
The LoadBalancer service distributes the incoming requests to the NodePort service, which then routes the traffic to the appropriate pods.
The load balancer port 32066
is the built in NodePort that it is creating. In the background, the load balancer receives packets on port 8888
and forwards them to the NodePort service on port 32066
. Then the NodePort is passing it to the ClusterIP, which is forwarding it to the pods. Note that there is always going to be that NodePort shown next to the colon in the PORT(S)
column for the LoadBalancer service even though the port is not really the load balancer is using on the host.
Cleaning up
kubectl delete service/httpenv service/httpenv-np service/httpenv-lb deployment/httpenv
Enjoy Reading This Article?
Here are some more articles you might like to read next: