loading...

Introduction to Linkerd for beginners

marceldempers profile image 💻:~:$ That DevOps Guy ・6 min read

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 video on YouTube.

maxresdefault

Step 1 : We need a Kubernetes Cluster

Lets create a Kubernetes cluster to play with using kind
Kind is great for running throwaway test clusters :)

kind create cluster --name linkerd --image kindest/node:v1.19.1
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 |
                                                               |            |       |           |
                                                               +------------+       +-----------+



Enter fullscreen mode Exit fullscreen mode

To follow along with this tutorial, all the code is in my GitHub 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/
Enter fullscreen mode Exit fullscreen mode

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 

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

Next up we'll need a fake DNS name servicemesh.demo

Let's fake one by adding the following entry in our hosts (C:\Windows\System32\drivers\etc\hosts) file:

127.0.0.1  servicemesh.demo

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Now we can access our site under http://servicemesh.demo/home/ here

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

linkerd check --pre
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Let's wait until all components are running

watch kubectl -n linkerd get pods
kubectl -n linkerd get svc
Enter fullscreen mode Exit fullscreen mode

You can also do a final check:

linkerd check
Enter fullscreen mode Exit fullscreen mode

Step 5: Access the LinkerD Dashboard

Let's access the linkerd dashboard via port-forward

kubectl -n linkerd port-forward svc/linkerd-web 8084
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 -

Enter fullscreen mode Exit fullscreen mode

Step 7: Generate some traffic to our services

Let's run a curl loop to generate some traffic to our site
We'll make a call to /home/ and to simulate the browser making a call to get the playlists,

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;}
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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   √
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Peace!

Discussion

pic
Editor guide