Today I’m going to show how you can get a Netlify-like experience for deploying your static sites with two great tools: Hugo and OpenFaaS. In a future blog post we will be discussing about the JAMstack and how you can integrate existing tools with OpenFaaS.
You need to have a Kubernetes cluster up & running. I recommend DigitalOcean, it’s cost-efficient and very easy to set-up.
You’ll need helm to install the components in the cluster. If you can’t install
Tiller, helm’s server-side component, in your cluster then you can use
For this tutorial you will need to install OpenFaaS using an ingress controller instead of exposing the gateway with a LoadBalancer. For this you’ll need to set
exposeServices=false when installing it.
- Install an Ingress Controller
Currently we support Nginx, Traefik and Zalando’s Skipper. We will be using Nginx for this tutorial:
helm install stable/nginx-ingress --name nginxingress --set rbac.create=true
- Install the cert-manager (optional)
Installing the cert-manager to get automatic TLS certificates is optional but I highly recommend it. I will be using it today.
Install the Ingress Operator
The Ingress Operator automatically manages the creation of custom ingress rules and TLS certificates for your functions using a new CRD called
FunctionIngress introduced by Alex in this blog post.
Lets deploy the operator to our cluster following the instructions at the documentation:
git clone https://github.com/openfaas-incubator/ingress-operator cd ingress-operator kubectl apply -f ./artifacts/operator-crd.yaml kubectl apply -f ./artifacts/operator-rbac.yaml kubectl apply -f ./artifacts/operator-amd64.yaml
Introducing the hugo template
Today I’m showing you a new template for creating hugo static sites that took me little to no time to make thanks to the simplicity and flexibility of OpenFaaS’s templating system. You can check it out here.
The template copies over the contents of your hugo site, builds it into the
public directory and then uses a very lightweight static server that serves the content and provides a healtcheck that follows the standards from OpenFaaS.
Create a new Hugo site
We can use the hugo template to create hugo sites and then serve them with custom domain names using OpenFaaS and the Ingress Operator. First lets create the site:
git init faas template pull https://github.com/matipan/openfaas-hugo-template faas new --lang hugo -g <openfaas gateway url> --prefix <docker hub username> example-site
This will create a folder called
cd into it and now create the site with this instructions from the hugo quickstart guide:
hugo new site . git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke echo 'theme = "ananke"' >> config.toml
At this point you can run
hugo server in that directory to build and test your site locally without needing to deploy it to OpenFaaS. Remember to update the
baseURL found in the
config.toml to the domain that you will be using.
Deploy your blog:
faas-cli up -f example-site.yml
Create a DNS A record for your sub-domain
I’m using my personal domain
matiaspan.dev that I got at namecheap.com. I can create sub-domains for each function. If you are familiar with DNS, then create an A record for the IP address of the LoadBalancer created for the ingress controller(i.e nginx):
kubectl get svc -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginxingress-nginx-ingress-controller LoadBalancer 10.245.116.147 220.127.116.11 80:31113/TCP,443:30596/TCP 2d21h
You can see that my external IP address is:
If you are getting started with DNS management I recommend DigitalOcean, it’s free and has a great developer experience. Here is how I use the CLI to create the record for
doctl compute domain create example.matiaspan.dev --ip-address 18.104.22.168 Domain TTL example.matiaspan.dev 0
And this is how the UI looks like:
Map the custom domain with a FunctionIngress
Now it’s time to map the custom domain with a
FunctionIngress, just like Alex showed in this blog post.
Save the following in a YAML file
apiVersion: openfaas.com/v1alpha2 kind: FunctionIngress metadata: name: example-site-tls namespace: openfaas spec: domain: "example.matiaspan.dev" function: "example-site" ingressType: "nginx" tls: enabled: true issuerRef: name: "letsencrypt-prod" kind: "Issuer"
- For the
nameI used a convention of the function’s name plus a suffix of -tls if using TLS.
- Edit the
domainto point as your own DNS A record or sub-domain
- For the
issuerRef, you can use the
-prodissuer which you set up earlier using the OpenFaaS docs. If you are not using TLS then remove the
tlssection from the file.
Now apply the file with
kubectl apply -f example-site-fni.yml
Check out your brand new site!
After creating the
FunctionIngress our Ingress Operator will detect the recently created CRD and create an ingress record. If you are using TLS this ingress will be decorated with annotations that the CertManager then detects and creates the TLS certificate for your site.
Check the ingress record:
kubectl get ingress -n openfaas NAME HOSTS ADDRESS PORTS AGE example-site-tls example.matiaspan.dev 22.214.171.124 80, 443 56s
Now the certificate:
kubectl get cert -n openfaas NAME READY SECRET AGE example-site-tls-cert True example-site-tls-cert 89s
If you modify or delete the
FunctionIngress then the certificate and the ingress will also be affected.
Navigate to your domain and check out your new site!
CI/CD with OpenFaaS Cloud
OpenFaaS Cloud can offer you an automated experience, with a single push you can have your site deployed in no time!
If this sounds interesting to you check out our “single click” bootstrap tool to install OpenFaaS Cloud in less than 100 seconds or apply for access to the Community Cluster.
After you’ve deployed OpenFaaS Cloud create a repository on GitHub(or your self hosted GitLab) called
example-site. Add this repository to your GitHub app or add the
openfaas-cloud tag if you are using GitLab.
Since we don’t do recursive clones in OpenFaaS Cloud you will need to clone your site’s theme instead of adding it as a submodule. Once you’ve done that commit and push your changes.
After a while, if you head over to your personal dashboard(find it at
system.<your domain>/dashboard/<username>) you will see your new function deployed.
FunctionIngress so that it points to our brand new function
kubectl edit -n openfaas functioningresses.openfaas.com example-site:
apiVersion: openfaas.com/v1alpha2 kind: FunctionIngress metadata: name: example-site-tls namespace: openfaas spec: domain: "example.matiaspan.dev" function: "<username>-example-site" ingressType: "nginx" tls: enabled: true issuerRef: name: "letsencrypt-prod" kind: "Issuer"
- You need to update the
functionto match with the new one. OpenFaaS Cloud deploys function using the following convention:
<username>-<function name>. If you are unsure about the name you can find it with
We won’t be using our previous function anymore so remove it:
faas-cli remove example-site
Try creating a new blog post with:
hugo new posts/my-first-post.md. Remember to run that command inside the folder of your hugo site, not the root folder of the project.
Commit and push your changes again, after OpenFaaS Cloud does its thing you will be able to see your new changes deployed. Awesome!
CI/CD with GitLab
If you can’t or don’t want to install OpenFaaS Cloud but you still want to have a Netlify-like experience then you can host your repository on GitLab and use their free CI/CD offerings. Save the following to a YAML file in the root folder of the repo
image: docker:stable stages: - build services: - docker:dind before_script: - apk add --no-cache git - if [ -f "./faas-cli" ] ; then cp ./faas-cli /usr/local/bin/faas-cli || 0 ; fi - if [ ! -f "/usr/local/bin/faas-cli" ] ; then apk add --no-cache curl git && curl -sSL cli.openfaas.com | sh && chmod +x /usr/local/bin/faas-cli && /usr/local/bin/faas-cli template pull && cp /usr/local/bin/faas-cli ./faas-cli ; fi build: stage: build script: - git submodule init && git submodule update # Build Docker image - /usr/local/bin/faas-cli template pull https://github.com/matipan/openfaas-hugo-template - /usr/local/bin/faas-cli build --tag=sha --parallel=2 # Login & Push Docker image to private repo - echo -n "$CI_DOCKER_LOGIN" | docker login --username $(echo -n "$CI_DOCKER_USERNAME") --password-stdin - /usr/local/bin/faas-cli push --tag=sha - echo -n "$CI_OF_PWD" | /usr/local/bin/faas-cli login --gateway $(echo -n "$CI_OF_GATEWAY") --username admin --password-stdin # Deploy function from private repo - /usr/local/bin/faas-cli deploy --tag=sha only: - master
Go to your project’s CI/CD page and set the following variables:
CI_DOCKER_LOGIN: the password for docker hub
CI_DOCKER_USERNAME: your docker username
CI_OF_PWD: the password for your OpenFaaS gateway
CI_OF_GATEWAY: the URL for your OpenFaaS gateway
Commit and push your changes and see how your function gets automatically built and deployed!
The hugo template we showed today combined with the Ingress Operator and OpenFaaS Cloud(or GitLab CI/CD) allowed us to create a great way to build and host sites for your project’s documentation, personal blogs and more.
I chose Hugo for today’s blog post but you can create another template for your favorite tool. Check out this static server for an easy way to serve the content built by your static site tool.
Hope you enjoyed today’s tutorial. Until next time!