{"id":19865652,"url":"https://github.com/openfaas/openfaas-linkerd-workshop","last_synced_at":"2025-02-28T23:28:07.742Z","repository":{"id":38445354,"uuid":"187050643","full_name":"openfaas/openfaas-linkerd-workshop","owner":"openfaas","description":"Lightweight Serverless on Kubernetes with mTLS and traffic-splitting with Linkerd2","archived":false,"fork":false,"pushed_at":"2021-02-04T07:59:09.000Z","size":4113,"stargazers_count":99,"open_issues_count":0,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-11T15:46:32.778Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openfaas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-16T15:05:57.000Z","updated_at":"2024-09-16T20:22:01.000Z","dependencies_parsed_at":"2022-08-18T23:10:20.787Z","dependency_job_id":null,"html_url":"https://github.com/openfaas/openfaas-linkerd-workshop","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fopenfaas-linkerd-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fopenfaas-linkerd-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fopenfaas-linkerd-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fopenfaas-linkerd-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openfaas","download_url":"https://codeload.github.com/openfaas/openfaas-linkerd-workshop/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241275120,"owners_count":19937311,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T15:23:36.931Z","updated_at":"2025-02-28T23:28:07.711Z","avatar_url":"https://github.com/openfaas.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"Guide for Serverless on Kubernetes with OpenFaaS \u0026 Linkerd2\n===============================================================\n\n[Linkerd2](https://linkerd.io/2/) is a service mesh that provides features such as:\n* Mutual TLS between gateway, ingress and functions *\n* Dashboard and pre-configured grafana dashboards with prometheus metrics,\n* Works along-side ingress controllers,\n* Retries and timeouts,\n* Telemetry and monitoring,\n* A lot more! [Checkout the documentation](https://linkerd.io/2/features/)\n\nOne of the goals for Linkerd2 is that *it just works*. Is an operator-friendly project just like OpenFaaS! :smile:\n\nToday we will install Linkerd to our Kubernetes cluster so that the communication between the Gateway and the Functions goes through the linkerd proxy. These will give us encrypted communication, retries, timeouts and more.\n\nIf you are running on a GKE cluster with RBAC enabled you need to grant a cluster role of cluster-admin to your Google account:\n\n```bash\nkubectl create clusterrolebinding cluster-admin-binding-$USER \\\n    --clusterrole=cluster-admin --user=$(gcloud config get-value account)\n```\n\n### Reference architecture / examples\n\n![](/docs/reference-architecture.png)\n\n### Caveats\n\nA note on mTLS. Linkerd2 can currently only encrypt HTTP traffic which means all traffic between your IngressController, the API Gateway and your functions will be encrypted.\n\nAt present Linkerd2 only supports mTLS for HTTP traffic, which means that asynchronous requests published with NATS Streaming cannot be encrypted. mTLS for TCP is on the roadmap for Linkerd2 and will enable encryption for NATS Streaming.\n\nA work-around may be to deploy without NATS Streaming, or to only use synchronous invocations for sensitive data.\n\nSee also: [automatic mTLS in Linkerd2](https://linkerd.io/2/features/automatic-mtls/)\n\n## Need a *lab environment*?\n\nTry the brand-new sandbox environment that only needs a single DigitalOcean VM:\n\n* [openfaas-incubator/workshop-vscode](https://github.com/openfaas-incubator/workshop-vscode)\n\n1. A Virtual Machine will be provisioned with a cloud hosting provider using cloudinit\n2. Kubernetes with k3s will be installed on the VM\n3. OpenFaaS will be installed into the k3s cluster\n4. A Docker image will be run which provides VSCode via a web-browser\n5. The login password for VSCode will be obtained via ssh\n6. VSCode can now be used in web-browser via your VM's IP. The self-signed certificate will provide encryption and the login password will protect against tampering.\n\n## Install pre-reqs\n\nThe OpenFaaS helm chart can be installed most simply with our `arkade` CLI, it can also be used to install `linkerd`, `kubectl` and `faas-cli.\n\n```bash\ncurl -sLS https://dl.get-arkade.dev | sh\nsudo mv arkade /usr/local/bin/\n```\n\nGet the CLIs we'll need for the tutorial:\n\n```bash\narkade get linkerd2 --version stable-2.9.0\narkade get kubectl\narkade get faas-cli\n\nexport PATH=$PATH:$HOME/.arkade/bin/\n\n# Make an alias as \"linkerd\"\nln -s $HOME/.arkade/bin/linkerd2 $HOME/.arkade/bin/linkerd\n```\n\nInstall OpenFaaS:\n\n```bash\narkade install openfaas \\\n  --set gateway.directFunctions=true\n```\n\nThe `directFunctions=true` changes the OpenFaaS gateway invocation behaviour from using the faas-netes side-car, and its own list of endpoints, to using the service name, where Linkerd can then take over the resolution of a function's pod.\n\n## Install Linkerd 2\n\nInstalling Linkerd is easy. First, you will install the CLI (command-line interface) onto your local machine. Using this CLI, you’ll install the Linkerd control plane into your Kubernetes cluster. Finally, you’ll “mesh” one or more services by adding the data plane proxies.\n\nSee the [Architecture page](https://linkerd.io/2/reference/architecture/) for details.\n\n\u003e Note: these steps are for Linkerd 2.9, earlier or newer versions may need some alterations to the commands, but the principles should not be too different. Pull requests with tested changes are welcome.\n\n### Step 1: Install the CLI\n\nCheck the CLI version of Linkerd:\n\n```bash\nlinkerd version\n```\n\n### Step 2: Validate your Kubernetes cluster\n\nLinkerd's CLI has a handy command called `check`. This command allows us to see if our kubernetes cluster meets linkerd's needs:\n\n```bash\nlinkerd check --pre\n```\n\n### Step 3: Install Linkerd 2 onto the cluster\n\nUse arkade:\n\n```bash\narkade install linkerd\n```\n\nOr run each step manually:\n\nSetup Linkerd's config step:\n\n```bash\nlinkerd install config | kubectl apply -f -\n```\n\nNow let's install linkerd's control plane in our cluster:\n\n```bash\nlinkerd install control-plane | kubectl apply -f -\n```\n\nThis may take a minute or two. We can validate that everything's happening correctly by running:\n\n```bash\nlinkerd check\n```\n\n### Step 4: Add Linkerd 2 to OpenFaaS\n\nThe term \"injection\" refers to how Linkerd will \"mesh\" function by adding an additional proxy container to each Pod.\n\nInject Linkerd to the OpenFaaS Gateway to mesh calls from the gateway to functions:\n\n```bash\nkubectl -n openfaas get deploy gateway -o yaml | linkerd inject --skip-outbound-ports=4222 - | kubectl apply -f -\n```\n\nThis command injects the linkerd proxy and ignores the port `4222` for outbound traffic. Currently linkerd2 only supports HTTP traffic and port `4222` uses TCP traffic for `NATS`.\n\nYou can also mesh other services which use HTTP rather than TCP.\n\n```bash\nkubectl -n openfaas get deploy/basic-auth-plugin -o yaml | linkerd inject - | kubectl apply -f -\nkubectl -n openfaas get deploy/faas-idler -o yaml | linkerd inject - | kubectl apply -f -\nkubectl -n openfaas get deploy/queue-worker -o yaml | linkerd inject  --skip-outbound-ports=4222 - | kubectl apply -f -\n```\n\nNow enable automatic injection on the `openfaas-fn` namespace, Linkerd will now inject the proxy to each function Pod that we create. If we are using mutual TLS (enabled by default), we now have encryption between the gateway and each function.\n\n```bash\nkubectl annotate namespace openfaas-fn linkerd.io/inject=enabled\n```\n\nIf you already had functions deployed in your namespace you can run the injection on all of them with the following command:\n\n```bash\nkubectl -n openfaas-fn get deploy -o yaml | linkerd inject - | kubectl apply -f -\n```\n\n### Step 5: (optional) Configure your `IngressController`\n\nIf you're using a `IngressController`, then we need to run some additional commands to mesh the traffic end-to-end.\n\nInstall ingress-nginx:\n\n```bash\narkade install ingress-nginx\n```\n\nInstall cert-manager to obtain TLS certificates:\n\n```bash\narkade install ingress-nginx\n```\n\nYou'll need to create a DNS A or CNAME record to the \"EXTERNAL-IP\" shown under `kubectl get svc` for ingress-nginx, make sure that it points at `openfaas.example.com` (changing `example.com` to your own domain).\n\nDeploy an Ingress definition for OpenFaaS:\n\n```bash\narkade install openfaas-ingress \\\n --email webmaster@domain.com \\\n --domain openfaas.example.com\n```\n\nNow inject the linkerd proxy into the `IngressController`:\n\n```bash\nkubectl get deploy/\u003cname of your ingress controller\u003e -o yaml | linkerd inject - | kubectl apply -f -\n```\n\nOnce your ingress controller is injected you will notice that you cannot access your gateway. This is because of the following:\n\n* Linkerd discovers services based on the `:authority` or `Host header`, which allows Linkerd to understand what service a request is destined for without being dependent on DNS or IPs.\n\n* When it comes to ingress, most controllers do not rewrite the incoming header (example.com) to the internal service name (example.default.svc.cluster.local) by default.\n\n* We need to re-write the external DNS name, to the internal name known by Linkerd\n\nFor Nginx add the following `annotation` to the ingress definition for your OpenFaaS gateway:\n\n```yaml\nnginx.ingress.kubernetes.io/configuration-snippet: |\n  proxy_set_header l5d-dst-override gateway.openfaas.svc.cluster.local:8080;\n  proxy_hide_header l5d-remote-ip;\n  proxy_hide_header l5d-server-id;\n```\n\nFor alternative ingress controllers, see [Linkerd's documentation on using ingress](https://linkerd.io/2/tasks/using-ingress/)\n\n\u003e A note on the default backend: it is not possible to rewrite the header in this way for the default backend. Because of this, if you inject Linkerd into your Nginx ingress controller's pod, the default backend will not be usable.\n\nIf you are running your cluster on-premises, on your laptop, or in a private network where you cannot obtain a LoadBalancer, consider using the [inlets-operator](https://github.com/inlets/inlets-operator).\n\n## Use Linkerd\n\nLinkerd has a rich set of features which are growing at a steady pace. We will only cover a small sub-set in this tutorial. Contributions are welcome.\n\n### Access your dashboard\n\nLinkerd comes with a very helpful and detailed dashboards that allow us to look into the traffic going through our cluster. To open the dashboard run:\n\n```bash\nlinkerd dashboard \u0026\n```\n\nThis will open up the browser, from there you can click the `Tap` option in the side bar and look for traffic flowing from the gateway to the functions.\n\nTraffic going from the ingress controller to the gateway and finally from the gateway to the function:\n![gateway-to-function-traffic](/docs/gateway-dashboard-with-ingress.png)\n\nIncoming traffic to a function:\n![incoming-traffic-to-a-function](/docs/list-function-linkerd-request.png)\n\n\u003e Note: If you are running `kubectl` inside a VM or on a remote cluster, then you can use SSH port-forwarding to forward the dashboard back to your local machine.\n\n### Access Grafana\n\nYou can also access a Grafana dashboard, which is useful for debugging and inspecting individual functions.\n\nFind a meshed namespace, such as \"openfaas-fn\" and then click on the right hand side for that Deployment:\n\n![](./docs/select-grafana.png)\n\nYou can now view inbound / outbound metrics for that function including RPS, TCP details, and such.\n\n![](./docs/view-grafana.png)\n\n\u003e I am using `hey` to generate load and can see a bump in throughput after each auto-scaling event has fired.\n\nTo generate some load, see the auto-scaling guide in the [OpenFaaS Workshop Lab 9](https://github.com/openfaas/workshop/blob/master/lab9.md). \n\n### Disable meshing for a function\n\n```\nfaas-cli store deploy figlet \\\n  --name figlet-no-mesh \\\n  --annotation \"linkerd.io/inject=disabled\"\n```\n\n### Try traffic splitting for blue/green and canary deployments\n\nLinkerd 2.4 added the [traffic-splitting feature](https://linkerd.io/2/features/traffic-split/) and the [TrafficSplit](https://github.com/deislabs/smi-spec/blob/master/traffic-split.md) object from the [SMI spec](https://smi-spec.io).\n\n* Deploy two versions of a function\n\n```bash\nfaas-cli deploy --image functions/alpine:latest \\\n  --fprocess=\"echo green\" \\\n  --name echo-green\n\nfaas-cli deploy --image functions/alpine:latest \\\n  --fprocess=\"echo blue\" \\\n  --name echo-blue\n```\n\nWe need to create a dummy `Deployment` and `Service`, also called a `root` Service.\n\n* Create a root `Service` and `Deployment`:\n\nWe can do this by deploying another function, it will echo `root` so that we can see when the `TrafficSplit` is working and when it is not.\n\n```bash\nfaas-cli deploy --image functions/alpine:latest \\\n  --fprocess=\"echo root\" \\\n  --name echo\n```\n\n* Test each endpoint\n\n```bash\n# curl 127.0.0.1:31112/function/echo-green\ngreen\n\n# curl 127.0.0.1:31112/function/echo-blue\nblue\n\n# curl 127.0.0.1:31112/function/echo\nroot\n```\n\nYou'll see that `echo` returns `root` as its message, that's because the `TrafficSplit` is not yet connected.\n\n* Deploy the split\n\n\u003e Use `kubectl apply -f - ` then paste in the example, followed by `Ctrl+D`\n\n```yaml\napiVersion: split.smi-spec.io/v1alpha1\nkind: TrafficSplit\nmetadata:\n  name: function-split\n  namespace: openfaas-fn\nspec:\n  # The root service that clients use to connect to the destination application.\n  service: echo\n  # Services inside the namespace with their own selectors, endpoints and configuration.\n  backends:\n  - service: echo-blue\n    weight: 100m\n  - service: echo-green\n    weight: 900m\n```\n\nLet's try an initial split of: 90% green, 10% blue.\n\nTest the canary:\n\n```bash\n# for i in {0..10}; do  curl 127.0.0.1:31112/function/echo; done\ngreen\ngreen\nblue\ngreen\ngreen\nblue\ngreen\ngreen\ngreen\ngreen\ngreen\n# \n```\n\nProve the TrafficSplit is working:\n\n```\nkubectl delete -n openfaas-fn trafficsplit.split.smi-spec.io --all\n\n# for i in {0..10}; do  curl 127.0.0.1:31112/function/echo; done\nroot\nroot\nroot\nroot\nroot\nroot\nroot\nroot\nroot\nroot\nroot\n# \n```\n\nNow we have no split and we're hitting the dummy root `Deployment`.\n\nTry a 50/50 split:\n\n```yaml\napiVersion: split.smi-spec.io/v1alpha1\nkind: TrafficSplit\nmetadata:\n  name: function-split\n  namespace: openfaas-fn\nspec:\n  # The root service that clients use to connect to the destination application.\n  service: echo\n  # Services inside the namespace with their own selectors, endpoints and configuration.\n  backends:\n  - service: echo-blue\n    weight: 500m\n  - service: echo-green\n    weight: 500m\n```\n\nAnd now we see:\n\n```bash\n# for i in {0..10}; do  curl 127.0.0.1:31112/function/echo; done\ngreen\nblue\ngreen\nblue\nblue\ngreen\ngreen\ngreen\nblue\nblue\nblue\n#\n```\n\n## Next steps\n\nConnect with the project communities:\n\n* [OpenFaaS Slack](https://slack.openfaas.io/)\n* [Linkerd Slack](https://slack.linkerd.io/)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfaas%2Fopenfaas-linkerd-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenfaas%2Fopenfaas-linkerd-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfaas%2Fopenfaas-linkerd-workshop/lists"}