Search code examples
argocd

How to manage dependencies with ArgoCD?


How can I manage dependencies of my pods when deploying with ArgoCD?

Why do I need this?

I want to make sure, that first pod A is deployed and running successfully before pod B is deployed.

Flux offers such a workload dependency feature. But I can't see such feature for ArgoCD.


Solution

  • You can deploy your pods in a given order by using Sync Waves.

    Example

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: podA
      annotations:
        argocd.argoproj.io/sync-wave: "1"
    ...
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: podB
      annotations:
        argocd.argoproj.io/sync-wave: "2"
    ...
    

    ** Waves for different applications**

    If you want to have waves for different applications, then you need to do several things:

    1. Patch the ArgoCD configuration https://codefresh.io/blog/argo-cd-application-dependencies/

    $ cat patch-argocd-cm.yaml
    
    data:
      resource.customizations.health.argoproj.io_Application: |
        hs = {}
        hs.status = "Progressing"
        hs.message = ""
        if obj.status ~= nil then
          if obj.status.health ~= nil then
            hs.status = obj.status.health.status
            if obj.status.health.message ~= nil then
              hs.message = obj.status.health.message
            end
          end
        end
        return hs
    

    2. Increase ARGOCD_SYNC_WAVE_DELAY

    https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/

    This prevents Argo CD from assessing resource health too quickly (against the stale object), causing hooks to fire prematurely.

    $ kubectl patch cm/argocd-cm --type=merge -n argocd --patch-file patch-argocd-cm.yaml
    

    3. Use tags in Application definitions

    Use tags for you Application references and have a auto sync policy for your child applications.

    https://github.com/mattesja/argocd-demo/tree/nohook

      sources:
        - path: charts/app
          repoURL: https://github.com/mattesja/argocd-demo
          targetRevision: "1.0"
    syncPolicy:
      automated: {}
    

    If you push the new target revisions in the Applications at the same time, do a refresh and then sync the parent Application, then the child applications will be sync according to the sync waves.

    3b Alternative solution

    First I worked out a solution which will trigger the child app sync via REST api. But I think variant 3 is better.

    https://github.com/mattesja/argocd-demo

    apiVersion: batch/v1
    kind: Job
    metadata:
      generateName: sync-child-application-app-1
      annotations:
        argocd.argoproj.io/hook: Sync
        argocd.argoproj.io/hook-delete-policy: HookSucceeded
        argocd.argoproj.io/sync-wave: "1"
    spec:
      template:
        spec:
          containers:
            - name: sync-child-application
              image: curlimages/curl
              command:
                - "/bin/sh"
                - "-c"
                - |
                  ADMIN_PW=$(cat /etc/secret/password)
                  echo "retrieve token"
                  ARGOCD_TOKEN=$(curl -ss -k -X POST -H "Content-Type: application/json" https://argo-argocd-server.argocd.svc.cluster.local/api/v1/session -d "{\"username\":\"admin\",\"password\":\"$ADMIN_PW\"}"|sed "s/.*token.*\"\(.*\)\".*/\1/")
    
                  syncstatus=$(curl -ss -k -H "Content-Type: application/json"  https://argo-argocd-server.argocd.svc.cluster.local/api/v1/applications/app-1  -H "Authorization: Bearer $ARGOCD_TOKEN"| sed -n 's/.*"sync":{"status":"\([^"]*\)".*/\1/p')
                  echo "syncstatus: $syncstatus"
                  if [ "$syncstatus" == "Synced" ]; then
                    echo "Application is synced. Exiting..."
                    exit 0
                  fi
    
                  echo "sync app"
                  curl -ss -k -X POST -H "Content-Type: application/json"  https://argo-argocd-server.argocd.svc.cluster.local/api/v1/applications/app-1/sync -H "Authorization: Bearer $ARGOCD_TOKEN"
    
                  echo "wait for health"
                  # Trigger sync and then waiting for health is not thread safe!
                  # We might encounter a race condition where the app health is still healthy, because the app was not restarted yet.
                  sleep 30
                  status=""
                  while [ "$status" != "Healthy" ]; do
                    sleep 5
                    echo "waiting for app-1 to be healthy"
                    status=$(curl -ss -k -H "Content-Type: application/json"  https://argo-argocd-server.argocd.svc.cluster.local/api/v1/applications/app-1  -H "Authorization: Bearer $ARGOCD_TOKEN" | sed -n 's/.*"health":{"status":"\([^"]*\)".*/\1/p')
                  done
                  echo "app-1 is healthy"
              volumeMounts:
                - name: secret-volume
                  mountPath: /etc/secret
                  readOnly: true
          volumes:
            - name: secret-volume
              secret:
                secretName: argocd-initial-admin-secret
          restartPolicy: Never
      backoffLimit: 2
    

    Documentation / References