Grab free TLS & Custom Domains for your Functions with FunctionIngress

With OpenFaaS, you get a URL for every function by convention which is great and suits many people. This guide shows you how to get a Custom Domain along with a free TLS cert for your functions using the new FunctionIngress concept.

July 29, 2019
Community
End-user
Ingress
Production
Kubernetes


Find out how you can expand beyond the default URL given to each function in OpenFaaS with the new FunctionIngress CRD.

In this tutorial I’ll show you how to use the new FunctionIngress Custom Resource Definition (CRD) along with a new Kubernetes Operator to get Custom Domains for any OpenFaaS function deployed on Kubernetes.

How it works

First of all, we install the new Kubernetes Operator called “IngressOperator”. This Operator is responsible for translating CRD entries called FunctionIngress into two separate resources in the cluster: an Ingress definition and a TLS Certificate. The TLS Certificate is optional, and created by cert-manager by adding special annotations to the generated Ingress definition.

I built the IngressOperator to automate some of the tasks end-users of the project were using to deploy pretty-URLs for their static websites, APIs and functions with OpenFaaS. The first time I wrote about the Operator was in the Insiders Update for 2019-07-05.

Tutorial

To run through the tutorial, you will need to have some software set up already and a Kubernetes cluster with a public LoadBalancer service. If your Kubernetes services does not have a public LoadBalancer, install the IngressController using host ports.

Pre-reqs

  • Kubernetes
    You need to have a Kubernetes cluster. I recommend using DigitalOcean Kubernetes for an easy and cost-efficient set-up.

  • helm
    You’ll need helm for most of the components we are using. If you are allergic to helm’s server-side component called “tiller”, then don’t worry. You can simply use the “helm template” command to generate plain YAML files.

  • OpenFaaS via helm
    Install OpenFaaS via helm

  • The IngressController
    Nginx, Traefik and Zalando’s Skipper are currently supported, if you have a request for another controller, then raise an issue.

In this tutorial I’ll be using Nginx, install with the following:

helm install stable/nginx-ingress --name nginxingress --set rbac.create=true
  • cert-manager (optional)
    Using TLS is optional, but highly recommended and I will be setting it up today.

Follow the steps for “Install cert-manager” and “Configure cert-manager” from the OpenFaaS documentation here.

Deploy IngressOperator

We’ll now deploy the IngressOperator.

You’ll need to find your values.yaml file for the OpenFaaS Helm chart, then add:

ingressOperator:
  create: true

Then run a helm upgrade --install as per the Helm chart README.

Create a static website

We can use the Nginx static website template to create a function or microservice. Once deployed, we’ll move on to creating its custom domain name entry and then a CRD entry for it.

export OPENFAAS_PREFIX=alexellis2

faas template pull https://github.com/alexellis/static-site-template
faas new --lang static-site-nginx my-homepage --prefix ${OPENFAAS_PREFIX}

Set OPENFAAS_PREFIX with your own Docker Hub username, or private registry address and repo.

Create the homepage:

echo "<html>Hello world</html>" > ./my-homepage/index.html

The following will build a container image, push it to the remote registry and then deploy it to OpenFaaS, resulting in a static website.

faas-cli up -f my-homepage.yml

Your traditional URL will appear on:

faas-cli describe -f my-homepage.yml my-homepage

Name:                my-homepage
Status:              Ready
Replicas:            1
Available replicas:  0
Invocations:         0
Image:               alexellis2/my-homepage:latest
Function process:
URL:                 http://206.189.242.89:8080/function/my-homepage
Async URL:           http://206.189.242.89:8080/async-function/my-homepage
Labels:              faas_function : my-homepage

We’ll now create a DNS entry and then the custom hostname mapping and TLS certificate along with that.

Create a DNS A record for your sub-domain

My testing domain is myfaas.club and it cost me a very minimal amount of money from namecheap.com. I can create sub-domains for each function, or for any testing that I do. If you are familiar with DNS-management, then create an A record for the IP address of the LoadBalancer created by Nginx.

kubectl get svc
NAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
nginxingress-nginx-ingress-controller        LoadBalancer   10.245.169.18   178.128.137.209   80:32126/TCP,443:30028/TCP   32d

You can see my external IP listed as 178.128.137.209. As a DigitalOcean customer, I can now use the DigitalOcean UI or CLI to create a DNS A record for 178.128.137.209. Here is an example using the doctl CLI:

doctl compute domain create my-homepage.myfaas.club --ip-address 178.128.137.209

Domain                     TTL
my-homepage.myfaas.club    0

Map the Custom Domain with a FunctionIngress

Now we will map the Custom Domain to the function using a FunctionIngress definition.

Save the following in a YAML file my-homepage-fni.yaml:

apiVersion: openfaas.com/v1
kind: FunctionIngress
metadata:
  name: my-homepage-tls
  namespace: openfaas
spec:
  domain: "my-homepage.myfaas.club"
  function: "my-homepage"
  ingressType: "nginx"
  tls:
    enabled: true
    issuerRef:
      name: "letsencrypt-prod"
      kind: "Issuer"
  • For the name I used a convention of the function’s name plus a suffix of -tls if using TLS.
  • Edit the domain to point as your own DNS A record or sub-domain.
  • For the issuerRef, you can use the -staging or -prod issuer which you set up earlier using the OpenFaaS docs.

Now apply the file with kubectl apply -f my-homepage-fni.yaml

Check what happened

We already have a URL to access our static website, but after having created the FunctionIngress, we’ll get a HTTPS URL too. This is what happens:

  • The CRD is detected and an Ingress record is created
  • The Ingress record is decorated with information about TLS
  • CertManager detects the TLS information using something called IngressShim
  • CertManager creates the TLS certificate

Check the ingress:

kubectl get ingress -n openfaas

NAME              HOSTS                      ADDRESS        PORTS     AGE
my-homepage-tls   my-homepage.myfaas.club    167.71.8.102   80, 443   46s

Now check the certificate:

kubectl get cert -n openfaas

NAME                          READY   SECRET                               AGE
my-homepage-tls-certificate   true    my-homepage-tls-certificate-secret   2m37s

Note, if it appears as “Not Ready” for a long time, you can debug it with: kubectl describe cert/my-homepage-tls-certificate -n openfaas

The objects above were created automatically, so they will be deleted or edited if you delete or edit the FunctionIngress custom resource. You can find out what happened inside the Operator by checking its logs:

kubectl logs -n openfaas deploy/ingress-operator

Try out your brand new Custom Domain

Congratulations! You can now create Custom Domains for any of your functions or microservices deployed with OpenFaaS, and add TLS too.

Changing versions

We can now create a dedicated URL for anything we deploy through OpenFaaS. There’s nothing to stop you deploying multiple names for the same function to create an alias or versioned endpoint. If we were to deploy a new version of our function (my-homepage-v2), we could deploy a new FunctionIngress record, or simply edit the object in Kubernetes via kubectl. The result is that the Ingress record will be edited to point at the new function without deleting or re-issuing a new Certificate.

apiVersion: openfaas.com/v1
kind: FunctionIngress
metadata:
  name: my-homepage-tls
  namespace: openfaas
spec:
  domain: "my-homepage.myfaas.club"
  function: "my-homepage-v2"
  ingressType: "nginx"
  tls:
    enabled: true
    issuerRef:
      name: "letsencrypt-prod"
      kind: "Issuer"

Connect & Learn

I hope you enjoyed the tutorial for the IngressOperator and FunctionIngress CRD. In the next post the community will show you how to combine this blog post with OpenFaaS Cloud and a template for Hugo to generate static websites from markdown. This would be great for hosting documentation, blogs and much more.