Installing Argo CD
The documented one-liner fails on this chart with "annotations: Too long". The cause is client-side apply storing your whole manifest in an annotation, and the fix is one flag. A CRD in the same install measures 197,595 bytes of it.
Delivery and GitOps Guide 42 of 46 Intermediate
- Kubernetes1.36.4
- Argo CDstable manifests, 2026-08
- Source repoargoproj/argocd-example-apps
- TimeAbout 18 min
- Reviewed22 August 2026
Written against the versions above. The stable manifests move. The behaviour shown here - the annotation limit, self-heal, prune scope - is not version specific.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| CKA1001 | 192.168.0.175 | Ubuntu 26.04 LTS | Control Plane Node | 2 Core | 4 GB | 50 GB |
| CKA1001-NODE01 | 192.168.0.176 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
| CKA1001-NODE02 | 192.168.0.177 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
| CKA1001-NODE03 | 192.168.0.178 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
Before you start
- A cluster and kubectl. Around 700 MB of spare memory - Argo CD runs seven Pods.
- Outbound HTTPS from the cluster, so the repo server can reach GitHub.
-
Apply the manifests, and read the last line
Everything scrolls past looking healthy - service accounts, roles, config maps, seven Deployments, network policies - and then:
The CustomResourceDefinition "applicationsets.argoproj.io" is invalid: metadata.annotations: Too long: may not be more than 262144 bytesThis is not Argo CD's fault and not a broken cluster.
kubectl applywithout--server-sidestores a copy of the entire object you submitted in thekubectl.kubernetes.io/last-applied-configurationannotation, so it can compute a diff next time. Annotations are capped at 256 KB. A CRD with a large OpenAPI schema exceeds it on its own.The dangerous part is that the command partially succeeded. Most objects exist; one CRD does not.
bash Example session kubectl --context cka1001 create namespace argocdnamespace/argocd createdkubectl --context cka1001 apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlcustomresourcedefinition.apiextensions.k8s.io/applications.argoproj.io createdcustomresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io createdserviceaccount/argocd-application-controller createdserviceaccount/argocd-applicationset-controller createdserviceaccount/argocd-dex-server createdserviceaccount/argocd-notifications-controller createdExpected resultA long list of created objects, then the
Too longerror, then a non-zero exit.Success conditionYou have the error text rather than a vague failure.
-
Confirm what is actually missing
Never assume a partial apply left the thing you need. Ask:
Error from server (NotFound): ... "applicationsets.argoproj.io" not foundSo
Applicationexists butApplicationSetdoes not. A cluster in that state will run single Applications fine and fail confusingly the first time someone writes an ApplicationSet - weeks later, with no memory of this install.bash Example session kubectl --context cka1001 get crd applicationsets.argoproj.io 2>&1 | head -2Error from server (NotFound): customresourcedefinitions.apiextensions.k8s.io "applicationsets.argoproj.io" not foundExpected resultA
NotFoundfor the CRD that failed.Success conditionYou can name the object that did not get created.
-
Server-side apply, and why it works
--server-sidechanges who computes the diff. The API server tracks field ownership inmetadata.managedFieldsinstead of stashing your manifest in an annotation, so there is nothing to exceed the limit.Expect conflict warnings on the second run: objects created client-side are now owned by a different manager, and server-side apply says so rather than silently taking over. On a fresh install those are informational. In production, read them - a conflict is the API server telling you two things are fighting over a field.
After it completes, all three CRDs exist.
bash Example session kubectl --context cka1001 apply --server-side -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml 2>&1 | tail -4* You may co-own fields by updating your manifest to match the existing value; in this case, you'll become the manager if the other manager(s) stop managing the field (remove it from their configuration).See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflictskubectl --context cka1001 get crd -o name | grep argoproj.iocustomresourcedefinition.apiextensions.k8s.io/applications.argoproj.iocustomresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.iocustomresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.ioExpected resultConflict guidance from server-side apply, then three
argoproj.ioCRDs.Success condition
applicationsets.argoproj.iois present. -
Measure the annotation that caused it
Worth doing once so the limit stops being abstract. The
ApplicationCRD - the one that *did* apply client-side - carries 197,595 bytes oflast-applied-configuration. That is 75% of the 262,144-byte ceiling, for a CRD that fits. Its larger sibling did not.The
managedFieldsmanagers on the server-side-applied CRD name both writers:kubectlandkube-apiserver. That list is how server-side apply keeps track without an annotation at all.bash Example session kubectl --context cka1001 get crd applications.argoproj.io -o jsonpath='{.metadata.annotations.kubectl\.kubernetes\.io/last-applied-configuration}' | wc -c197595kubectl --context cka1001 get crd applicationsets.argoproj.io -o jsonpath='{.metadata.managedFields[*].manager}'kubectl kube-apiserverExpected resultA byte count in the high 190,000s, and two field managers.
Success conditionYou can state how close the working CRD came to the limit.
-
What got installed
Seven Pods, and each one has a distinct job worth knowing:
- application-controller - the reconcile loop. Compares cluster to Git and acts.
- repo-server - clones repos and renders manifests (Helm, Kustomize, plain YAML).
- server - the API and web UI.
- redis - a cache for rendered manifests.
- dex - optional SSO.
- applicationset-controller, notifications-controller - generate Applications, and send alerts.
Note the Service is ClusterIP. Argo CD does not expose itself, which is a sane default: the UI is an admin surface with cluster-wide write access.
bash Example session kubectl --context cka1001 -n argocd get podsNAME READY STATUS RESTARTS AGEargocd-application-controller-0 1/1 Running 0 81sargocd-applicationset-controller-579c4c54b8-z29v2 1/1 Running 0 81sargocd-dex-server-744c5d4467-sjvhd 1/1 Running 0 81sargocd-notifications-controller-dd4ff84c-f8564 1/1 Running 0 81sargocd-redis-84497fb7c5-699gg 1/1 Running 0 81sargocd-repo-server-5f46d9f598-mtgrj 1/1 Running 0 81sargocd-server-7f4549bb69-d7grb 1/1 Running 0 81skubectl --context cka1001 -n argocd get svc argocd-server -o custom-columns=NAME:.metadata.name,TYPE:.spec.type,PORTS:.spec.ports[*].portNAME TYPE PORTSargocd-server ClusterIP 80,443Expected resultSeven Running Pods and a ClusterIP Service on 80/443.
Success conditionAll Argo CD Pods are Running.
Troubleshooting
Server-side apply reports conflicts and refuses.
Why: Fields are owned by the earlier client-side apply.
Fix:
--force-conflictstakes ownership. Use it on an install you control; understand what you are overwriting on anything shared.repo-server logs
failed to list refsor DNS errors.Why: No outbound access, or cluster DNS cannot resolve the repo host.
Fix:Test from a Pod:
kubectl -n argocd exec deploy/argocd-repo-server -- nslookup github.com. This is a cluster networking problem, not an Argo problem.argocd-server stays
Pending.Why: Not enough allocatable memory for seven Pods.
Fix:
kubectl -n argocd describe podand read Events. On a small lab, install thecoremanifest instead - controller and repo-server only, no UI.