AZURE KUBERNETES SERVICE

Azure Kubernetes: Part 2- Expose a Service to Outside World

Expose a simple service in AKS

Ayush P Gupta
5 min readJun 30, 2023

In our previous article Azure Kubernetes: Part 1- Deploy an image we learned how to deploy a simple Docker image to our Kubernetes cluster. However, our service was confined to cluster by default. We need to expose it to the outside world so as to make it accessible.
In this article, we shall look into how we can expose our service via an IP and consume it.

Ideally, we should expose our service via Ingress Controller (Reverse Proxy eg. Nginx) instead of directly exposing it.

Service vs Pod

Before we dive in, we need to understand clearly the difference between a Service and Pod

A pod is simply a standalone docker image runner.

Service acts as a load balancer and evenly distributes incoming traffic to pods. A pod is generally not exposed directly. A service is exposed and accepts all incoming traffic.

Basics

If we look at our service definition from the last blog,

#########################################################
# Apple Service
#########################################################

kind: Service
apiVersion: v1
metadata:
name: apple-service
spec:
selector:
app: apple
ports:
- port: 5678 # Default port for image

our service by default is exposed as internal Cluster IP.

In the above image, we note

  1. Cluster IP is assigned to our apple-service. This is an internal cluster IP and not external IP. You cannot access this service via this IP.
  2. External IP column is empty. Hence to access it via the outside world our service needs to have an external IP.

Service Type

We can expose a Pod directly, but it's bad practice as Pod lifetime cannot be predicted. Service can have the following type configurations:

  1. ClusterIP
  2. NodePort
  3. LoadBalancer

For this article, we shall restrict ourselves to only ClusterIP, and LoadBalancer.

ClusterIP

By default when no config is supplied a service is exposed as ClusterIP.
ClusterIP is simply an internal Kubernetes local IP to access services internally.

Not all services need to be exposed. Some are like internal microservice which only aid other services internally. From a security point, this is an important feature to not expose critical services outside the cluster.

You can access such a service internally in a cluster via the assigned IP. Useful for inter-microservices communication.

LoadBalancer

This configuration assigns an external IP (automatically in AKS) to our service. We can then access this service via the IP from the browser, REST client, etc.
The incoming traffic is uniformly distributed to the pods (if multiple).
A service will throw 503 if no pods can be found to accept the request or not available

Expose a Service

Let’s get back to our service manifest and add the following lines

type: LoadBalancer
#########################################################
# Apple Service
#########################################################

kind: Service
apiVersion: v1
metadata:
name: apple-service
spec:
selector:
app: apple
ports:
- port: 5678
type: LoadBalancer # Add this line

Apply the changes using the following (make sure you are default namespace and correct cluster and correct terminal dir):

kubectl apply -f ./deploy.yml 

Note: In previous article we used apple.yml/banana.yml but here we have renamed it to deploy.yml. File name can be anything as per user choice.

The result would be the following:

IP has been assigned say x.y.236.36

Now if we try to open this newly generated IP in the browser you might see an error. This is because we need to specify the port also which is 5678.

Hurrah! We exposed our service successfully.
Because we used a docker image which simply ‘echo’ string, hence we are getting apple as response.

Important Points

Though we have successfully exposed our service, the following are some key points to be noted:

  1. Service is not exposed on default 80, 443 port rather 5678
  2. Better to use a custom domain than IP
  3. No SSL configured
  4. Better to use an Ingress rather than exposing service directly

Customize Port

Our service runs on port 5678, also docker image or Pod runs on 5678. We can customize our service port to use some other port than the default docker image port. Because the docker image port is fixed, the service port can be easily changed.

For eg, we can map Pod port 5678 to let’s say 3000 in service. The service would now be exposed via the 3000 port and it shall automatically map incoming requests to the 5678 port.

  ports:
- port: 3000
protocol: TCP
targetPort: 5678

Our service manifest would now look like this:

#########################################################
# Apple Service
#########################################################

kind: Service
apiVersion: v1
metadata:
name: apple-service
spec:
selector:
app: apple
ports:
- port: 3000
protocol: TCP
targetPort: 5678
type: LoadBalancer

Redeploy file

kubectl apply -f ./deploy.yml

The port has now been changed to 3000.

Bonus: Access Service Internally in Cluster

We can also access a service internally inside the cluster when inter-microservice communication is needed.
Accessing service internally is much better compared to accessing via outside IP. This decreases latency.

The internal URL to a service is of the following format

{service-name}.{namespace}.svc.cluster.local:PORT

For eg, accessing apple-service internally would be using the following URL

apple-service.default.svc.cluster.local:3000

Try accessing with another pod or curl. We shall be getting the same response.

Conclusions

In this blog, we learned about the basics of how to expose a Service and change its Port. We also saw how inter-microservice communications work in the cluster.

In the next blog we shall how to setup Ingress and SSL for our service.

Whola! Both you and I learned something new today. Congrats
👏 👏 👏

Further Reading

  1. https://kubernetes.io/docs/concepts/services-networking/service/
  2. https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/

For Part 1:

https://medium.com/@apgapg/azure-kubernetes-part-1-deploy-an-image-f36fe76c99f7

--

--