Introduction to Linkerd for beginners
Tags: devops, cloud, kubernetes, docker
Published: 2020-10-24 03:32:49

I had a blast learning about Linkerd lately. It's a service mesh designed to help with traditional issues regarding service to service communication

Many times we would have to write a lot of code and operational overhead to achieve:

* SSL between microservices
* Auto retry for failed requests
* Metrics (Request per second & Latency)
* Tracing 
* and More

A service mesh can help here by injecting a discrete proxy next to every application which hijacks requests coming in and out of that service.

I cover these challenges and service mesh basics in my [Introduction to Service mesh] (https://youtu.be/rVNPnHeGYBE) video on YouTube.

![maxresdefault](https://dev-to-uploads.s3.amazonaws.com/i/6pafxhvm6s9lx6muc4z3.jpg)

## Step 1 : We need a Kubernetes Cluster

Lets create a Kubernetes cluster to play with using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
Kind is great for running throwaway test clusters :)

```
kind create cluster --name linkerd --image kindest/node:v1.19.1
```

Make sure you have `kubectl` installed and its pointing to your cluster. You should be able to contact your cluster like so:

```
#test cluster access:

kubectl get nodes
NAME                    STATUS   ROLES    AGE   VERSION
linkerd-control-plane   Ready    master   26m   v1.19.1
```

## Step 2: Example Microservice Architecture

I have a few components that makes up a video catalog application.
This architecture consists of :
* Ingress controller: A gateway for receiving traffic
* Videos Web : A web interface to show video catalog
* Playlists API: An API to retrieve lists of playlists
* Playlists DB: A small redis database to store playlists
* Videos API: An API to retrieve video data by ID
* Videos DB: A small redis database to store video data

Architecture:

```
                              servicemesh.demo/home            +--------------+
                              +------------------------------> | videos-web   |
                              |                                |              |
servicemesh.demo/home  +------+------------+                   +--------------+
   +------------------>+ingress-nginx      |
                       |Ingress controller |
                       +------+------------+                   +---------------+    +--------------+
                              |                                | playlists-api +--->+ playlists-db |
                              +------------------------------> |               |    |              |
                              servicemesh.demo/api/playlists   +-----+---------+    +--------------+
                                                                     |
                                                                     v
                                                               +-----+------+       +-----------+
                                                               | videos-api +------>+ videos-db |
                                                               |            |       |           |
                                                               +------------+       +-----------+



```

To follow along with this tutorial, all the code is in my [GitHub](https://github.com/marcel-dempers/docker-development-youtube-series/tree/master/kubernetes/servicemesh/linkerd) repo

Clone the repo, and lets deploy all the applications to our cluster:

```
# ingress controller
kubectl create ns ingress-nginx
kubectl apply -f kubernetes/servicemesh/applications/ingress-nginx/

# applications
kubectl apply -f kubernetes/servicemesh/applications/playlists-api/
kubectl apply -f kubernetes/servicemesh/applications/playlists-db/
kubectl apply -f kubernetes/servicemesh/applications/videos-api/
kubectl apply -f kubernetes/servicemesh/applications/videos-web/
kubectl apply -f kubernetes/servicemesh/applications/videos-db/
```
## Step 3: Make sure all our apps are up and running

```
kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE  
playlists-api-d7f64c9c6-rfhdg   1/1     Running   0          2m19s
playlists-db-67d75dc7f4-p8wk5   1/1     Running   0          2m19s
videos-api-7769dfc56b-fsqsr     1/1     Running   0          2m18s
videos-db-74576d7c7d-5ljdh      1/1     Running   0          2m18s
videos-web-598c76f8f-chhgm      1/1     Running   0          100s 

```
Let's double check the Ingress controller too :

```
kubectl -n ingress-nginx get pods
NAME                                        READY   STATUS    RESTARTS   AGE  
nginx-ingress-controller-6fbb446cff-8fwxz   1/1     Running   0          2m38s
nginx-ingress-controller-6fbb446cff-zbw7x   1/1     Running   0          2m38s

```

Next up we'll need a fake DNS name `servicemesh.demo` <br/>
Let's fake one by adding the following entry in our hosts (`C:\Windows\System32\drivers\etc\hosts`) file: <br/>


```
127.0.0.1  servicemesh.demo

```
Now we have a DNS `servicemesh.demo`, lets connect to our Ingress controller using `port-forward`

```
kubectl -n ingress-nginx port-forward deploy/nginx-ingress-controller 80
```

Now we can access our site under `http://servicemesh.demo/home/` [here](http://servicemesh.demo/home/)

## Step 4: Installing LinkerD

Firstly, I like to do most of my work in containers so everything is reproducible and my machine remains clean. Let's get a small lightweight Alpine Linux container so we can get to work:

```
docker run -it --rm -v ${HOME}:/root/ -v ${PWD}:/work -w /work --net host alpine sh

# install curl & kubectl
apk add --no-cache curl nano
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl

#test cluster access:
/work # kubectl get nodes
NAME                    STATUS   ROLES    AGE   VERSION
linkerd-control-plane   Ready    master   26m   v1.19.1

```

Now let's install the `linkerd` CLI in our container:
I grabbed the `edge-20.10.1` release using `curl`

```
curl -L -o linkerd https://github.com/linkerd/linkerd2/releases/download/edge-20.10.1/linkerd2-cli-edge-20.10.1-linux-amd64 
chmod +x linkerd && mv ./linkerd /usr/local/bin/

linkerd --help
```

Let's do some preflight checks 
Linkerd has a great capability to check compatibility with the target cluster

```
linkerd check --pre
```
Let's grab the YAML from the `linkerd` CLI:
```
# Grab YAML:
linkerd install > ./kubernetes/servicemesh/linkerd/manifest/linkerd-edge-20.10.1.yaml

# Deploy it:
kubectl apply -f ./kubernetes/servicemesh/linkerd/manifest/linkerd-edge-20.10.1.yaml
```
Let's wait until all components are running

```
watch kubectl -n linkerd get pods
kubectl -n linkerd get svc
```

You can also do a final check:
```
linkerd check
```

## Step 5: Access the LinkerD Dashboard

Let's access the `linkerd` dashboard via `port-forward`

```
kubectl -n linkerd port-forward svc/linkerd-web 8084
```
Feel free to have a browse around to familiarise yourself with the dashboard features.

# Step 6: Mesh our video catalog services

There are 2 ways to mesh services:

1) We can add an annotation to your deployment to persist the mesh if our YAML is part of a GitOps flow:

This is a more permanent solution:

```
  template:
    metadata:
      annotations:
        linkerd.io/inject: enabled
```

2) Or inject `linkerd` on the fly:
This may only be temporary as your CI/CD system may roll out the previous YAML

```
kubectl get deploy
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
playlists-api   1/1     1            1           8h 
playlists-db    1/1     1            1           8h 
videos-api      1/1     1            1           8h 
videos-db       1/1     1            1           8h 
videos-web      1/1     1            1           8h 

kubectl get deploy playlists-api -o yaml | linkerd inject - | kubectl apply -f -
kubectl get deploy playlists-db -o yaml | linkerd inject - | kubectl apply -f -
kubectl get deploy videos-api -o yaml | linkerd inject - | kubectl apply -f -
kubectl get deploy videos-db -o yaml | linkerd inject - | kubectl apply -f -
kubectl get deploy videos-web -o yaml | linkerd inject - | kubectl apply -f -
kubectl -n ingress-nginx get deploy nginx-ingress-controller  -o yaml | linkerd inject - | kubectl apply -f -

```

## Step 7: Generate some traffic to our services

Let's run a `curl` loop to generate some traffic to our site </br>
We'll make a call to `/home/` and to simulate the browser making a call to get the playlists, <br/>
we'll make a follow up call to `/api/playlists`

```
While ($true) { curl -UseBasicParsing http://servicemesh.demo/home/;curl -UseBasicParsing http://servicemesh.demo/api/playlists; Start-Sleep -Seconds 1;}
```

## Step 8: Failure and Observability

In my video, I inject a fault to my `videos-api` using some faulty code that can be enabled by setting Environment variable `FLAKY=true` on the `videos-api` deploy.yaml file. I redeploy that service once the environment variable is set. 
```
kubectl apply -f kubernetes/servicemesh/applications/videos-api/
```
We can observe cascading failures in the `linkerd` dashboard once failures start to occur.

## Step 9: Service Profiles & Auto Retry

Now that we have a failure, we can test out the auto retry feature by creating a service profile. A service profile can be generated using the `linkerd` CLI or you can just apply one I created already:

```
 kubectl apply -f kubernetes/servicemesh/linkerd/serviceprofiles/videos-api.yaml
```

We can notice retries are occuring when effective RPS is different to the actual RPS 

```
linkerd routes -n default deploy/playlists-api --to svc/videos-api -o wide
```
We will also see the playlist API recover in the `linkerd` dashboard.

## Step 10: Mutual TLS

A cool feature of Linkerd is every meshed service gets mutual TLS which means all internal meshed service traffic is encrypted using TLS. We can view this by running :

```
linkerd -n default edges deployment
SRC                  DST             SRC_NS    DST_NS    SECURED       
playlists-api        videos-api      default   default   √
linkerd-prometheus   playlists-api   linkerd   default   √
linkerd-prometheus   playlists-db    linkerd   default   √
linkerd-prometheus   videos-api      linkerd   default   √
linkerd-prometheus   videos-db       linkerd   default   √
linkerd-prometheus   videos-web      linkerd   default   √
linkerd-tap          playlists-api   linkerd   default   √
linkerd-tap          playlists-db    linkerd   default   √
linkerd-tap          videos-api      linkerd   default   √
linkerd-tap          videos-db       linkerd   default   √
linkerd-tap          videos-web      linkerd   default   √
```
You can also `tap` deployments to get a `tcpdump` style view which will also show tls on traffic between services:
```
linkerd -n default tap deploy
```

Hope you found this guide useful!
Be sure to checkout my LinkerD episode on YT

{% youtube Hc-XFPHDDk4 %}

Peace!