ArgoCD Install & Upgrade Guide
by bless2k@gmail.com (AI-assisted by Claude), 2026/05
ArgoCD는 Kubernetes(k8s) 환경에서 GitOps 기반의 지속적 배포(CD)를 구현하고 자동화하기에 매우 강력하고 유용한 툴이다. 다만, 버그가 많은 편이므로 지속적인 관리와 업데이트가 필요하다.
A practical, end-to-end guide covering installation, backup, upgrade, and rollback of ArgoCD using manifest-based deployment.
Scope: Non-HA install via
manifests/install.yaml. Tested for ArgoCD v3.x on AKS, EKS, GKE, and on-prem Kubernetes 1.27+. For HA installs, swapmanifests/install.yamlformanifests/ha/install.yamlthroughout — all other steps are identical.
0. Prerequisites
- Kubernetes cluster, version 1.27 or newer (verify against the ArgoCD support matrix)
kubectlconfigured with cluster-admin context for the target cluster- Outbound network access to
raw.githubusercontent.comandquay.io
Set the target version once and reuse it throughout:
export ARGOCD_VERSION=v3.4.11. Installation
1.1 Create the Namespace
kubectl create namespace argocdThe upstream manifests assume the namespace name
argocd. Changing it requires editing everyClusterRoleBindingand Service reference — more work than it saves. Stick withargocdunless you have a strong reason not to.
1.2 Apply the Install Manifests
The unified install.yaml bundles CRDs, RBAC, ConfigMaps, Secrets, Services, Deployments, and the application-controller StatefulSet. There is no separate CRDs step.
kubectl apply -n argocd --server-side --force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/${ARGOCD_VERSION}/manifests/install.yamlWhy --server-side --force-conflicts:
- The ApplicationSet CRD exceeds the 262144-byte client-side apply annotation limit. Plain
kubectl applywill fail withmetadata.annotations: Too long. --force-conflictslets the apply take ownership of fields that would otherwise conflict with existing managers. On a fresh install this is harmless; on upgrades it has consequences (see §4.1).
Always pin to a version tag (
v3.4.1), neverstable. Pinning gives you a reproducible install you can match exactly during upgrade and rollback.
1.3 Wait for All Components
kubectl rollout status -n argocd deploy/argocd-server
...kubectl get pods -n argocdAll pods should be Running and Ready 1/1.
1.4 Retrieve the Initial Admin Password
ArgoCD generates a random admin password on first install and stores it in a secret. Read it once, then plan to change it (§1.7).
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d ; echoThe username is admin.
1.5 Access the Argo CD Server
The argocd-server Service is ClusterIP by default. Pick one of the access patterns below.
Option A — Port-forward (quickest, for testing):
kubectl port-forward -n argocd svc/argocd-server 8080:443
# UI: https://localhost:8080The certificate is self-signed; the browser will warn on first visit.
Option B — LoadBalancer (cloud clusters):
kubectl patch svc argocd-server -n argocd \
-p '{"spec": {"type": "LoadBalancer"}}'kubectl get svc argocd-server -n argocd \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}{"\n"}'On AKS this provisions an Azure Load Balancer; on EKS, an ELB; on GKE, a GCLB. Restrict access via NSG/SG rules or a private LB if exposing only to corporate networks.
Option C — Ingress with TLS (recommended for production):
Configure your ingress controller (NGINX, Traefik, AGIC on AKS, ALB on EKS) to terminate TLS and forward to argocd-server. ArgoCD ships with HTTP/2 and gRPC; for NGINX you typically need nginx.ingress.kubernetes.io/backend-protocol: HTTPS and to disable TLS termination at the ArgoCD server with --insecure in argocd-cmd-params-cm. See the upstream ingress configurations doc for controller-specific examples.
1.6 Change the Admin Password
Log in to the UI as admin with the password from §1.4, then User Info → Update Password.
Get HyunWoo Lee, Yet Another Software Engineer’s stories in your inbox
Join Medium for free to get updates from this writer.
After the password is changed, delete the bootstrap secret so it cannot be re-read:
kubectl -n argocd delete secret argocd-initial-admin-secret1.7 Smoke Test
Confirm sync works end-to-end with a declarative Application:
cat <<'EOF' | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: guestbook
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated: {}
syncOptions:
- CreateNamespace=true
EOFkubectl -n argocd get application guestbook -wThe Application should reach SYNC STATUS: Synced and HEALTH STATUS: Healthy. Delete it when done:
kubectl -n argocd delete application guestbook
kubectl -n default delete deploy,svc -l app=guestbook-uiIf the app reaches Synced / Healthy, your install is complete.
2. Pre-Upgrade Checklist
- Record current version — you’ll need it for rollback:
kubectl -n argocd get deploy argocd-server \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'- Read the upgrade notes for every minor hop between current and target version: https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/
- Verify Kubernetes compatibility for the target ArgoCD version: support matrix
- Capture customizations that
--force-conflictswill overwrite (skip if managed via Kustomize/Helm):
kubectl -n argocd get deploy,sts,svc,cm -o yaml > argocd-workloads-pre-upgrade.yaml- Take the backup in §3.
3. Pre-Upgrade Backup
Capture full ArgoCD state to a single file using argocd admin export. The argocd-application-controller-0 pod is the cleanest target — it is a StatefulSet, so its name is predictable, and its ServiceAccount has the right permissions.
3.1 Export Configuration
# (Simple)
kubectl exec -n argocd deploy/argocd-server -- argocd admin export > argocd-backup-$(date +%F).yaml
# (Optional)
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
kubectl exec -n argocd argocd-application-controller-0 -- \
argocd admin export -n argocd > "argocd-backup-${TIMESTAMP}.yaml"3.2 Verify the Export
ls -lh "argocd-backup-${TIMESTAMP}.yaml"
grep -c '^kind:' "argocd-backup-${TIMESTAMP}.yaml"You should see a non-zero file size and a count covering your ConfigMaps, Secrets, AppProjects, Applications, and ApplicationSets.
4. Upgrade Procedure
4.1 Apply the Target Version
export ARGOCD_VERSION=v3.4.1kubectl apply -n argocd --server-side --force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/${ARGOCD_VERSION}/manifests/install.yamlThe --server-side --force-conflicts flags are mandatory. Without them you will hit:
CustomResourceDefinition.apiextensions.k8s.io "applicationsets.argoproj.io" is invalid:
metadata.annotations: Too long: may not be more than 262144 bytes4.2 Re-Apply Customizations
If §2.3 captured custom changes, re-apply your patches/overlays now. --force-conflicts will have reverted any direct edits to fields the upstream manifests own.
5. Post-Upgrade Verification
5.1 Wait for Rollout
kubectl rollout status -n argocd deploy/argocd-server
kubectl rollout status -n argocd deploy/argocd-repo-server
kubectl rollout status -n argocd deploy/argocd-applicationset-controller
kubectl rollout status -n argocd deploy/argocd-dex-server
kubectl rollout status -n argocd deploy/argocd-notifications-controller
kubectl rollout status -n argocd deploy/argocd-redis
kubectl rollout status -n argocd statefulset/argocd-application-controllerAll commands should return successfully rolled out.
5.2 Verify Server Version
Check the actual deployed image:
kubectl -n argocd get deploy argocd-server \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
# Expect: quay.io/argoproj/argocd:v3.4.15.3 Sanity Test
- Open the Argo CD UI; confirm the Applications list loads and
Sync Statusis healthy. - Pick one low-risk Application and trigger a manual
Refresh(not Sync). - Confirm any
OutOfSyncresources are explained by expected drift — not by tracking-annotation or RBAC regressions introduced by the upgrade.
6. Rollback Procedure
Rollback safety by version distance:
- Patch downgrades (3.4.1 → 3.4.0): safe.
- Minor downgrades (3.4 → 3.3): usually safe, but new CRD fields written under the newer version may fail validation under the older one.
- Major downgrades (3.x → 2.x): not supported. Use restore-from-backup, not downgrade.
6.1 Re-Apply the Previous Version
This handles workloads, RBAC, Services, ConfigMaps, and CRDs.
PREVIOUS_VERSION=v3.2.0 # whatever you recorded in §2.1kubectl apply -n argocd --server-side --force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/${PREVIOUS_VERSION}/manifests/install.yamlWait for rollout (use the commands from §5.1).
Existing Applications, AppProjects, and ApplicationSets are stored as CRDs — they survive the binary swap. If a CR contains fields introduced after ${PREVIOUS_VERSION}, those resources are preserved at the API layer but the older controller may log validation warnings. Edit the affected resources to remove the newer fields, or restore them from your backup (§6.2).
6.2 Restore from argocd admin export (If Needed)
Use this only if §6.1 leaves you with corrupted or incompatible CRs.
⚠️ This overwrites in-cluster ArgoCD state with the contents of the backup file. Existing Applications, Projects, and configuration created after the backup will be replaced. Review the backup contents before importing.
# Decrypt if you encrypted the backup
age -d -o argocd-backup-pre-upgrade.yaml argocd-backup-pre-upgrade.yaml.age# Pipe the file into the application-controller pod
kubectl exec -i -n argocd argocd-application-controller-0 -- \
argocd admin import -n argocd - < argocd-backup-pre-upgrade.yamlThe -i flag keeps stdin open so the file can be piped in.
Useful flags for argocd admin import:
--dry-run— preview changes without applying.--prune— delete resources that exist in the cluster but not in the backup. Use with caution; safer to omit on the first attempt.--ignore-tracking— skip tracking annotation reconciliation.
6.3 Restart the Application Controller
After a restore, force a fresh reconciliation pass:
kubectl rollout restart statefulset/argocd-application-controller -n argocd
kubectl rollout status statefulset/argocd-application-controller -n argocd7. Troubleshooting & Notes
- Apply fails with
Too long: may not be more than 262144 bytes: You forgot--server-side --force-conflicts. Re-run with the flags. - Custom modifications disappeared after upgrade: Expected with
--force-conflicts. Re-apply your patches (§4.2). Long-term, move toward a Kustomize overlay or Helm install so customizations are tracked and re-applicable. - Server-side diff differences after upgrade: v3.4 uses server-side diffing by default. If sync results look different, audit your
ignoreDifferencessettings — server-side diff is more accurate and may surface drift the old client-side diff hid. - Sessions invalidated after upgrade or restore: If
argocd-secret(server signing key) was rotated or restored from a different snapshot, all existing JWTs are invalidated. Users must re-login. - Stale pods in
ErrororCompletedstate: Common on cloud clusters due to spot-node preemption or node auto-repair. The Deployment/StatefulSet has already replaced them; clean up withkubectl delete pod <name> -n argocdonce the replacement isRunning. - CLI not available locally: All
argocd admincommands work viakubectl execinto the application-controller pod — no local CLI install required for backup/restore operations. - Forgot the admin password and deleted
argocd-initial-admin-secret: Patch the bcrypt hash in theargocd-secretdirectly — see the FAQ entry.






