Journey into Kubernetes - Services


3 min read

A service makes pods accessible. If you want the pods in your deployment to communicate with other pods or be accessible from outside the cluster, you must define a service. There are 4 types of services, but the two we're interested in are ClusterIP and LoadBalancer. ClusterIP does not expose a public IP address, so the service can only communicate within the cluster. LoadBalancer on the other hand does expose a public IP and can be hit from the outside world.

If you have pods which do not require communication with any other pods, then you don't need a service. This could be a cron job, or an app which listens to a queue and sends an e-mail. Services have several properties, but to get up and running you need just a few pieces in place. Let's create a fancyapi-service.yml file and toss this inside:

apiVersion: v1
kind: Service
  name: fancyapi-service
  namespace: integration
    app: fancyapi
    - name: http
      protocol: TCP
      port: 80
      targetPort: 5000
  type: ClusterIP

The interesting parts of this definition are in the spec map. First, we have the selector. You may recall from the last article about deployments that selectors let you grab objects which have tags assigned. In this definition, we're grabbing things tagged with app: fancyapi. Just so happens that our deployment has that tag!

The ports map is where you define how you want your pods to be accessible. In the above example, we're defining just one port named http using the TCP protocol. The next two values are important to get right:

  • port is what other services will call this service on
  • targetPort is the port that the container is exposing

In this example we're assuming the exposed port in the container is 5000 (default ASP.NET Core application port), but obviously yours may be different. This port is the same one you may have defined in your Dockerfile under EXPOSE property, or when you were building your container image with the -p flag.

The last thing we need to talk about is the type: ClusterIP. ClusterIP means the service will have an internal IP address assigned by K8s (kubenet specifically). Your service will not have an outside IP address. If you wanted to expose your service outside the cluster, you could do so by setting the type to NodePort. When you do this, K8s requests an IP address from the hosting service (in our case Azure) and then assigns a port to it. The port is usually in the 30000s range by default.

You could also expose it via type: LoadBalancer. We're going to use LoadBalancer a bit later in this article series when we set up an Ingress Controller. For now, let's stick to ClusterIP. Go ahead and apply this YML:

kubectl apply -f fancyapi-service.yml

Then check your services:

kubectl get services

You'll see a table with one item in it. It will have a CLUSTER-IP that starts with 10 and not have an EXTERNAL-IP. That's okay, we'll get there.

Most tutorials I found end here at this step. They'll tell you to use NodePort or LoadBalancer and call it good. Setting up an Ingress Controller is honestly not that difficult though, so I don't know why nobody goes further. We'll get started with the Ingress Controller in the next article by creating a local SSL certificate.

Did you find this article valuable?

Support Paul K by becoming a sponsor. Any amount is appreciated!