Argo CD is a declarative, GitOps-based continuous delivery (CD) tool for Kubernetes. It automates the deployment and lifecycle management of applications in a cluster by using Git repositories as the single source of truth for the desired state of the infrastructure.
This article explains how to set up Argo CD and deploy an application in a Kubernetes cluster using the command line and manifests.
Prerequisites:
- Installed the kind with Cloud Provider KIND
- Installed ArgoCD CLI
Kubernetes Cluster
# kind-cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
apiServerPort: 6443
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
$ kind create cluster --config kind-cluster.yaml
Creating cluster "kind" ...
• Ensuring node image (kindest/node:v1.33.1) 🖼 ...
✓ Ensuring node image (kindest/node:v1.33.1) 🖼
• Preparing nodes 📦 📦 📦 📦 ...
✓ Preparing nodes 📦 📦 📦 📦
• Writing configuration 📜 ...
✓ Writing configuration 📜
• Starting control-plane 🕹️ ...
✓ Starting control-plane 🕹️
• Installing CNI 🔌 ...
✓ Installing CNI 🔌
• Installing StorageClass 💾 ...
✓ Installing StorageClass 💾
• Joining worker nodes 🚜 ...
✓ Joining worker nodes 🚜
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Have a nice day! 👋
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 7m2s v1.33.1
kind-worker Ready <none> 6m53s v1.33.1
kind-worker2 Ready <none> 6m53s v1.33.1
kind-worker3 Ready <none> 6m53s v1.33.1
Argo CD
Setup the Argo CD
$ kubectl create namespace argocd
namespace/argocd created
$ kubectl get namespaces
NAME STATUS AGE
argocd Active 9s
default Active 15m
kube-node-lease Active 15m
kube-public Active 15m
kube-system Active 15m
local-path-storage Active 15m
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io created
serviceaccount/argocd-application-controller created
serviceaccount/argocd-applicationset-controller created
serviceaccount/argocd-dex-server created
serviceaccount/argocd-notifications-controller created
serviceaccount/argocd-redis created
serviceaccount/argocd-repo-server created
serviceaccount/argocd-server created
role.rbac.authorization.k8s.io/argocd-application-controller created
role.rbac.authorization.k8s.io/argocd-applicationset-controller created
role.rbac.authorization.k8s.io/argocd-dex-server created
role.rbac.authorization.k8s.io/argocd-notifications-controller created
role.rbac.authorization.k8s.io/argocd-redis created
role.rbac.authorization.k8s.io/argocd-server created
clusterrole.rbac.authorization.k8s.io/argocd-application-controller created
clusterrole.rbac.authorization.k8s.io/argocd-applicationset-controller created
clusterrole.rbac.authorization.k8s.io/argocd-server created
rolebinding.rbac.authorization.k8s.io/argocd-application-controller created
rolebinding.rbac.authorization.k8s.io/argocd-applicationset-controller created
rolebinding.rbac.authorization.k8s.io/argocd-dex-server created
rolebinding.rbac.authorization.k8s.io/argocd-notifications-controller created
rolebinding.rbac.authorization.k8s.io/argocd-redis created
rolebinding.rbac.authorization.k8s.io/argocd-server created
clusterrolebinding.rbac.authorization.k8s.io/argocd-application-controller created
clusterrolebinding.rbac.authorization.k8s.io/argocd-applicationset-controller created
clusterrolebinding.rbac.authorization.k8s.io/argocd-server created
configmap/argocd-cm created
configmap/argocd-cmd-params-cm created
configmap/argocd-gpg-keys-cm created
configmap/argocd-notifications-cm created
configmap/argocd-rbac-cm created
configmap/argocd-ssh-known-hosts-cm created
configmap/argocd-tls-certs-cm created
secret/argocd-notifications-secret created
secret/argocd-secret created
service/argocd-applicationset-controller created
service/argocd-dex-server created
service/argocd-metrics created
service/argocd-notifications-controller-metrics created
service/argocd-redis created
service/argocd-repo-server created
service/argocd-server created
service/argocd-server-metrics created
deployment.apps/argocd-applicationset-controller created
deployment.apps/argocd-dex-server created
deployment.apps/argocd-notifications-controller created
deployment.apps/argocd-redis created
deployment.apps/argocd-repo-server created
deployment.apps/argocd-server created
statefulset.apps/argocd-application-controller created
networkpolicy.networking.k8s.io/argocd-application-controller-network-policy created
networkpolicy.networking.k8s.io/argocd-applicationset-controller-network-policy created
networkpolicy.networking.k8s.io/argocd-dex-server-network-policy created
networkpolicy.networking.k8s.io/argocd-notifications-controller-network-policy created
networkpolicy.networking.k8s.io/argocd-redis-network-policy created
networkpolicy.networking.k8s.io/argocd-repo-server-network-policy created
networkpolicy.networking.k8s.io/argocd-server-network-policy created
$ kubectl get all -n argocd
NAME READY STATUS RESTARTS AGE
pod/argocd-application-controller-0 1/1 Running 0 4m14s
pod/argocd-applicationset-controller-fc5545556-xwf5k 1/1 Running 0 4m15s
pod/argocd-dex-server-f59c65cff-rn6m5 1/1 Running 1 (3m10s ago) 4m15s
pod/argocd-notifications-controller-59f6949d7-qmw9h 1/1 Running 0 4m15s
pod/argocd-redis-75c946f559-r7hw9 1/1 Running 0 4m15s
pod/argocd-repo-server-6959c47c44-zcgvw 1/1 Running 0 4m15s
pod/argocd-server-65544f4864-d8bdg 1/1 Running 0 4m15s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/argocd-applicationset-controller ClusterIP 10.96.198.72 <none> 7000/TCP,8080/TCP 4m15s
service/argocd-dex-server ClusterIP 10.96.130.197 <none> 5556/TCP,5557/TCP,5558/TCP 4m15s
service/argocd-metrics ClusterIP 10.96.76.149 <none> 8082/TCP 4m15s
service/argocd-notifications-controller-metrics ClusterIP 10.96.212.160 <none> 9001/TCP 4m15s
service/argocd-redis ClusterIP 10.96.87.147 <none> 6379/TCP 4m15s
service/argocd-repo-server ClusterIP 10.96.249.213 <none> 8081/TCP,8084/TCP 4m15s
service/argocd-server ClusterIP 10.96.182.198 <none> 80:31808/TCP,443:32242/TCP 4m15s
service/argocd-server-metrics ClusterIP 10.96.205.52 <none> 8083/TCP 4m15s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/argocd-applicationset-controller 1/1 1 1 4m15s
deployment.apps/argocd-dex-server 1/1 1 1 4m15s
deployment.apps/argocd-notifications-controller 1/1 1 1 4m15s
deployment.apps/argocd-redis 1/1 1 1 4m15s
deployment.apps/argocd-repo-server 1/1 1 1 4m15s
deployment.apps/argocd-server 1/1 1 1 4m15s
NAME DESIRED CURRENT READY AGE
replicaset.apps/argocd-applicationset-controller-fc5545556 1 1 1 4m15s
replicaset.apps/argocd-dex-server-f59c65cff 1 1 1 4m15s
replicaset.apps/argocd-notifications-controller-59f6949d7 1 1 1 4m15s
replicaset.apps/argocd-redis-75c946f559 1 1 1 4m15s
replicaset.apps/argocd-repo-server-6959c47c44 1 1 1 4m15s
replicaset.apps/argocd-server-65544f4864 1 1 1 4m15s
NAME READY AGE
statefulset.apps/argocd-application-controller 1/1 4m15s
$ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
service/argocd-server patched
$ kubectl get svc argocd-server -n argocd -o=jsonpath='{.status.loadBalancer.ingress[0].ip}'
172.18.0.6
$ curl -sIL http://172.18.0.6:80 -k
HTTP/1.1 307 Temporary Redirect
Content-Type: text/html; charset=utf-8
Location: https://172.18.0.6/
Date: Fri, 28 Nov 2025 14:30:00 GMT
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 788
Content-Security-Policy: frame-ancestors 'self';
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
X-Frame-Options: sameorigin
X-Xss-Protection: 1
Date: Fri, 28 Nov 2025 14:30:00 GMT
$ argocd admin initial-password -n argocd
CH5hFPo5q1TcHi9-
This password must be only used for first time login. We strongly recommend you update the password using `argocd account update-password`.
$ argocd login 172.18.0.6 --insecure --username admin
Password: CH5hFPo5q1TcHi9-
'admin:login' logged in successfully
Context '172.18.0.6' updated
$ argocd account update-password
*** Enter password of currently logged in user (admin):
*** Enter new password for user admin:
*** Confirm new password for user admin:
Password updated
Context '172.18.0.6' updated
$ kubectl -n argocd delete secret argocd-initial-admin-secret
secret "argocd-initial-admin-secret" deleted
$ argocd version
argocd: v3.2.0+66b2f30
BuildDate: 2025-11-04T15:21:01Z
GitCommit: 66b2f302d91a42cc151808da0eec0846bbe1062c
GitTreeState: clean
GoVersion: go1.25.0
Compiler: gc
Platform: windows/amd64
argocd-server: v3.2.0+66b2f30
BuildDate: 2025-11-04T14:51:35Z
GitCommit: 66b2f302d91a42cc151808da0eec0846bbe1062c
GitTreeState: clean
GoVersion: go1.25.0
Compiler: gc
Platform: linux/amd64
Kustomize Version: v5.7.0 2025-06-28T07:00:07Z
Helm Version: v3.18.4+gd80839c
Kubectl Version: v0.34.0
Setup a Repository
$ argocd repo add https://github.com/viastakhov/argocd-kustomize-demo.git
Repository 'https://github.com/viastakhov/argocd-kustomize-demo.git' added
$ argocd repo list
TYPE NAME REPO INSECURE OCI LFS CREDS STATUS MESSAGE PROJECT
git https://github.com/viastakhov/argocd-kustomize-demo.git false false false false Successful
Create a Project
Projects provide a logical grouping of applications, which is useful when Argo CD is used by multiple teams.
# ./argo-cd/project.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: nginx
spec:
sourceRepos:
- '*'
destinations:
- namespace: '*'
server: '*'
clusterResourceWhitelist:
- group: '*'
kind: '*'
$ argocd proj create -f ./argo-cd/project.yaml
$ argocd proj list
NAME DESCRIPTION DESTINATIONS SOURCES CLUSTER-RESOURCE-WHITELIST NAMESPACE-RESOURCE-BLACKLIST SIGNATURE-KEYS ORPHANED-RESOURCES DESTINATION-SERVICE-ACCOUNTS
default *,* * */* <none> <none> disabled <none>
nginx *,* * */* <none> <none> disabled <none>
Create an Application
An Application is the Kubernetes resource object representing a deployed application instance in an environment.
# ./argo-cd/appset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: nginx
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/viastakhov/argocd-kustomize-demo.git
revision: HEAD
directories:
- path: kustomize/overlays/*
template:
metadata:
name: 'nginx-{{index .path.segments 2}}'
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: nginx
source:
repoURL: https://github.com/viastakhov/argocd-kustomize-demo.git
targetRevision: HEAD
path: '{{.path.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{index .path.segments 2}}'
syncPolicy:
syncOptions:
- CreateNamespace=false
automated:
enabled: true
prune: false
selfHeal: false
allowEmpty: false
$ argocd appset create ./argo-cd/appset.yaml
ApplicationSet 'nginx' created
Name: argocd/nginx
Project: nginx
Server: https://kubernetes.default.svc
Namespace: {{index .path.segments 2}}
Source:
- Repo: https://github.com/viastakhov/argocd-kustomize-demo.git
Target: HEAD
Path: {{.path.path}}
SyncPolicy: Automated
$ argocd appset list
NAME PROJECT SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/nginx nginx nil [{ParametersGenerated Successfully generated parameters for all Applications 2025-12-04 03:04:54 +0300 MSK True ParametersGenerated} {ResourcesUpToDate All applications have been generated successfully 2025-12-04 03:04:54 +0300 MSK True ApplicationSetUpToDate}] https://github.com/viastakhov/argocd-kustomize-demo.git {{.path.path}} HEAD
$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/nginx-dev https://kubernetes.default.svc dev nginx Synced Healthy Auto <none> https://github.com/viastakhov/argocd-kustomize-demo.git kustomize/overlays/dev HEAD
argocd/nginx-prod https://kubernetes.default.svc prod nginx Synced Healthy Auto <none> https://github.com/viastakhov/argocd-kustomize-demo.git kustomize/overlays/prod HEAD
$ argocd app resources nginx-prod
GROUP KIND NAMESPACE NAME ORPHANED
ConfigMap production nginx-conf-c6752d2t6f No
Namespace production No
Service production nginx-svc No
apps Deployment production nginx-app No
$ argocd app get nginx-prod
Name: argocd/nginx-prod
Project: nginx
Server: https://kubernetes.default.svc
Namespace: prod
URL: https://172.18.0.6/applications/nginx-prod
Source:
- Repo: https://github.com/viastakhov/argocd-kustomize-demo.git
Target: HEAD
Path: kustomize/overlays/prod
SyncWindow: Sync Allowed
Sync Policy: Automated
Sync Status: Synced to HEAD (d70b25e)
Health Status: Healthy
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Namespace prod production Running Synced namespace/production created
ConfigMap production nginx-conf-c6752d2t6f Synced configmap/nginx-conf-c6752d2t6f created
Service production nginx-svc Synced Healthy service/nginx-svc created
apps Deployment production nginx-app Synced Healthy deployment.apps/nginx-app created
Namespace production Synced
Cleanup
$ argocd appset delete nginx
Are you sure you want to delete 'nginx' and all its Applications? [y/n] y
applicationset 'nginx' deleted
$ argocd appset list
NAME PROJECT SYNCPOLICY CONDITIONS REPO PATH TARGET
$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
Bonus
Applications In Any Namespace
Since version 2.5, Argo CD supports managing Application resources in namespaces other than the namespace of the control plane (usually argocd), but this feature has to be explicitly enabled and configured accordingly.
# ./argo-cd/project.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: nginx
spec:
sourceNamespaces:
- '*'
sourceRepos:
- '*'
destinations:
- namespace: '*'
server: '*'
clusterResourceWhitelist:
- group: '*'
kind: '*'
$ argocd proj create -f ./argo-cd/project.yaml
$ kubectl patch cm/argocd-cmd-params-cm -n argocd -p '{"data": {"application.namespaces": "'*'"}}'
configmap/argocd-cmd-params-cm patched
$ kubectl rollout restart -n argocd deployment argocd-server
deployment.apps/argocd-server restarted
$ kubectl rollout restart -n argocd statefulset argocd-application-controller
statefulset.apps/argocd-application-controller restarted
$ kubectl patch clusterrole argocd-server --type='json' -p='[{"op": "replace", "path": "/rules/3/resources", "value": ["applications", "applicationsets", "appprojects"]}]'
clusterrole.rbac.authorization.k8s.io/argocd-server patched
$ kubectl patch clusterrole argocd-server --type='json' -p='[{"op": "replace", "path": "/rules/3/verbs", "value": ["get", "watch", "list", "create", "update", "delete", "patch"]}]'
clusterrole.rbac.authorization.k8s.io/argocd-server patched
$ kubectl create ns development
namespace/development created
$ kubectl create ns production
namespace/production created
$ argocd app create nginx \
--repo https://github.com/viastakhov/argocd-kustomize-demo.git \
--path kustomize/overlays/dev \
--dest-server https://kubernetes.default.svc \
--dest-namespace development \
--sync-policy auto \
--project nginx \
--app-namespace development \
--set-finalizer
application 'nginx' created
$ argocd app create nginx \
--repo https://github.com/viastakhov/argocd-kustomize-demo.git \
--path kustomize/overlays/prod \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--sync-policy auto \
--project nginx \
--app-namespace production \
--set-finalizer
application 'nginx' created
$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
development/nginx https://kubernetes.default.svc development nginx Synced Healthy Auto <none> https://github.com/viastakhov/argocd-kustomize-demo.git kustomize/overlays/dev
production/nginx https://kubernetes.default.svc production nginx Synced Healthy Auto <none> https://github.com/viastakhov/argocd-kustomize-demo.git kustomize/overlays/prod
$ kubectl get applications -n development -o wide
NAME SYNC STATUS HEALTH STATUS REVISION PROJECT
nginx Synced Healthy 2550d54636eee62d843f4c56b27b7bdcf351d34a nginx
$ kubectl get applications -n production -o wide
NAME SYNC STATUS HEALTH STATUS REVISION PROJECT
nginx Synced Healthy 2550d54636eee62d843f4c56b27b7bdcf351d34a nginx
$ kubectl delete ns development
namespace "development" deleted
$ kubectl delete ns production
namespace "production" deleted
$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET






Top comments (0)