Getting Started with Kubernetes¶
This comprehensive guide will walk you through setting up argocd-agent on Kubernetes, including installing Argo CD on both the control plane and workload clusters, deploying the principal and agent components, and connecting your first agent using mutual TLS (mTLS) authentication.
Component Placement Overview
Before proceeding, make sure you understand which Argo CD components run where. This guide follows those placement requirements strictly.
Prerequisites¶
Before starting, ensure you have:
Clusters¶
- At least two Kubernetes clusters: One for the control plane and one or more for workloads
- Administrative access to all clusters with
kubectlconfigured - Network connectivity from workload clusters to the control plane cluster
Tools¶
kubectl(v1.20 or later)argocd-agentctlCLI tool (download from releases)kustomize(optional, for customization)
Agent Planning¶
- Unique agent names following DNS label standards
- Networking plan for exposing the principal service to agents
- Decision on agent mode: autonomous or managed for each agent
Architecture Overview¶
Control Plane Cluster Workload Cluster(s)
┌─────────────────────┐ ┌─────────────────────┐
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ Argo CD │ │ │ │ Argo CD │ │
│ │ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │ │
│ │ │ API Server │ │ │◄──────┐│ │ │ App │ │ │
│ │ │ Repository │ │ │ ││ │ │ Controller │ │ │
│ │ │ Redis │ │ │ ││ │ │ Repository │ │ │
│ │ │ Dex (SSO) │ │ │ ││ │ │ Redis │ │ │
│ │ └─────────────┘ │ │ ││ │ └─────────────┘ │
│ └─────────────────┘ │ ││ └─────────────────┘ │
│ ┌─────────────────┐ │ ││ ┌─────────────────┐ │
│ │ Principal │ │◄──────┘│ │ Agent │ │
│ │ ┌─────────────┐ │ │ │ │ │ │
│ │ │ gRPC Server │ │ │ │ │ │ │
│ │ │ Resource │ │ │ │ │ │ │
│ │ │ Proxy │ │ │ │ │ │ │
│ │ └─────────────┘ │ │ │ └─────────────────┘ │
│ └─────────────────┘ │ └─────────────────────┘
└─────────────────────┘
Step 1: Control Plane Setup¶
1.1 Create Namespace¶
kubectl create namespace argocd --context <control-plane-context>
1.2 Install Argo CD on Control Plane¶
Install a customized Argo CD instance that excludes components that will run on workload clusters replacing
# Apply the principal-specific Argo CD configuration
kubectl apply -n argocd \
--server-side \
-k 'https://github.com/argoproj-labs/argocd-agent/install/kubernetes/argo-cd/principal?ref=<release-branch>' \
--context <control-plane-context>
This configuration includes:
- ✅ argocd-server (API and UI)
- ✅ argocd-dex-server (SSO, if needed)
- ✅ argocd-redis (state storage)
- ✅ argocd-repo-server (Git repository access)
- ❌ argocd-application-controller (runs on workload clusters only)
- argocd-applicationset-controller (optional)
Critical Component Placement
The argocd-application-controller must never be deployed on the control plane cluster. It can only run on workload clusters where it has direct access to manage Kubernetes resources. Running it on the control plane is not supported and is out of scope for this project.
1.3 Configure Apps-in-Any-Namespace¶
Update the Argo CD server configuration to enable apps-in-any-namespace:
kubectl patch configmap argocd-cmd-params-cm -n argocd --context <control-plane-context> \
--patch '{"data":{"application.namespaces":"*"}}'
# Restart the server to apply changes
kubectl rollout restart deployment argocd-server -n argocd --context <control-plane-context>
1.4 Expose Argo CD UI (Optional)¶
# Option 1: Port forwarding (development)
kubectl port-forward svc/argocd-server -n argocd 8080:443 --context <control-plane-context>
# Option 2: LoadBalancer (production)
kubectl patch svc argocd-server -n argocd --context <control-plane-context> \
--patch '{"spec":{"type":"LoadBalancer"}}'
# Option 3: Ingress (production with custom domain)
# Create your own ingress resource based on your ingress controller
Step 2: PKI Setup¶
2.1 Initialize Certificate Authority¶
# Initialize the PKI
argocd-agentctl pki init \
--principal-context <control-plane-context> \
--principal-namespace argocd
2.2 Generate Principal Certificates¶
# Issue gRPC server certificate (agents connect to this)
argocd-agentctl pki issue principal \
--principal-context <control-plane-context> \
--principal-namespace argocd \
--ip 127.0.0.1,<principal-external-ip> \
--dns localhost,<principal-dns-name> \
--upsert
# Issue resource proxy certificate (Argo CD connects to this)
argocd-agentctl pki issue resource-proxy \
--principal-context <control-plane-context> \
--principal-namespace argocd \
--ip 127.0.0.1,<resource-proxy-ip> \
--dns localhost,<resource-proxy-dns> \
--upsert
Replace placeholders:
<principal-external-ip>: External IP where agents will reach the principal<principal-dns-name>: DNS name for the principal service<resource-proxy-ip>: IP for the resource proxy (usually cluster-internal)<resource-proxy-dns>: DNS name for resource proxy
2.3 Create JWT Signing Key¶
argocd-agentctl jwt create-key \
--principal-context <control-plane-context> \
--principal-namespace argocd \
--upsert
Step 3: Install Principal¶
3.1 Deploy Principal Component¶
Change
kubectl apply -n argocd \
-k 'https://github.com/argoproj-labs/argocd-agent/install/kubernetes/principal?ref=<release-branch>' \
--context <control-plane-context>
The principal is pre-configured to use mTLS authentication by default. You can verify this configuration:
# Check the principal authentication configuration
kubectl get configmap argocd-agent-params -n argocd --context <control-plane-context> \
-o jsonpath='{.data.principal\.auth}'
# Should output: mtls:CN=([^,]+)
Update principal configuration:
# Allow principal to operate in agent's namespace
kubectl patch configmap argocd-agent-params -n argocd --context <control-plane-context> \
--patch "{\"data\":{
\"principal.allowed-namespaces\":\"my-first-agent\"
}}"
# Restart the principal to apply changes
kubectl rollout restart deployment argocd-agent-principal -n argocd --context <control-plane-context>
3.2 Expose Principal Service¶
The principal's gRPC service needs to be accessible from workload clusters:
# Option 1: LoadBalancer
kubectl patch svc argocd-agent-principal -n argocd --context <control-plane-context> \
--patch '{"spec":{"type":"LoadBalancer"}}'
# Option 2: NodePort
kubectl patch svc argocd-agent-principal -n argocd --context <control-plane-context> \
--patch '{"spec":{"type":"NodePort","ports":[{"port":8443,"nodePort":30443}]}}'
3.3 Verify Principal Installation¶
# Check pod status
kubectl get pods -n argocd --context <control-plane-context> | grep principal
# Check logs
kubectl logs -n argocd deployment/argocd-agent-principal --context <control-plane-context>
# Expected log output:
# INFO[0001] Starting argocd-agent-principal v0.1.0
# INFO[0002] gRPC server listening on :8443
# INFO[0003] Resource proxy started on :9090
Step 4: Workload Cluster Setup¶
4.1 Choose Agent Mode¶
- Managed Mode: Principal manages Applications, agent executes them
- Autonomous Mode: Agent manages its own Applications, principal provides observability
For this guide, we'll use managed mode as it's simpler for getting started. For autonomous mode, replace agent-managed with agent-autonomous in the following commands.
4.2 Create Namespace¶
kubectl create namespace argocd --context <workload-cluster-context>
4.3 Install Argo CD on Workload Cluster¶
Replace
# For managed agents
kubectl apply -n argocd \
--server-side \
-k 'https://github.com/argoproj-labs/argocd-agent/install/kubernetes/argo-cd/agent-managed?ref=<release-branch>' \
--context <workload-cluster-context>
# For autonomous agents (alternative)
# kubectl apply -n argocd \
# --server-side \
# -k 'https://github.com/argoproj-labs/argocd-agent/install/kubernetes/argo-cd/agent-autonomous?ref=<release-branch>' \
# --context <workload-cluster-context>
This configuration includes:
- ✅ argocd-application-controller (reconciles applications - required on workload clusters)
- ✅ argocd-repo-server (Git access for the application controller)
- ✅ argocd-redis (local state for the application controller)
- ❌ argocd-server (runs on control plane only)
- ❌ argocd-dex-server (runs on control plane only)
- ❌ argocd-applicationset-controller (managed agents don't run their own, see ApplicationSets — managed agents)
Why Application Controller Runs Here
The argocd-application-controller runs on workload clusters because it needs direct access to the Kubernetes API to create, update, and delete resources. The argocd-agent facilitates communication between the control plane and these controllers, enabling centralized management while maintaining local execution.
Step 5: Create and Connect Your First Agent¶
5.1 Create Agent Configuration¶
# Create agent configuration on the principal
argocd-agentctl agent create my-first-agent \
--principal-context <control-plane-context> \
--principal-namespace argocd \
--resource-proxy-server <principal-external-ip>:9090 \
--resource-proxy-username my-first-agent \
--resource-proxy-password "$(openssl rand -base64 32)"
5.2 Issue Agent Client Certificate¶
argocd-agentctl pki issue agent my-first-agent \
--principal-context <control-plane-context> \
--agent-context <workload-cluster-context> \
--agent-namespace argocd \
--upsert
5.3 Propagate Certificate Authority to Agent¶
argocd-agentctl pki propagate \
--principal-context <control-plane-context> \
--principal-namespace argocd \
--agent-context <workload-cluster-context> \
--agent-namespace argocd
5.4 Verify Certificate Installation¶
The agent client certificate should already be installed from step 5.2. Verify it exists:
# Verify the client certificate secret exists
kubectl get secret argocd-agent-client-tls -n argocd --context <workload-cluster-context>
# Verify the CA certificate secret exists
kubectl get secret argocd-agent-ca -n argocd --context <workload-cluster-context>
5.5 Create Agent Namespace on Principal¶
For managed agents, create a namespace on the principal where the agent's Applications will be created and managed:
kubectl create namespace my-first-agent --context <control-plane-context>
5.6 Deploy Agent¶
Replace
kubectl apply -n argocd \
-k 'https://github.com/argoproj-labs/argocd-agent/install/kubernetes/agent?ref=<release-branch>' \
--context <workload-cluster-context>
5.7 Configure Agent Connection¶
Update the agent configuration to connect to your principal using mTLS authentication:
kubectl patch configmap argocd-agent-params -n argocd --context <workload-cluster-context> \
--patch "{\"data\":{
\"agent.server.address\":\"<principal-external-ip>\",
\"agent.server.port\":\"8443\",
\"agent.mode\":\"managed\",
\"agent.creds\":\"mtls:any\"
}}"
# Restart the agent to apply changes
kubectl rollout restart deployment argocd-agent-agent -n argocd --context <workload-cluster-context>
Step 6: Verification¶
6.1 Check Agent Connection¶
# Check agent logs
kubectl logs -n argocd deployment/argocd-agent-agent --context <workload-cluster-context>
# Expected output:
# INFO[0001] Starting argocd-agent (agent) v0.1.0 (ns=argocd, mode=managed, auth=mtls)
# INFO[0002] Authentication successful
# INFO[0003] Connected to argocd-agent-principal v0.1.0
6.2 Verify Principal Recognizes Agent¶
# Check principal logs
kubectl logs -n argocd deployment/argocd-agent-principal --context <control-plane-context>
# Expected output:
# INFO[0001] Agent my-first-agent connected successfully
# INFO[0002] Creating a new queue pair for client my-first-agent
6.3 List Connected Agents¶
argocd-agentctl agent list \
--principal-context <control-plane-context> \
--principal-namespace argocd
6.4 Test Application Synchronization (Managed Mode)¶
Propagate a default AppProject from principal to the agent:
kubectl patch appproject default -n argocd \
--context <control-plane-context> --type='merge' \
--patch='{"spec":{"sourceNamespaces":["*"],"destinations":[{"name":"*","namespace":"*","server":"*"}]}}'
Verify the AppProject is synchronized to the agent:
# Check that the AppProject appears on the workload cluster
kubectl get appprojs -n argocd --context <workload-cluster-context>
Create a test application on the principal:
cat <<EOF | kubectl apply -f - --context <control-plane-context>
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: test-app
namespace: my-first-agent
spec:
project: default
source:
repoURL: https://github.com/argoproj/argocd-example-apps
targetRevision: HEAD
path: guestbook
destination:
server: https://<principal-external-ip:port>?agentName=my-first-agent # For example, https://172.18.255.200:443?agentName=my-first-agent
namespace: guestbook
syncPolicy:
syncOptions:
- CreateNamespace=true
EOF
Verify the application is synchronized to the agent:
# Check that the application exists on the principal
kubectl get applications -n my-first-agent --context <control-plane-context>
# Check that the application appears on the workload cluster
kubectl get applications -n argocd --context <workload-cluster-context>
Access the Argo CD UI to see your agent and its applications!
Next Steps¶
Security Hardening¶
- Replace development certificates with production-grade PKI
- Configure proper RBAC in Argo CD
- Set up network policies to restrict traffic
- Enable audit logging for compliance
Scaling¶
- Add more agents using the Adding Agents guide
- Configure AppProjects for multi-tenancy
- Set up ApplicationSets for automated app deployment
- Implement GitOps workflows with your Git repositories
Operations¶
- Monitor agent connectivity and health
- Set up backup procedures for Argo CD state
- Plan certificate rotation schedules
- Configure alerts for agent disconnections
Troubleshooting¶
Common Issues¶
Agent Cannot Connect:
# Check network connectivity
kubectl run debug --rm -it --image=busybox --context <workload-cluster-context> \
-- nc -zv <principal-external-ip> 8443
# Verify certificates
kubectl get secrets -n argocd --context <workload-cluster-context> | grep tls
# Check client certificate
kubectl get secret argocd-agent-client-tls -n argocd --context <workload-cluster-context> -o yaml
Principal Service Not Accessible:
# Check service status
kubectl get svc argocd-agent-principal -n argocd --context <control-plane-context>
# For LoadBalancer, check external IP assignment
kubectl describe svc argocd-agent-principal -n argocd --context <control-plane-context>
Applications Not Syncing:
# Check principal logs for sync errors
kubectl logs -n argocd deployment/argocd-agent-principal --context <control-plane-context>
# Verify namespace exists on principal (managed mode)
kubectl get namespace my-first-agent --context <control-plane-context>
# Check application controller logs on workload cluster
kubectl logs -n argocd deployment/argocd-application-controller --context <workload-cluster-context>
Certificate Issues:
# Regenerate agent certificate
argocd-agentctl pki issue agent my-first-agent \
--principal-context <control-plane-context> \
--agent-context <workload-cluster-context> \
--agent-namespace argocd \
--upsert
# Check certificate validity
kubectl get secret argocd-agent-client-tls -n argocd --context <workload-cluster-context> \
-o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout
Missing Server Secretkey:
# The application status contains:
status:
conditions:
- lastTransitionTime: "2025-09-22T16:20:56Z"
message: 'error getting cluster by name "in-cluster": server.secretkey is missing'
type: InvalidSpecError
# Create a random server.secretkey
kubectl patch secret argocd-secret -n argocd \
--context <workload-cluster-context> \
--patch='{"data":{"server.secretkey":"'$(openssl rand -base64 32 | base64 -w 0)'"}}'
Related Documentation¶
- Agent Modes - Understanding autonomous vs managed modes
- Adding More Agents - Scale your deployment
- Application Synchronization — managed agents - How apps sync between clusters (managed mode)
- Application Synchronization — autonomous agents - How apps sync between clusters (autonomous mode)
- AppProject synchronization — managed agents - Managing project boundaries (managed mode)
- AppProject synchronization — autonomous agents - Managing project boundaries (autonomous mode)
- Live Resources - Viewing resources across clusters