> ## Documentation Index
> Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Ingress to a microservices-based application connected via Linkerd's service mesh

> Set up a local cluster to demonstrate how to use the ngrok Kubernetes Operator with Linkerd.

This guide walks you through setting up a local cluster (or using an existing one) to mesh a microservices-based application with Linkerd and use the ngrok Kubernetes Operator to route public traffic through an encrypted tunnel to your cluster.

The ngrok Kubernetes Operator is the official controller for adding secure public ingress and middleware execution to your Kubernetes applications with ngrok.
Linkerd is an open source service mesh: a set of network proxies that handle communications between microservices and add observability, security, and reliability at the platform level.
Linkerd enables mutual TLS (mTLS) between microservices for confidentiality and authenticity.
When integrated, the ngrok Kubernetes Operator and Linkerd simplify your networking stack (internal and external traffic) and give you additional monitoring and resiliency.

## What you'll need

* An existing remote or local Kubernetes cluster or the minikube CLI installed locally to create a new testing cluster.
* The Linkerd 2.x CLI installed locally (helper script, Homebrew, or binary in your `$PATH`).
* An ngrok account.
* kubectl and Helm 3.0.0+ installed on your local workstation.
* The [ngrok Kubernetes Operator](/k8s/) installed on your cluster.
* A reserved domain from the ngrok [dashboard](https://dashboard.ngrok.com/domains) or [API](/api-reference/reserveddomains/list); this guide refers to it as `<NGROK_DOMAIN>`.

## Set up a local development cluster

* Create a local Kubernetes cluster with minikube.
  You will assign it a profile named `ngrok-linkerd` with `-p`, and for the best compatibility with Linkerd, use the `containerd` container runtime.

  ```bash theme={null}
  minikube start -p ngrok-linkerd --container-runtime=containerd
  ```

  <Tip>
    If your OS does not support containerd, you can run minikube without specifying the container runtime.

    ```bash theme={null}
    minikube start -p ngrok-linkerd
    ```

    If minikube defaults to using the `docker` runtime, you will likely see an error related to root privileges when installing Linkerd to your cluster.
    The error includes a workaround to let you install Linkerd despite using the `docker` runtime.
  </Tip>

* Use `kubectl` to verify your local cluster is running properly.

  ```bash theme={null}
  kubectl get namespaces

  NAME              STATUS   AGE
  default           Active   72s
  kube-node-lease   Active   72s
  kube-public       Active   72s
  kube-system       Active   72s
  ```

## Deploy Linkerd's service mesh to your cluster

* Verify your Linkerd CLI is working correctly with `linkerd version`, which should display the same output as below.
  The `Server version: unavailable` is expected at this point.

  ```bash theme={null}
  linkerd version
  Client version: stable-2.14.2
  Server version: unavailable
  ```

* Validate that your Kubernetes cluster is ready to deploy Linkerd with `linkerd check --pre`.
  You should see the following output at the end:

  ```bash theme={null}
  linkerd check --pre
  ...
  Status check results are √
  ```

* Generate and deploy the Kubernetes manifests required to run Linkerd on your cluster, starting with the CRDs.

  ```bash theme={null}
  linkerd install --crds | kubectl apply -f -
  ```

  Followed by the core resources.

  ```bash theme={null}
  linkerd install | kubectl apply -f -
  ```

* Check that Linkerd installed correctly with `linkerd check`.
  You should see a number of successful checks in your terminal output, with a final verification at the end.

  ```bash theme={null}
  linkerd check
  ...
  Status check results are √
  ```

<Note>
  These steps follow the Linkerd getting-started documentation for installing the service mesh.
</Note>

## Deploy an example microservices-based application

To demonstrate how Linkerd and the ngrok Kubernetes Operator integrate to add additional observability, security, and reliability into your cluster, you'll deploy the Emojivoto demo application, which was developed by Buoyant, the company that originally developed Linkerd.

* Create an ngrok static subdomain for ingress if you don't have one already.
  Go to the [**Domains** section](https://dashboard.ngrok.com/domains) of the ngrok dashboard and click **Create Domain** or **New Domain**.
  This static subdomain will be your `NGROK_DOMAIN` for the remainder of this guide.
  Creating a subdomain on the ngrok network provides a public route for HTTP, HTTPS, and TLS traffic.

* Deploy Emojivoto to the `emojivoto` namespace.

  ```bash theme={null}
  curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/emojivoto.yml \
    | kubectl apply -f -
  ```

* Add meshing by injecting Linkerd's data plane proxies into each pod with a rolling deploy.
  The following command retrieves all deployments from the previous step, injects the Linkerd proxy, and redeploys each pod.

  ```bash theme={null}
  kubectl get -n emojivoto deploy -o yaml \
    | linkerd inject - \
    | kubectl apply -f -
  ```

* Verify your data plane with `linkerd -n emojivoto check --proxy`; it should end with a healthy status check.

  ```bash theme={null}
  linkerd -n emojivoto check --proxy
  ...
  Status check results are √
  ```

* Create a new `emojivoto-ingress.yaml` file and add the following YAML content (see Linkerd's ingress task documentation for the ngrok example).
  It defines the ngrok Kubernetes Operator for routing traffic on your `NGROK_DOMAIN` to the `web-svc` deployment you created when deploying Emojivoto.

  <Tip>
    Edit line `9` of the manifest below (the `NGROK_DOMAIN` variable) with your ngrok subdomain (for example, `one-two-three.ngrok.app`).
  </Tip>

  ```yaml showLineNumbers theme={null}
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: emojivoto-ingress
    namespace: emojivoto
  spec:
    ingressClassName: ngrok
    rules:
      - host: <NGROK_DOMAIN>
        http:
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: web-svc
                  port:
                    number: 80
  ```

* Apply the `emojivoto-ingress.yaml` manifest you just created.

  ```bash theme={null}
  kubectl apply -f emojivoto-ingress.yaml
  ```

  Give your cluster a few moments to launch the necessary resources and for ngrok to pick up the new tunnel.

  <Tip>
    **Troubleshooting:** If you see an error when applying the manifest, double-check that you've updated the `NGROK_DOMAIN` value and try again.
  </Tip>

* Access your Emojivoto application by navigating to your ngrok domain (for example, `https://one-two-three.ngrok.app`) in your browser.

## Add Linkerd's dashboard to verify meshing and mTLS

Given that one of the key benefits of a service mesh is increased observability, and the inherent security enhancements that come from mTLS connections between your microservices, you'll want to double-check that your deployments and pods are properly meshed.

* Install the Linkerd dashboard.

  ```bash theme={null}
  linkerd viz install | kubectl apply -f -
  ```

* To verify mTLS, restart all pods in the `emojivoto` namespace to enable tapping.

  ```bash theme={null}
  kubectl -n emojivoto rollout restart deploy
  ```

* Use Linkerd's tap feature: run `linkerd viz -n emojivoto tap deploy` to stream traffic from all pods in the `emojivoto` namespace to your terminal.
  The Emojivoto app generates traffic automatically, so you'll see a consistent stream of requests.

  ```bash theme={null}
  linkerd viz -n emojivoto tap deploy
  ...
  req id=0:11 proxy=out src=10.244.0.15:43706 dst=10.244.0.2:8080 tls=true :method=POST :authority=emoji-svc.emojivoto:8080 :path=/emojivoto.v1.EmojiService/ListAll
  ```

  You should see `tls=true` in all of these requests between these pods.
  You can also use `kubectl get pods -o wide` to see the IP address of each pod, which lets you verify the source and destination of each request.
  For example, the request shown above is the `web-svc` service sending a POST request, with mTLS enabled, to the `emoji-svc` service, which maintains and stores the votes database.

* Run `linkerd viz dashboard &` to open the Linkerd dashboard in your browser.
  The default dashboard shows golden metrics (success rates, traffic, latencies per namespace) and the number of meshed pods per namespace.
  Some of the auto-generated traffic is designed to fail, which shows how to use the dashboard to debug pod-to-pod issues.

## What's next?

You've now integrated a demo microservices application with Linkerd's service mesh and ngrok's Kubernetes Operator to add multiple new layers of security and reliability without having to worry about configuring middleware, network interfaces, mTLS, or deploying new monitoring services for observing the external behavior of your code.

After deploying this local demo, you have a few options for moving forward.

### Clean up

To clean up from the work you've done for this local demo, you can stop and delete your minikube cluster with the `minikube` CLI:

```
minikube stop -p ngrok-linkerd
minikube delete -p ngrok-linkerd
```

Then remove the Linkerd CLI from your local workstation:

```bash theme={null}
rm -rf $HOME/.linkerd2
```

### Extend your ngrok Kubernetes Operator and Linkerd integration

For production and real-world applications, explore installing Linkerd with Helm and production runbooks.
In more complex scenarios, you can follow the same steps to install the ngrok Kubernetes Operator and configure an Ingress so ngrok handles routing and middleware for simplicity, global load balancing, and automatic encryption.

See the [ngrok Kubernetes Operator GitHub repository](https://github.com/ngrok/ngrok-operator) and [project documentation](https://github.com/ngrok/ngrok-operator/tree/main/docs) for more details.
