Having trouble with your Kubernetes Deployments? Start with the basics.
Published: 2020-10-14 11:01:04



Debugging your Deployments in Kubernetes can turn out to be quite the task. Where do you start? The Service or the Ingress? Or the Pods itself? If it’s any one of the three, how do you go about troubleshooting it? All these questions can make Debugging harder than it needs to be.  

 
 
Most of the Debugging solutions lie in the **basics** of Kubernetes Deployments itself. If you understand the components of a Kubernetes Deployment, and how they link to each other, you will be better equipped to solve most (if not all) of your Deployment issues.
 
 
So here’s a brief look at the basics of Kubernetes Deployment:
 
 
 
# The Components of a Kubernetes Deployments
 
 
When you wish to deploy an application in Kubernetes, you usually define three components:
 
a **Deployment** — which is a recipe for creating copies of your application called Pods
 
a **Service** — an internal load balancer that routes the traffic to Pods.
 
an **Ingress** — a description of how the traffic should flow from outside the cluster to your Service.
 
 
Here's a quick visual recap.
 
 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ff0ku4ybic49eklw7nkn.gif)
 
Let’s deploy a simple Hello World application for our example.
 
 
The YAML for such an application should look similar to this:

 ```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
      labels:
        any-name: my-app
    spec:
      containers:
        - name: cont1
          image: learnk8s/app:1.0.0
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - port: 80
      targetPort: 8080
  selector:
    name: app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
    - http:
      paths:
        - backend:
            serviceName: app
            servicePort: 80
          path: /
```
 
It can be seen that the definition is quite long, and more importantly, it raises a few questions as to how the components relate to each other.
 
Some of the questions are:
 
- When should you use port 80 and when port 8080?
- Should you create a new port for every Service so that they don't clash?
- Do label names matter? Should it be the same everywhere?
 
 
To better understand how these components relate to each other, we must know how they connect to each other.
 
 
# Connections between the components
 
 
Let's start with Deployment and Service.
 
 
## Connecting Deployment and Service
 
 
The surprising news is that Service and Deployment aren't connected at all.
 
Instead, the Service points to the Pods directly and skips the Deployment altogether.
 
So what you should pay attention to is how the Pods and the Service are related to each other.
 
You should remember three things:
 
1. The Service selector should match at least one label of the Pod
1. The Service `targetPort` should match the `containerPort` of the container inside the Pod
1. The Service `port` can be any number. Multiple Services can use the same port because they have different IP addresses assigned.

 
 
The following diagram summarises how to connect the ports:
 
 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q6wuwu2kqta7vpjgw6gt.gif)
 
 
If you look at the YAML, the labels and `ports`/`targetPort` should match:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
      labels:
        any-name: my-app
    spec:
      containers:
        - name: cont1
          image: learnk8s/app:1.0.0
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - port: 80
      targetPort: 8080
  selector:
    any-name: my-app
``` 
 
_What about the `track: canary` label at the top of the Deployment?_
 
_Should that match too?_
 
That label belongs to the deployment, and it's not used by the Service's selector to route traffic.
 
In other words, you can safely remove it or assign it a different value.

_And what about the `matchLabels` selector_?
 
**It always has to match the Pod labels** and it's used by the Deployment to track the Pods.

_Assuming that you made the correct change, how do you test it?_

You can check if the Pods have the right label with the following command:
 
 ```bash
kubectl get pods --show-labels
```

Or if you have Pods belonging to several applications:

```bash
kubectl get pods --selector any-name=my-app --show-labels
```

Where `any-name=my-app` is the label `any-name: my-app`.

_Still having issues?_

You can also connect to the Pod!

You can use the `port-forward` command in kubectl to connect to the Service and test the connection.

```bash
kubectl port-forward service/<service name> 3000:80
```

Where:

- `service/<service name>` is the name of the service — in the current YAML is "my-service"
- 3000 is the port that you wish to open on your computer
- 80 is the port exposed by the Service in the `port` field

If you can connect, the setup is correct.

If you can't, you most likely misplaced a label or the port doesn't match.

## Connecting Service and Ingress

The next step in exposing your app is to configure the Ingress.

The Ingress has to know how to retrieve the Service to then retrieve the Pods and route traffic to them.

The Ingress retrieves the right Service by name and port exposed.

Two things should match in the Ingress and Service:

1. The `servicePort` of the Ingress should match the `port` of the Service
1. The `serviceName` of the Ingress should match the `name` of the Service

The following diagram summarises how to connect the ports:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tj7xkyfon4oydadr3dp8.gif)

In practice, you should look at these lines:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - port: 80
      targetPort: 8080
  selector:
    any-name: my-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
    - http:
      paths:
        - backend:
            serviceName: my-service
            servicePort: 80
          path: /
```

_How do you test that the Ingress works?_

You can use the same strategy as before with `kubectl port-forward`, but instead of connecting to a service, you should connect to the Ingress controller.

First, retrieve the Pod name for the Ingress controller with:

```bash
kubectl get pods --all-namespaces
NAMESPACE   NAME                              READY STATUS
kube-system coredns-5644d7b6d9-jn7cq          1/1   Running
kube-system etcd-minikube                     1/1   Running
kube-system kube-apiserver-minikube           1/1   Running
kube-system kube-controller-manager-minikube  1/1   Running
kube-system kube-proxy-zvf2h                  1/1   Running
kube-system kube-scheduler-minikube           1/1   Running
kube-system nginx-ingress-controller-6fc5bcc  1/1   Running
```

Identify the Ingress Pod (which might be in a different Namespace) and describe it to retrieve the port:

```bash
kubectl describe pod nginx-ingress-controller-6fc5bcc \
 --namespace kube-system \
 | grep Ports
Ports:         80/TCP, 443/TCP, 18080/TCP
```

Finally, connect to the Pod:

```bash
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
```

At this point, every time you visit port 3000 on your computer, the request is forwarded to port 80 on the Ingress controller Pod.

If you visit <http://localhost:3000>, you should find the app serving a web page.

## Recap on ports

Here's a quick recap on what ports and labels should match:

1. The Service selector should match the label of the Pod
1. The Service `targetPort` should match the `containerPort` of the container inside the Pod
1. The Service port can be any number. Multiple Services can use the same port because they have different IP addresses assigned.
1. The `servicePort` of the Ingress should match the `port` in the Service
1. The name of the Service should match the field `serviceName` in the Ingress

Knowing how to structure your YAML definition is only part of the story.

_What happens when something goes wrong?_

Perhaps the Pod doesn't start, or it's crashing. This is when you can refer to our simplified troubleshooting guide.
 
 
# The 3-step troubleshooting guide.
 
 
Troubleshooting your Kubernetes deployments involves checking all the three components i.e. Deployment (Pods), Ingress, and Service in a bottom-up manner. Here is a structured guide (with a visual graph) on every possible deployment problem you may run into, and how to deal with it: [A visual guide on troubleshooting Kubernetes deployments](https://learnk8s.io/troubleshooting-deployments)