|
| 1 | +--- |
| 2 | +title: "Learn how to integrate Istio service mesh with your Functions" |
| 3 | +description: "Learn how to enable Istio for OpenFaaS to take advantage of Mutual TLS and the Istio Gateway" |
| 4 | +date: 2021-05-12 |
| 5 | +image: /images/2021-05-istio/background.jpg |
| 6 | +categories: |
| 7 | + - live |
| 8 | + - use-cases |
| 9 | + - functions |
| 10 | +author_staff_member: alex |
| 11 | +dark_background: true |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +Learn how to enable Istio for OpenFaaS to take advantage of Mutual TLS and the Istio Gateway |
| 16 | + |
| 17 | +## Introduction |
| 18 | + |
| 19 | +Service meshes have become popular add-ons for Kubernetes, so much so that they have their [own ServiceMeshCon days](https://events.linuxfoundation.org/servicemeshcon/) at [KubeCon](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/), the official Kubernetes conference. |
| 20 | + |
| 21 | +A service mesh can be used to apply policies to network communication, encrypt traffic between endpoints and for advanced routing. |
| 22 | + |
| 23 | +<img src="https://istio.io/latest/img/istio-bluelogo-whitebackground-unframed.svg" width="10%" alt="Istio logo"> |
| 24 | + |
| 25 | +[Istio](https://istio.io) is one of the most popular service meshes available for use with Kubernetes and with help from the team at Google, we've recently updated the support and documentation for using Istio with OpenFaaS. |
| 26 | + |
| 27 | +The value for users is: |
| 28 | +* Providing more advanced and flexible policy than Kubernetes' NetworkPolicies |
| 29 | +* Encrypting traffic between all OpenFaaS components and functions for "zero trust" |
| 30 | +* Providing advanced networking like retries, and weighting for canaries and gradual rollouts of new functions |
| 31 | + |
| 32 | +Thank you to [John Howard](https://github.com/howardjohn) from Google for helping us with this work and to [Lucas Roesler](https://github.com/lucasroesler) for reviewing and testing the work. |
| 33 | + |
| 34 | +In this blog post we'll give you a quick introduction so that you can start integrating Istio with OpenFaaS. We'll then go on to show you how to measure the resource consumption of the cluster, and how to create a TLS certificate for the Istio Gateway. |
| 35 | + |
| 36 | +There are many service mesh products available. Other popular options include: [Linkerd](https://linkerd.io), [Kuma](https://kuma.io/) and [Consul](https://learn.hashicorp.com/tutorials/consul/service-mesh). |
| 37 | + |
| 38 | +> You may also like the workshop we created to show how to do mutual TLS and traffic shifting with [OpenFaaS and Linkerd](https://github.com/openfaas/openfaas-linkerd-workshop). |
| 39 | +
|
| 40 | +## Tutorial |
| 41 | + |
| 42 | +We are using arkade, the open source marketplace to download CLIs and to install the apps we need. You can also do this the hard way if you prefer, just refer to the documentation or the helm chart for more. |
| 43 | + |
| 44 | +### Bootstrap the cluster |
| 45 | + |
| 46 | +Create a local cluster for testing: |
| 47 | + |
| 48 | +```bash |
| 49 | +arkade get kind |
| 50 | + |
| 51 | +kind create cluster \ |
| 52 | + --name openfaas-istio |
| 53 | +``` |
| 54 | + |
| 55 | +### Add Istio |
| 56 | + |
| 57 | +Once up and running, install Istio: |
| 58 | + |
| 59 | +```bash |
| 60 | +arkade install istio |
| 61 | +``` |
| 62 | + |
| 63 | +At time of writing this installs Istio 1.9. |
| 64 | + |
| 65 | +### Install OpenFaaS |
| 66 | + |
| 67 | +Now install OpenFaaS using the following changes: |
| 68 | + |
| 69 | +The `gateway.directFunctions=true` flag prevents OpenFaaS from trying to do its own endpoint load-balancing between function replicas, and defers to Envoy instead. Envoy is configured for each pod by Istio and handles routing and retries. |
| 70 | + |
| 71 | +The `istio.mtls` flag is optional, but when set encrypts the traffic between each of the pods in the `openfaas` and `openfaas-fn` namespace. |
| 72 | + |
| 73 | +```bash |
| 74 | +arkade install openfaas \ |
| 75 | + --set gateway.directFunctions=true \ |
| 76 | + --set istio.mtls=true |
| 77 | +``` |
| 78 | + |
| 79 | +At this point everything is configured and you can use OpenFaaS. |
| 80 | + |
| 81 | +### Deploy a test function |
| 82 | + |
| 83 | +Create an Istio Gateway so that we can connect to the OpenFaaS Gateway and log in. |
| 84 | + |
| 85 | +```bash |
| 86 | +# gateway.yaml |
| 87 | +cat > gateway.yaml <<EOF |
| 88 | +apiVersion: networking.istio.io/v1alpha3 |
| 89 | +kind: Gateway |
| 90 | +metadata: |
| 91 | + name: openfaas-gateway |
| 92 | + namespace: openfaas |
| 93 | +spec: |
| 94 | + selector: |
| 95 | + istio: ingressgateway # use istio default controller |
| 96 | + servers: |
| 97 | + - port: |
| 98 | + number: 80 |
| 99 | + name: http |
| 100 | + protocol: HTTP |
| 101 | + hosts: |
| 102 | + - "*" |
| 103 | +--- |
| 104 | +apiVersion: networking.istio.io/v1alpha3 |
| 105 | +kind: VirtualService |
| 106 | +metadata: |
| 107 | + name: openfaas-api |
| 108 | + namespace: openfaas |
| 109 | +spec: |
| 110 | + hosts: |
| 111 | + - "*" |
| 112 | + gateways: |
| 113 | + - openfaas-gateway |
| 114 | + http: |
| 115 | + - match: |
| 116 | + - uri: |
| 117 | + prefix: / |
| 118 | + route: |
| 119 | + - destination: |
| 120 | + host: gateway |
| 121 | + port: |
| 122 | + number: 8080 |
| 123 | +EOF |
| 124 | + |
| 125 | +kubectl apply -f gateway.yaml |
| 126 | +``` |
| 127 | + |
| 128 | +Port-forward the Istio Ingress Gateway: |
| 129 | + |
| 130 | +```bash |
| 131 | +kubectl port-forward -n istio-system \ |
| 132 | + svc/istio-ingressgateway \ |
| 133 | + 8080:80 \ |
| 134 | + 8443:443 & |
| 135 | +``` |
| 136 | + |
| 137 | +Log in: |
| 138 | + |
| 139 | +```bash |
| 140 | +PASSWORD=$(kubectl get secret -n openfaas basic-auth -o jsonpath="{.data.basic-auth-password}" | base64 --decode; echo) |
| 141 | +echo -n $PASSWORD | faas-cli login --username admin --password-stdin |
| 142 | +``` |
| 143 | + |
| 144 | +```bash |
| 145 | +# Find something you are interested in with: |
| 146 | +faas-cli store list |
| 147 | + |
| 148 | +# Deploy one of the functions |
| 149 | +faas-cli store deploy nodeinfo |
| 150 | +``` |
| 151 | + |
| 152 | +Invoke the function via the Istio Ingress gateway: |
| 153 | + |
| 154 | +```bash |
| 155 | +echo | faas-cli invoke nodeinfo |
| 156 | +``` |
| 157 | + |
| 158 | +Describe the Function's deployment, so you can see that the Istio proxy (Envoy) has been configured: |
| 159 | + |
| 160 | +``` |
| 161 | +kubectl describe pod -n openfaas-fn |
| 162 | +
|
| 163 | +Events: |
| 164 | + Type Reason Age From Message |
| 165 | + ---- ------ ---- ---- ------- |
| 166 | + Normal Scheduled 48s default-scheduler Successfully assigned openfaas-fn/nodeinfo-857d9c469b-ww66k to openfaas-istio-control-plane |
| 167 | + Normal Pulling 47s kubelet Pulling image "docker.io/istio/proxyv2:1.9.1" |
| 168 | + Normal Pulled 46s kubelet Successfully pulled image "docker.io/istio/proxyv2:1.9.1" in 938.690323ms |
| 169 | + Normal Created 46s kubelet Created container istio-init |
| 170 | + Normal Started 46s kubelet Started container istio-init |
| 171 | + Normal Pulling 46s kubelet Pulling image "ghcr.io/openfaas/nodeinfo:latest" |
| 172 | + Normal Pulled 38s kubelet Successfully pulled image "ghcr.io/openfaas/nodeinfo:latest" in 8.160064746s |
| 173 | + Normal Created 38s kubelet Created container nodeinfo |
| 174 | + Normal Started 38s kubelet Started container nodeinfo |
| 175 | + Normal Pulling 38s kubelet Pulling image "docker.io/istio/proxyv2:1.9.1" |
| 176 | + Normal Pulled 37s kubelet Successfully pulled image "docker.io/istio/proxyv2:1.9.1" in 925.80937ms |
| 177 | + Normal Created 37s kubelet Created container istio-proxy |
| 178 | + Normal Started 37s kubelet Started container istio-proxy |
| 179 | +``` |
| 180 | + |
| 181 | +## Going Further |
| 182 | + |
| 183 | +### Measuring the effects |
| 184 | + |
| 185 | +There is a cost involved with installing a service mesh like Istio. There will be additional RAM required, additional control-plane components to configure and keep updated, along with additional latency and cold-start times for scaling functions from zero. |
| 186 | + |
| 187 | +If you would like to understand the quiescent load on the cluster, you can install the Kubernetes metrics-server through arkade: |
| 188 | + |
| 189 | +```bash |
| 190 | +arkade install metrics-server |
| 191 | + |
| 192 | +# Wait a few minutes for data collection, then run: |
| 193 | +kubectl top node |
| 194 | +kubectl top pod -A |
| 195 | +``` |
| 196 | + |
| 197 | +### Getting a TLS certificate |
| 198 | + |
| 199 | +Let's now get a TLS certificate so that we can serve traffic to clients securely. |
| 200 | + |
| 201 | +First, create a DNS A record for the IP address of the Istio Ingress gateway using your preferred cloud dashboard and DNS service. |
| 202 | + |
| 203 | +```bash |
| 204 | +kubectl get svc -n istio-system istio-ingressgateway |
| 205 | +NAME TYPE CLUSTER-IP EXTERNAL-IP |
| 206 | +istio-ingressgateway LoadBalancer 10.106.200.195 <pending> |
| 207 | +``` |
| 208 | +If you're running within a private VPC, on-premises or on your laptop, then you will need to get a public IP for Istio through the inlets-operator. See a full guide to [setting up the inlets-operator with Istio](https://blog.alexellis.io/a-bit-of-istio-before-tea-time/) to provide an IP via a secure tunnel. That will then change `<pending>` to a fully accessible IP. |
| 209 | + |
| 210 | +Otherwise, copy the IP or CNAME issued to you under `EXTERNAL-IP` and create your DNS entry. I'll be using the domain `faas.o6s.io`. |
| 211 | + |
| 212 | +You can get a TLS certificate to serve traffic over HTTPS using cert-manager. |
| 213 | + |
| 214 | +```bash |
| 215 | +arkade install cert-manager |
| 216 | +``` |
| 217 | + |
| 218 | +Now create an `Issuer` and register it with [Let's Encrypt](https://letsencrypt.org/): |
| 219 | + |
| 220 | +```bash |
| 221 | +export EMAIL="you@example.com" |
| 222 | + |
| 223 | +cat > issuer.yaml <<EOF |
| 224 | +apiVersion: cert-manager.io/v1 |
| 225 | +kind: Issuer |
| 226 | +metadata: |
| 227 | + name: letsencrypt-prod |
| 228 | + namespace: istio-system |
| 229 | +spec: |
| 230 | + acme: |
| 231 | + server: https://acme-v02.api.letsencrypt.org/directory |
| 232 | + email: $EMAIL |
| 233 | + privateKeySecretRef: |
| 234 | + name: letsencrypt-prod |
| 235 | + solvers: |
| 236 | + - selector: {} |
| 237 | + http01: |
| 238 | + ingress: |
| 239 | + class: istio |
| 240 | +EOF |
| 241 | +kubectl apply -f issuer.yaml |
| 242 | +``` |
| 243 | + |
| 244 | +Define a certificate: |
| 245 | + |
| 246 | +```bash |
| 247 | +export DOMAIN="faas.o6s.io" |
| 248 | + |
| 249 | +cat > cert.yaml <<EOF |
| 250 | +apiVersion: cert-manager.io/v1alpha2 |
| 251 | +kind: Certificate |
| 252 | +metadata: |
| 253 | + name: ingress-cert |
| 254 | + namespace: istio-system |
| 255 | +spec: |
| 256 | + secretName: ingress-cert |
| 257 | + commonName: $DOMAIN |
| 258 | + dnsNames: |
| 259 | + - $DOMAIN |
| 260 | + issuerRef: |
| 261 | + name: letsencrypt-prod |
| 262 | + kind: Issuer |
| 263 | +EOF |
| 264 | +kubectl apply -f cert.yaml |
| 265 | +``` |
| 266 | + |
| 267 | +You can then check the status of the issuer and certificate: |
| 268 | + |
| 269 | +```bash |
| 270 | +kubectl get issuer -n istio-system -o wide |
| 271 | +NAME READY STATUS AGE |
| 272 | +letsencrypt-prod True The ACME account was registered with the ACME server 2m22s |
| 273 | + |
| 274 | +kubectl get certificate -n istio-system -o wide |
| 275 | +NAME READY SECRET ISSUER STATUS AGE |
| 276 | +ingress-cert True ingress-cert letsencrypt-prod Certificate is up to date and has not expired 30s |
| 277 | +``` |
| 278 | + |
| 279 | +Now finally update the IngressGateway we created earlier so that it uses the domain we have defined such as `faas.o6s.io`. |
| 280 | + |
| 281 | +```bash |
| 282 | +# gateway.yaml |
| 283 | +cat > gateway.yaml <<EOF |
| 284 | +apiVersion: networking.istio.io/v1alpha3 |
| 285 | +kind: Gateway |
| 286 | +metadata: |
| 287 | + name: openfaas-gateway |
| 288 | + namespace: openfaas |
| 289 | +spec: |
| 290 | + selector: |
| 291 | + istio: ingressgateway |
| 292 | + servers: |
| 293 | + - port: |
| 294 | + number: 443 |
| 295 | + name: https |
| 296 | + protocol: HTTPS |
| 297 | + tls: |
| 298 | + mode: SIMPLE |
| 299 | + credentialName: ingress-cert |
| 300 | + hosts: |
| 301 | + - faas.o6s.io |
| 302 | +EOF |
| 303 | + |
| 304 | +kubectl apply -f gateway.yaml |
| 305 | +``` |
| 306 | + |
| 307 | +At this point you can log into OpenFaaS via its public URL and access the nodeinfo function: |
| 308 | + |
| 309 | +```bash |
| 310 | +export OPENFAAS_URL="https://faas.o6s.io" |
| 311 | +echo -n $PASSWORD | faas-cli login --username admin --password-stdin |
| 312 | + |
| 313 | +Calling the OpenFaaS server to validate the credentials... |
| 314 | + |
| 315 | +credentials saved for admin https://faas.o6s.io |
| 316 | +``` |
| 317 | + |
| 318 | +Invoke the function: |
| 319 | + |
| 320 | +```bash |
| 321 | +curl -s -d "" $OPENFAAS_URL/function/nodeinfo |
| 322 | +``` |
| 323 | + |
| 324 | +## Wrapping up |
| 325 | + |
| 326 | +In a short period of time we were able to deploy Istio and OpenFaaS on a local KinD cluster and see Envoy's sidecar providing mutual TLS encryption. We then went on to explore the additional resource consumption added by using Istio, and finally showed you how to create a TLS certificate for external traffic using a free certificate from Let's Encrypt. |
| 327 | + |
| 328 | +If you wanted to take things further, you could look into more advanced policies for routing and traffic shifting or partial weighting using [VirtualServices](https://istio.io/latest/docs/reference/config/networking/virtual-service/) for individual functions. |
| 329 | + |
| 330 | +> You may also like the workshop we created to show how to do mutual TLS and traffic shifting with [OpenFaaS and Linkerd](https://github.com/openfaas/openfaas-linkerd-workshop). |
| 331 | +
|
| 332 | +Do you have questions, comments or suggestions? |
| 333 | + |
| 334 | +* Find out more about [Istio](https://istio.io) |
| 335 | +* Join [OpenFaaS Slack](https://slack.openfaas.io/) |
0 commit comments