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.
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