In this post you’ll learn how to manage OpenFaaS functions based on GitOps principles by using ArgoCD

What is GitOps?

Alexis Richardson coined the term GitOps in 2017. Since then it’s gained significant interest in the enterprise companies because it allows for easier auditing of deployments.

With a GitOps approach, build artifacts from your Continuous Integration (CI) pipeline are deployed to your cluster. The desired state is set in a number of configuration files in a Git repository, and a second agent component runs inside the cluster to compare the delta. The differences are known as drift, and the agent’s role is to detect and correct it.

Separation of CI and CD

From Weaveworks.com

In the diagram above, we can see that GitOps separates our code repository, where our teams push and test code, from the repo containing deployment information, aka “config repo”. When new images or artifacts are created, the tags and versions in the config repo can be updated automatically or via a separate commit from a team member.

Two of the most popular open-source projects for GitOps are Flux, which was created at Weaveworks. Intuit, an American payroll company created ArgoCD. Both projects were donated to the Cloud Computing Foundation (CNCF) to encourage broader use and contributions.

We have previously looked at FluxCD with OpenFaaS, but in this post we’ll show how to use ArgoCD with the OpenFaaS Function CRD to continuously deploy your functions.

You can read more about ArgoCD on the project homepage.

Tutorial

In this section, we are going to create two application for ArgoCD, first one is OpenFaaS Operator, the second one is the repository that holds OpenFaaS functions manifest files.

ArgoCD can work against Kubernetes manifests in a various ways including kustomize, ksonnet, jsonnet, as well as other plugins which can generate YAML files that Kubernetes can apply. Today, we will be using a Helm chart and YAML manifests.

We will use the OpenFaaS Helm Chart to deploy OpenFaaS and its Operator. Once OpenFaaS Operator is deployed, we can use the Custom Resource called “Function” in order to define our OpenFaaS functions like any other Kubernetes resources such as Deployment, Pod etc.

In the second part, we’ll to use plain manifests to deploy OpenFaaS functions. A dedicated chart can also be created for deploying functions.

Conceptual architecture

Conceptual architecture

Conceptual architecture: ArgoCD monitoring two repositories and deploying OpenFaaS along with a set of functions

A recap on the OpenFaaS Operator

We need to use the Operator, because Argo can only apply Kubernetes YAML files, and cannot use the OpenFaaS REST API at this time. The normal installation of OpenFaaS uses its REST API to create functions using the CLI, REST API or UI. It also has a mode called “operator mode” where a Custom Resource can be used with kubectl to apply and deploy functions.

apiVersion: openfaas.com/v1
kind: Function
metadata:
  name: nodeinfo
  namespace: openfaas-fn
spec:
  name: nodeinfo
  image: functions/nodeinfo:latest

The faas-cli generate command can be used to convert the OpenFaaS stack.yml file into the Function CustomResource for use with kubectl.

The OpenFaaS Operator comes with an extension to the Kubernetes API that allows you to manage OpenFaaS functions in a declarative manner. The operator implements a control loop that tries to match the desired state of your OpenFaaS functions, defined as a collection of custom resources, with the actual state of your cluster.

To get more detail please refer to this link.

Prerequisites

Once we have arkade, we can create a cluster and install ArgoCD. If you prefer, you can also manually download all the tools required, and find the instructions for ArgoCD’s helm chart.

  • arkade (v0.7.10) Kubernetes marketplace
  # Run with or without sudo
  $ curl -sLS https://dl.get-arkade.dev | sudo sh
  • KinD (Kubernetes in Docker) v0.10.0

    Kubernetes is our recommendation for teams running at scale, but in this demo we will be using KinD for the sake of simplicity.

    $ arkade get kind --version=v0.10.0
    
  • kubectl v1.21.0

    You can control your cluster using kubectl CLI.

    $ arkade get kubectl --version=v1.21.0
    
  • ArgoCD CLI v2.0.0

    ArgoCD CLI controls an Argo CD server. More detailed installation instructions can be found via the CLI installation documentation. Fortunately, we can install it via arkade too.

    $ arkade get argocd --version=v2.0.0
    

Setup

1. Provision a local Kubernetes Cluster with KinD

You can start a Kubernetes cluster with KinD if you don’t have one already.

$ kind create cluster

Verify if your cluster working properly before moving onto the next step.

$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:49809
KubeDNS is running at https://127.0.0.1:49809/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

2. Deploy ArgoCD

There are various ways to install ArgoCD, one of them is ArgoCD Operator, and the other one is just with plain YAML manifest. We are going to deploy ArgoCD with plain YAML manifest in this section.

arkade is not only for the CLI tooling, it also helps you to get started to install applications using helm under the hood, hopefully arkade also supports installing ArgoCD.

$ kubectl create namespace argocd
$ arkade install argocd

Verify if everything is working properly in argocd namespace before moving onto the next step.

$ kubectl get pods --namespace argocd
NAME                                  READY   STATUS    RESTARTS   AGE
argocd-application-controller-0       1/1     Running   0          86s
argocd-dex-server-5dd657bd9-zkhb8     1/1     Running   0          86s
argocd-redis-759b6bc7f4-92l4b         1/1     Running   0          86s
argocd-repo-server-6c495f858f-rx8hh   1/1     Running   0          86s
argocd-server-859b4b5578-sczvk        1/1     Running   0          86s

3. Deploy OpenFaaS Operator and OpenFaaS functions through ArgoCD

There are two ways of defining applications to ArgoCD, one of them is by using CLI, the other one is by using CRDs. We are going to demonstrate both of them in here.

Option 1: by using CLI

First, we need to authenticate to ArgoCD server.Argo CD v1.9. Later the initial password for the admin account is auto-generated and stored as clear text in the field password in a secret named argocd-initial-admin-secret in your Argo CD installation namespace.

You can simply retrieve this password using kubectl:

$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
SyudUgAtDobmgSjM

Because ArgoCD Server is running on a Kubernetes, we should do port-forwarding first in order to access the server, it can be achieved by the following command easily:

$ kubectl port-forward svc/argocd-server -n argocd 8080:443
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

After that, by using the username admin and the password from above, lets log into ArgoCD:

$ argocd login --name local localhost:8080
WARNING: server certificate had error: x509: certificate signed by unknown authority. Proceed insecurely (y/n)? y
Username: admin
Password:
'admin:login' logged in successfully
Context 'local' updated

To get more detail about login process, please refer to this link.

Verify if you log into ArgoCD properly before moving on the next step.

$ argocd account list
NAME   ENABLED  CAPABILITIES
admin  true     login

$ argocd app list
NAME  CLUSTER  NAMESPACE  PROJECT  STATUS  HEALTH  SYNCPOLICY  CONDITIONS  REPO  PATH  TARGET

After you logged into ArgoCD, lets create our applications.

$ kubectl create namespace openfaas
namespace/openfaas created

$ kubectl create namespace openfaas-fn
namespace/openfaas-fn created

$ argocd app create openfaas-operator \
      --repo https://github.com/openfaas/faas-netes.git \
      --dest-namespace openfaas \
      --dest-server https://kubernetes.default.svc \
      --path chart/openfaas \
      --helm-set operator.create=true \
      --helm-set generateBasicAuth=true \
      --helm-set functionNamespace=openfaas-fn \
      --self-heal \
      --sync-policy automatic
application 'openfaas-operator' created

When deploying internally (to the same cluster that Argo CD is running in), https://kubernetes.default.svc should be used as the application’s K8s API server address. To get more detail about registering another cluster to deploy apps to, please refer to this link.

Verify if everything is working before moving onto the next step.

First, check the application status:

$  argocd app list -o wide
NAME               CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                        PATH            TARGET
openfaas-operator  https://kubernetes.default.svc  openfaas   default  Synced  Healthy  Auto        <none>      https://github.com/openfaas/faas-netes.git  chart/openfaas

Then, check the openfaas namespace for the installation:

$ kubectl get pods --namespace openfaas
NAME                                 READY   STATUS    RESTARTS   AGE
alertmanager-84d7b88f74-kt7jg        1/1     Running   0          4m6s
basic-auth-plugin-85d885557c-cgz4j   1/1     Running   0          4m6s
gateway-764b7b4865-p4rk8             2/2     Running   1          4m6s
nats-5fdf6476f-pmftg                 1/1     Running   0          4m6s
prometheus-844fffb-5rkc7             1/1     Running   0          4m6s
queue-worker-7cbc9f8688-qfww6        1/1     Running   0          4m6s

Before deploying OpenFaaS functions as custom resources, check the available CRDs on the Kubernetes, you should see the list like the following:

$ kubectl get customresourcedefinitions.apiextensions.k8s.io
NAME                       CREATED AT
applications.argoproj.io   2021-04-09T09:33:59Z
appprojects.argoproj.io    2021-04-09T09:33:59Z
functions.openfaas.com     2021-04-09T10:43:03Z
profiles.openfaas.com      2021-04-09T10:43:03Z

If you see the same output above, it means you are now ready to deploy OpenFaaS functions.

I prepared a repository that holds the function definitions, so, before running the following code, don’t forget to fork your own copy of this repository and give it to ”–repo” flag.

$ argocd app create openfaas-functions \
      --repo https://github.com/developer-guy/bring-gitops-to-your-openfaas-functions-with-argocd.git \
      --dest-server https://kubernetes.default.svc \
      --path functions \
      --self-heal \
      --sync-policy automatic
application 'openfaas-functions' created

Verify if everything is working before moving onto the next step.

First, check the application status, now, you should see two applications:

$  argocd app list -o wide
NAME                CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                                                      PATH            TARGET
openfaas-functions  https://kubernetes.default.svc             default  Synced  Healthy  Auto        <none>      https://github.com/developer-guy/bring-gitops-to-your-openfaas-functions-with-argocd.git  functions
openfaas-operator   https://kubernetes.default.svc  openfaas   default  Synced  Healthy  Auto        <none>      https://github.com/openfaas/faas-netes.git

Then, check the openfaas-fn namespace for the installation:

$ kubectl get functions --namespace openfaas-fn
NAME       AGE
nodeinfo   35s

Verify if it is working.

$ kubectl get pods --namespace openfaas-fn
NAME                        READY   STATUS    RESTARTS   AGE
nodeinfo-6d5434f4744-l6kfd   1/1     Running   0          2m6s

Option 2: by using CRDs

We are going to apply apps-of-apps pattern in here, which means we can create an app that creates other apps, which in turn can create other apps. This allows you to declaratively manage a group of app that can be deployed and configured in concert. In order to do that, we create an apps-of-apps.yaml in the repository and within this manifest we refer to the exact path which holds the actual application manifests.

To get more detail about apps-of-apps pattern, please refer to this link.

Lets deploy the applications.

$ kubectl create namespace openfaas
namespace/openfaas created

$ kubectl create namespace openfaas-fn
namespace/openfaas-fn created

$ argocd app create apps-of-apps \
      --repo https://github.com/developer-guy/bring-gitops-to-your-openfaas-functions-with-argocd.git \
      --dest-server https://kubernetes.default.svc \
      --path . \
      --self-heal \
      --sync-policy automatic
application 'apps-of-apps' created

We just created one application called apps-of-apps in here, but if you look at the output of the list command, you should see three application:

$  argocd app list
NAME                CLUSTER                         NAMESPACE  PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                                                      PATH            TARGET
apps-of-apps        https://kubernetes.default.svc             default  OutOfSync  Healthy  Auto        <none>      https://github.com/developer-guy/bring-gitops-to-your-openfaas-functions-with-argocd.git  applications
openfaas-functions  https://kubernetes.default.svc             default  Synced     Healthy  Auto        <none>      https://github.com/developer-guy/bring-gitops-to-your-openfaas-functions-with-argocd.git  functions
openfaas-operator   https://kubernetes.default.svc  openfaas   default  OutOfSync  Missing  Auto        <none>      https://github.com/openfaas/faas-netes.git                                                chart/openfaas

Verify if everything is working.

$ kubectl get functions --namespace openfaas-fn
NAME       AGE
nodeinfo   35s

$ kubectl get pods --namespace openfaas-fn
NAME                        READY   STATUS    RESTARTS   AGE
nodeinfo-7c564f4744-l6kfd   1/1     Running   0          101s

Taking it further

Join the community

Have you got questions, comments, or suggestions? Join the community on Slack.

Would you like help to set up your OpenFaaS installation, or someone to call when things don’t quite go to plan? Our OpenFaaS PRO Subscription plan gives you a say in the project roadmap, a support contact, and access to Enterprise-grade authentication with OIDC.

Acknowledgements

References

Batuhan Apaydın

Life-long learner. Software engineer at @Trendyol