Automatic review apps for microservices with ArgoCD

Learn how to use ArgoCD’s ApplicationSet to automatically deploy review apps for microservices using the PullRequestGenerator

Automatic review apps for microservices with ArgoCD
Diagram for deploying multiple services from GitLab as a single review app in ArgoCD

In this article, we will explain how to set up ArgoCD to automatically deploy review apps for GitLab Merge Requests (MRs), enabling your QA Tester or Customer to easily test and approve new features.

The principles for GitHub PRs or any other platform are almost identical, and if you have any additional questions on these platforms, feel free to reach out!

Application configuration

Creating a separate application on MR creation

To ensure that ArgoCD creates a new application once the MR has been created, we can use an ApplicationSet and add the Pull Request Generator. The Pull Request Generator utilizes the GitLab API to periodically poll for new/updated MRs and mirror applications for these MRs.

apiVersion: argoproj.io/v1alpha1 
kind: ApplicationSet 
spec: 
  generators: 
    - pullRequest: 
        gitlab: 
          project: "48042720" 
          api: https://gitlab.com/ 
          tokenRef: 
            secretName: gitlab-token 
            key: token 
          pullRequestState: opened 
  template: 
    metadata: 
      name: 'example-app-{{branch}}-{{number}}' 
    spec: 
      source: 
        repoURL: https://gitlab.com/argo-review-app-example/k8s-configuration-kustomize.git 
        path: example-app/overlays/qa 
        targetRevision: main 
        kustomize: 
          commonAnnotations: 
            app/param-host: pr-{{number}}.somedomain.com 
      project: default 
      destination: 
        server: https://kubernetes.default.svc 
        namespace: 'example-app-{{branch}}-{{number}}' 
      syncPolicy: 
        automated: {} 
        syncOptions: 
          - CreateNamespace=true

When you’ve got this running, great! You are actually done and ready to use Review apps for a simple/single repository!

However, if we are using multiple repositories, such as a backend and frontend service, we may need to test the frontend MR alongside the backend MR in the same environment.

ArgoCD’s generators allow us to define multiple sources, so we can add both repositories to the generator list.

apiVersion: argoproj.io/v1alpha1 
kind: ApplicationSet 
spec: 
  generators: 
    - pullRequest: 
        gitlab: 
          project: "48042720" 
          api: https://gitlab.com/ 
          tokenRef: 
            secretName: gitlab-token 
            key: token 
          pullRequestState: opened 
    - pullRequest: 
        gitlab: 
          project: "48042732" 
          api: https://gitlab.com/ 
          tokenRef: 
            secretName: gitlab-token 
            key: token 
          pullRequestState: opened

Handle duplicate branches across repositories

With two Git repositories configured as sources for the generator, we can create the frontend MR and have it spawn an application. However, generating the backend MR using the same branch name will attempt to create an already existing application.

To resolve this issue, we can utilize the Merge Generator from ArgoCD, which enables us to remove duplicate values and merge the configuration if the branch name matches. We use the mergeKeys value to check if the value is identical, and not create a second (or third) application for the same branch in a different repository.

apiVersion: argoproj.io/v1alpha1 
kind: ApplicationSet 
metadata: 
  name: example-app-pr-generator 
spec: 
  generators: 
    - merge: 
        mergeKeys: 
          - branch 
        generators: 
          - pullRequest: 
              gitlab: 
                project: "48042720" 
                api: https://gitlab.com/ 
                tokenRef: 
                  secretName: gitlab-token 
                  key: token 
                pullRequestState: opened 
          - pullRequest: 
              gitlab: 
                project: "48042732" 
                api: https://gitlab.com/ 
                tokenRef: 
                  secretName: gitlab-token 
                  key: token 
                pullRequestState: opened

Because we are working with multiple repositories, we must overwrite the generated application with the CI images from the project repositories, as we cannot guess both SHA’s from the application set (maybe the backend service does not have this branch because it only affects the frontend change).

To do this, we need to allow the Application to be modified, as the ApplicationSet keeps this in sync by default (so it replaces any modifications we apply to it). We can change this policy for the application set to only create and delete the application, but not update it with any changes.

Because review apps are short lived environments, the application set not applying new updates is only a minor disadvantage. If a change on the application set is made, which is important to propagate to a existing review app, you could use GitLab to re-open the PR or remove and re-add the “preview” label (or any other label you use to trigger the creation of the review app).

ArgoCD’s latest release candidate (v2.8.0) includes a major QoL feature which allows us to set the policy per application set, instead of for the entire controller.

Argo ≥ 2.8.0

From ArgoCD 2.8.0 and later, you will be able to set the sync policy in the application set:

apiVersion: argoproj.io/v1alpha1 
kind: ApplicationSet 
spec: 
  template: 
    spec: 
      syncPolicy: 
        applicationSync: create-delete

Argo < 2.8.0

In ArgoCD, we need to make a change to the applicationset-controller deployment. We can either add a flag to the command arguments --policy create-delete or set the ARGOCD_APPLICATIONSET_CONTROLLER_POLICY environment variable to create-delete.

Setting the ingress URL

Finally, we need to be able to access the application(s). This is possible by using commonAnnotations in Kustomize (or Helm values when you are using Helm).

To do this, we need to add some commonAnnotations for the hostname of each application. These commonAnnotations will be applied to every manifest/resource that is included in this kustomization repository.

kustomize: 
          commonAnnotations: 
            backend/param-host: pr-{{number}}.somedomain.com 
            frontend/param-host: fe-pr-{{number}}.somedomain.com

We can now use this value in our kustomization.yaml to generate the correct URL, using a replacement taking the value from the annotation and placing it on the right keys in the Ingress manifest.

replacements: 
- source: 
    kind: Ingress 
    name: example 
    fieldPath: metadata.annotations.backend/param-host 
  targets: 
    fieldPaths: 
      - spec.rules.0.host 
      - spec.tls.0.hosts.0 
  - select: 
      kind: Certificate 
      name: example-tls-certificate 
    fieldPaths: 
      - spec.dnsNames.0

You can also use commonAnnotations for setting environment variables. For instance, to let your frontend display the branch name as version or set up communication between frontend and backend.

Pipeline configuration

In GitLab, our primary concern for deploying a review app is to ensure that we build a container that we can deploy. The initial CI step would involve building and pushing the container to the registry path, which is also specified in your Kubernetes manifests.

After the build process, we can utilize the Argo CD CLI to update the image tag for the image to the most recent build container. To ensure that GitLab is also aware of this review app and its running state, we should implement a CI pipeline to start and stop the environment. This ensures that the running state in GitLab remains accurate and up-to-date.

The pipeline should run after the image container has been built and pushed, and you should run the following command (when using Kustomize):

argocd app set example-app-${CI_BRANCH_NAME}-${CI_MERGE_REQUEST_ID} --kustomize-image yourimage:${CI_COMMIT_SHA}

Conclusion

By following these steps, you’ll unleash the power of ArgoCD, streamlining your testing process, and boosting your team’s productivity. Automated review apps not only enhance efficiency but also ensure that your products maintain the highest quality.

As always, if you have any questions after reading this article, feel free to ask for any additional guidelines or help.