Managing database migrations in ArgoCD 🐙
Tags: kubernetes, devops, argocd
Published: 2024-03-10 15:58:01

ArgoCD is a fantastic tool for doing GitOps in Kubernetes. Most of modern backend frameworks comes with a system that allows to version control database schema definition which is named migrations (e.g. [Laravel](https://laravel.com/docs/master/migrations), [Django](https://docs.djangoproject.com/en/5.0/topics/migrations/) …). This system is very powerful because it allows the code for a new feature to be versioned together with the database schema required for the feature to function correctly. This can be used, for example, to create a table, add a column, etc. But how to handle these migrations in ArgoCD ? That’s what we’ll be looking at in this article.

## What a roll-out looks like

In the context of a Kubernetes cluster whose deployments are automated by ArgoCD, Argo will be responsible for synchronising the desired state of the Kubernetes cluster described in the Kubernetes manifest with the actual state of the cluster. The desired state is stored on Git and contains the exact version of the Docker image (via its SHA or tag) which contains your application. When you’ll want to deploy a new version of the Docker image, you will push to the Manifest the new image version. The flow of the roll-out will look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nabeg6jv5hr1e36daf4.png)

## ArgoCD Resource Hooks

ArgoCD comes with a hook mechanism that enables actions to be taken during synchronisation, i.e. when it detects a difference between the state described in Git stored Kubernetes manifest and the actual state of the cluster. These actions are called [Resource Hooks](https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/) and take the form of Kubernetes jobs.

As we want our migrations to be executed just before the new version of the code is deployed, we will use the PreSync hook to run a job just before the synchronisation operation. Our new deployment flow will look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unbx192rkipoc4iw7ttb.png)


## The implementation

Here is an example of a Kubernetes Job that subscribe to ArgoCD PreSync hook that will run Laravel migrations:

```yaml
---
apiVersion: batch/v1
kind: Job
metadata:
  generateName: my-app-migration-
  annotations:
    argocd.argoproj.io/hook: "PreSync"
    argocd.argoproj.io/hook-delete-policy: "BeforeHookCreation"
    argocd.argoproj.io/job-cleanup: "keep"
spec:
  template:
    spec:
      containers:
      - name: my-laravel-app
        image: my-laravel-docker-image:new-tag
        command:
          - "php"
          - "artisan"
          - "migrate"
      restartPolicy: Never
  backoffLimit: 0
```

This Kubernetes job will be launched when ArgoCD detect a change in the Manifest. ArgoCD will wait the completion of the job (exit code 0) before syncing the rest of your application.

## Conclusion

In summary, ArgoCD’s Resource Hooks, especially the PreSync hook, streamline the execution of database migrations before deploying new code versions, ensuring seamless synchronization between application code and database schema. This approach enhances version control and consistency, offering a good solution for Kubernetes roll-out.


**_If you liked this post, you can find more on my blog_** [**_https://adrien-mornet.tech/_**](https://adrien-mornet.tech/) **_🚀_**