Deploy MongoDB on Kubernetes with ArgoCD and Helm charts
Tags: kubernetes, opensource, database, cloudnative
Published: 2024-04-23 09:17:45

According to [CNCF GitOps Microsurvey](https://www.cncf.io/wp-content/uploads/2023/11/CNCF_GitOps-Microsurvey_Final.pdf), adoption of GitOps among Kubernetes practitioners is growing and ArgoCD and Flux are the most widely used CNCF GitOps projects. The desire to simplify application deployment and management in Kubernetes also makes sense, as complexity in Cloud Native space is the most common challenge. 

Databases on Kubernetes are complex as well, but Operators take away toil from administrators and developers. In this blog post we will simplify day-1 and day-2 operations for Databases on Kubernetes with a synergetic mix of ArgoCD and Operators, using [Percona Operator for MongoDB](https://docs.percona.com/percona-operator-for-mongodb/index.html) as an example.

## Choosing a strategy

ArgoCD allows the use of both regular YAML manifests and Helm charts. In conversations with our users, we see the tendency to use helm charts when those are available. Helm charts are a universal way to deploy and manage applications on Kubernetes, as a result easier onboarding.

YAMLs though can enable better flexibility, as it gives a direct exposure to manifests. 

In this article we provide an example for using Helm charts. Read [Deploy PostgreSQL on Kubernetes using Gitops and ArgoCD](https://www.percona.com/blog/deploy-postgresql-on-kubernetes-using-gitops-and-argocd/) to get an idea on how to deal with the YAML manifests case, it can be easily adapted for Percona Operator for MongoDB.

## Prepare the environment

For starters, you need the following:
Kubernetes cluster
Helm chart. In this article we use the official [Percona helm charts](https://github.com/percona/percona-helm-charts).

### Deploy and configure ArgoCD

ArgoCD has [detailed documentation](https://argo-cd.readthedocs.io/en/stable/) explaining the installation process. I did the following:

```
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
```

## Action

![ArgoCD with Percona Operator for MongoDB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iupdfshdumd8aon734d3.png)

The flow is the following:

1. User creates the Argo Application resources
2. ArgoCD syncs with the helm repository
3. ArgoCD provisions the resources based on ArgoCD application definitions and syncs with the Helm repository
4. User connects to the database once it is provisioned

One of the key parts to grasp is that ArgoCD uses helm repository as a source of truth, but it does not deploy helm directly in the Kubernetes cluster. So in the helm list output you will not see anything.

### Custom Resource Definitions (CRDs)

CRDs allow users to extend the Kubernetes API. Operators process Custom Resources (CRs) that users create and as a result deploy and manage applications. Custom Resource Definitions must be created before users start creating CRs. 

ArgoCD provides a way to sequence the provisioning of the resources, but only within a single application. In the case of a helm chart, we have two different Argo applications. 

The best practice here is to ensure that the application that has CRDs is provisioned first. Usual approach is to have role separation. Where Kubernetes cluster administrators provision CRDs and other roles, like developers or DBAs, only focus on database components. 

Application to deploy CRDs - [`argo_psmdb_operator.yaml`](https://github.com/spron-in/blog-data/blob/master/gitops-mongo/argo_psmdb_operator.yaml):

```
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: psmdb-operator
  namespace: argocd
spec:
  project: default
  syncPolicy:
    automated: {}
    syncOptions:
    - ServerSideApply=true
  source:
    chart: psmdb-operator
    path: charts/psmdb-operator/
    repoURL: https://percona.github.io/percona-helm-charts/
    targetRevision: 1.15.4
    helm:
      releaseName: psmdb-operator
  destination:
    server: "https://kubernetes.default.svc"
    namespace: default
```

Some things to note:
`- ServerSideApply=true` - is a must, otherwise CRD creation will fail with the following error:

```
time="2024-04-17T14:58:31Z" level=info msg="Updating operation state. phase: Running -> Running, message: 'one or more objects failed to apply, reason: CustomResourceDefinition.apiextensions.k8s.io \"perconaservermongodbs.psmdb.percona.com\" is invalid: metadata.annotations: Too long: must have at most 262144 bytes. Retrying attempt #5 at 2:57PM.' -> 'one or more tasks are running'" application=argocd/psmdb-operator syncId=00006-HyBZr
```

We enable automated sync in the example, this might not be desired for your use case. Read more about synchronization in the [documentation](https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/).

Check if application is synchronized:

```
% kubectl -n argocd get application psmdb-operator
NAME             SYNC STATUS   HEALTH STATUS
psmdb-operator   Synced        Healthy
```
 
Once it is synced, you should be able to see the Operator Pod and CRDs deployed.

### Deploy the Percona Server for MongoDB cluster

There is no difference between deploying CRDs with Operator and the Custom Resource for database cluster. We use another helm chart and also add extra parameters as an example - [`argo_psmdb_db.yaml`](https://github.com/spron-in/blog-data/blob/master/gitops-mongo/argo_psmdb_db.yaml):

```
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: psmdb-db
  namespace: argocd
spec:
  project: default
  syncPolicy:
    automated: {}
  source:
    chart: psmdb-db
    path: charts/psmdb-db/
    repoURL: https://percona.github.io/percona-helm-charts/
    targetRevision: 1.15.3
    helm:
      releaseName: psmdb-db
      valuesObject:
	  sharding:
          enabled: false
	  ...
  destination:
    server: "https://kubernetes.default.svc"
    namespace: default
```


Attention to `valuesObjects` section, where we provide some examples of passing [`values.yaml`](https://github.com/percona/percona-helm-charts/blob/main/charts/psmdb-db/values.yaml) variables. There are three ways how it can be done:

1. valuesObjects - the one in our example
2. values:

```
source:
  helm:
    values: |
      sharding:
        enabled: false
      ...
```

3. values files:

```
source:
  helm:
    valueFiles:
    - myvalues.yaml
```


If you do everything correctly, you would see the application synchronized and Custom Resource deployed:

```
% kubectl -n argocd get application psmdb-db
NAME       SYNC STATUS   HEALTH STATUS
psmdb-db   Synced        Healthy


% kubectl get psmdb
NAME       ENDPOINT   STATUS         AGE
psmdb-db   ...        ready          73s
```


## Conclusion

Deploying the [Percona Operator for MongoDB](https://github.com/percona/percona-server-mongodb-operator) using ArgoCD represents a significant step forward in managing complex database systems within Kubernetes. By integrating Helm charts with GitOps principles, organizations can achieve more consistent, scalable, and error-resistant deployments. 

As the cloud-native ecosystem continues to evolve, tools like ArgoCD and Kubernetes Operators will play increasingly critical roles. Their ability to reduce manual overhead and streamline operations is crucial in an environment where agility and reliability are paramount. We encourage practitioners to explore these technologies, experiment with the configurations discussed, and contribute back to the community with any findings or improvements.

Percona is committed to provide open source solutions to deploy and manage databases anywhere. Try out our operators or check the Beta version of an open source cloud native database platform - [Percona Everest](https://docs.percona.com/everest/index.html). It provides a nice GUI and API to deploy databases on Kubernetes. 

[100% open source Operator for MongoDB](https://docs.percona.com/percona-operator-for-mongodb/index.html) | [Deploy MongoDB with Percona Everest](https://docs.percona.com/everest/index.html)