--- title: "How to Install Argo CD on Kubernetes for GitOps Deployments" description: "Install Argo CD on a Kubernetes cluster, log in with the CLI, and deploy an application from a Git repository with automated sync, pruning and self-healing." category: "CI/CD DevOps" language: en source: https://cubepath.com/docs/ci-cd-devops/argocd-installation-for-gitops-deployments updated: 2026-09-25 --- # How to Install Argo CD on Kubernetes for GitOps Deployments Argo CD is a GitOps continuous delivery controller for Kubernetes. It watches a Git repository that contains your manifests (plain YAML, Kustomize or Helm) and keeps the cluster in the state described there, reporting any drift. In this tutorial you will install Argo CD with the official manifests, log in with the `argocd` CLI, deploy a sample application from Git and turn on automated sync so every commit is applied without running `kubectl` by hand. ## Prerequisites To follow this tutorial you need: - A running Kubernetes cluster (version 1.30 or newer), for example a CubePath managed Kubernetes cluster or a self-managed k3s/kubeadm cluster, with at least 2 GB of free memory for the Argo CD components. - `kubectl` installed on your workstation (Ubuntu 24.04 in the examples) and a kubeconfig with cluster-admin rights. Check it with `kubectl get nodes`. - A Git repository with Kubernetes manifests. The tutorial uses the public `argoproj/argocd-example-apps` repository, so you can start without your own. - Optional, for Step 6: an ingress controller, cert-manager and a DNS A record for `argocd.your_domain` pointing to the ingress load balancer. ## Step 1 - Installing Argo CD Argo CD runs in its own namespace. Create it: ```bash kubectl create namespace argocd ``` Apply the official manifest for the latest stable release. The `--server-side` flag is required because some Argo CD CRDs are larger than the annotation size limit that client-side `kubectl apply` uses: ```bash kubectl apply -n argocd --server-side --force-conflicts \ -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml ``` Wait until all pods report `Ready`: ```bash kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s ``` Then list them: ```bash kubectl get pods -n argocd ``` ```output NAME READY STATUS RESTARTS AGE argocd-application-controller-0 1/1 Running 0 2m argocd-applicationset-controller-6d8f7c9b5d-x2kqz 1/1 Running 0 2m argocd-dex-server-5c8b8d7f9d-7lq4m 1/1 Running 0 2m argocd-notifications-controller-7b9d8c6f4b-9hz2p 1/1 Running 0 2m argocd-redis-6f9c5b8d7c-kq8wd 1/1 Running 0 2m argocd-repo-server-7f8d9c6b5f-p4tnm 1/1 Running 0 2m argocd-server-5d7b9f8c6d-vw3rj 1/1 Running 0 2m ``` The `argocd-server` pod serves the web UI and API, the `repo-server` renders manifests from Git, and the `application-controller` compares and syncs them with the cluster. > Note: For production you can pin a specific release instead of `stable` by replacing `stable` in the URL with a tag such as `v3.1.0`. Pinning makes upgrades an explicit, reviewable change. ## Step 2 - Installing the Argo CD CLI The `argocd` CLI talks to the Argo CD API server and is the quickest way to create and inspect applications. Download the latest Linux binary (use `argocd-linux-arm64` on ARM machines): ```bash curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd rm argocd-linux-amd64 ``` Verify the client: ```bash argocd version --client --short ``` ```output argocd: v3.1.0+... ``` ## Step 3 - Logging in and changing the admin password The API server is not exposed outside the cluster yet. Open a port-forward in a separate terminal and leave it running: ```bash kubectl port-forward svc/argocd-server -n argocd 8080:443 ``` During installation Argo CD generates a random password for the `admin` user and stores it in a secret. Print it: ```bash argocd admin initial-password -n argocd ``` ```output Xk3pQ9vLr2TbYw7A This password must be only used for first time login. We strongly recommend you update the password using `argocd account update-password`. ``` Log in through the port-forward. The `--insecure` flag is needed because Argo CD uses a self-signed certificate by default: ```bash argocd login localhost:8080 --username admin --insecure ``` Set a new password and then delete the secret that holds the initial one, since it is no longer used: ```bash argocd account update-password kubectl -n argocd delete secret argocd-initial-admin-secret ``` You can also open `https://localhost:8080` in a browser while the port-forward is active and log in to the web UI with the same credentials. ## Step 4 - Deploying an application from Git An Argo CD *Application* links a path in a Git repository to a namespace in a cluster. Create one for the `guestbook` example with the CLI: ```bash argocd app create guestbook \ --repo https://github.com/argoproj/argocd-example-apps.git \ --path guestbook \ --dest-server https://kubernetes.default.svc \ --dest-namespace default ``` `https://kubernetes.default.svc` refers to the cluster Argo CD itself runs in. The application is created but not deployed yet, so its status is `OutOfSync`. Sync it: ```bash argocd app sync guestbook ``` Check the result: ```bash argocd app get guestbook ``` ```output Name: argocd/guestbook Project: default Server: https://kubernetes.default.svc Namespace: default Repo: https://github.com/argoproj/argocd-example-apps.git Target: Path: guestbook Sync Policy: Manual Sync Status: Synced to (a1b2c3d) Health Status: Healthy GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE Service default guestbook-ui Synced Healthy service/guestbook-ui created apps Deployment default guestbook-ui Synced Healthy deployment.apps/guestbook-ui created ``` `Synced` means the cluster matches Git, and `Healthy` means the resources are running correctly. Remove this test application before moving on; deleting it also deletes the resources it created: ```bash argocd app delete guestbook --yes ``` If your manifests are in a private repository, register it first with a read-only access token: ```bash argocd repo add https://github.com/your_org/your_repo.git --username your_user --password your_token ``` ## Step 5 - Defining the application declaratively with automated sync Creating applications with the CLI is handy for testing, but in a GitOps workflow the Application itself should also be a file under version control. Create `guestbook-app.yaml`: ```bash nano guestbook-app.yaml ``` ```yaml 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: guestbook syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true ``` The `syncPolicy` block is what turns this into continuous delivery: - `automated`: Argo CD syncs on its own when the Git revision changes (it polls every 3 minutes by default). - `prune: true`: resources removed from Git are deleted from the cluster. - `selfHeal: true`: manual changes in the cluster are reverted to the state in Git. - `CreateNamespace=true`: the `guestbook` namespace is created if it does not exist. Apply it: ```bash kubectl apply -f guestbook-app.yaml ``` After a few seconds the application is synced into the new namespace: ```bash kubectl get deployment -n guestbook ``` ```output NAME READY UP-TO-DATE AVAILABLE AGE guestbook-ui 1/1 1 1 30s ``` Test self-healing by changing the deployment by hand: ```bash kubectl scale deployment guestbook-ui -n guestbook --replicas=3 ``` Watch the replica count for a few seconds: ```bash kubectl get deployment guestbook-ui -n guestbook -w ``` Argo CD detects the drift and sets the replica count back to 1, the value in Git. From now on, the way to change this application is a commit to the repository. ## Step 6 - Exposing the web UI with an Ingress (optional) A port-forward is fine for administration from one machine. For team access, publish Argo CD through your ingress controller and let the ingress terminate TLS. First tell `argocd-server` to serve plain HTTP inside the cluster, then restart it: ```bash kubectl -n argocd patch configmap argocd-cmd-params-cm --type merge -p '{"data":{"server.insecure":"true"}}' kubectl -n argocd rollout restart deployment argocd-server ``` Create `argocd-ingress.yaml`. Replace `your_domain`, set `ingressClassName` to the class your controller uses (`kubectl get ingressclass`) and adjust the issuer name to your cert-manager `ClusterIssuer`: ```bash nano argocd-ingress.yaml ``` ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: argocd-server namespace: argocd annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: traefik rules: - host: argocd.your_domain http: paths: - path: / pathType: Prefix backend: service: name: argocd-server port: name: http tls: - hosts: - argocd.your_domain secretName: argocd-server-tls ``` Apply it and check that the certificate is issued: ```bash kubectl apply -f argocd-ingress.yaml kubectl get certificate -n argocd ``` ```output NAME READY SECRET AGE argocd-server-tls True argocd-server-tls 1m ``` Open `https://argocd.your_domain` in a browser. Most ingress controllers do not pass Argo CD's gRPC traffic through a plain HTTP route, so log in with the CLI in gRPC-Web mode: ```bash argocd login argocd.your_domain --grpc-web ``` To have Argo CD sync immediately on push instead of waiting for the next poll, add a webhook in your Git provider pointing to `https://argocd.your_domain/api/webhook` with content type `application/json` and the push event. ## Troubleshooting - **`metadata.annotations: Too long` when installing:** you ran `kubectl apply` without `--server-side`. Run the command from Step 1 again with the flag. - **Application shows `ComparisonError` or `authentication required`:** the repo server cannot read the repository. Check the URL and credentials with `argocd repo list` and re-add the repository with a valid token. - **Application stays `OutOfSync` right after a sync:** a controller or webhook in the cluster is changing a field Argo CD manages (a common case is `replicas` set by a HorizontalPodAutoscaler). Use `argocd app diff your_app` to see the field and remove it from the manifest or add an `ignoreDifferences` entry for it. - **Sync or health problems you cannot explain:** read the controller logs with `kubectl logs -n argocd statefulset/argocd-application-controller` and the repo server logs with `kubectl logs -n argocd deployment/argocd-repo-server`. ## Conclusion You installed Argo CD, secured the admin account, deployed an application from Git and enabled automated sync with pruning and self-healing, so the Git repository is now the source of truth for that workload. Next, move your own manifests into a repository and create an Application per service, add an `AppProject` to restrict which repositories and namespaces each team can use, and configure SSO through Dex or your OIDC provider instead of the local `admin` account.