GitOps & Continuous Delivery
ArgoCD for Platform Teams
4 min read
ArgoCD is the most popular GitOps tool for Kubernetes. For platform teams, it provides the foundation for automated, auditable deployments across multiple clusters and environments.
Installing ArgoCD
Deploy ArgoCD to your cluster:
# Create namespace
kubectl create namespace argocd
# Install ArgoCD (HA mode for production)
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/ha/install.yaml
# Or using Helm for more control
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--set server.service.type=LoadBalancer \
--set configs.params."server\.insecure"=true
# Wait for pods
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s
# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
# Access UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Open https://localhost:8080
ArgoCD Architecture
┌─────────────────────────────────────────────────────────┐
│ ARGOCD COMPONENTS │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ API Server │────│ Web UI │ │
│ │ (argocd-server) │ │ (React app) │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ │
│ ┌────────┴─────────┐ ┌──────────────────┐ │
│ │ Repo Server │────│ Application │ │
│ │ (argocd-repo- │ │ Controller │ │
│ │ server) │ │ (reconciliation) │ │
│ └──────────────────┘ └────────┬─────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Git Repos │ │ Clusters │ │
│ │ (source of │ │ (deployment │ │
│ │ truth) │ │ targets) │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Creating Applications
Deploy your first application with ArgoCD:
# application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: user-service
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/acme/gitops-repo.git
targetRevision: main
path: apps/overlays/production/user-service
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Delete resources removed from Git
selfHeal: true # Fix drift automatically
allowEmpty: false # Don't sync if source is empty
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# Apply the application
kubectl apply -f application.yaml
# Check status
argocd app get user-service
# Sync manually if needed
argocd app sync user-service
# View in UI
argocd app list
ApplicationSets for Scale
ApplicationSets generate multiple Applications from a single template:
# applicationset-all-apps.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: all-applications
namespace: argocd
spec:
generators:
# Generate from directory structure
- git:
repoURL: https://github.com/acme/gitops-repo.git
revision: main
directories:
- path: apps/overlays/production/*
template:
metadata:
name: '{{path.basename}}'
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/acme/gitops-repo.git
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
Multi-Cluster ApplicationSets
Deploy to multiple clusters:
# applicationset-multi-cluster.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-apps
namespace: argocd
spec:
generators:
- matrix:
generators:
# Clusters
- clusters:
selector:
matchLabels:
environment: production
# Applications
- git:
repoURL: https://github.com/acme/gitops-repo.git
revision: main
directories:
- path: apps/base/*
template:
metadata:
name: '{{name}}-{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/acme/gitops-repo.git
targetRevision: main
path: 'apps/overlays/{{metadata.labels.environment}}/{{path.basename}}'
destination:
server: '{{server}}'
namespace: '{{path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Adding Clusters
Register external clusters with ArgoCD:
# Add cluster using kubeconfig context
argocd cluster add production-cluster --name production
# Or via declarative Secret
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: production-cluster
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
environment: production
type: Opaque
stringData:
name: production
server: https://production.k8s.acme.com
config: |
{
"bearerToken": "...",
"tlsClientConfig": {
"insecure": false,
"caData": "..."
}
}
EOF
# List clusters
argocd cluster list
Projects for Multi-Tenancy
ArgoCD Projects provide RBAC boundaries:
# project-team-orders.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-orders
namespace: argocd
spec:
description: "Order team applications"
# Allowed source repositories
sourceRepos:
- https://github.com/acme/orders-*
- https://github.com/acme/gitops-repo.git
# Allowed destinations
destinations:
- namespace: 'orders-*'
server: https://kubernetes.default.svc
- namespace: team-orders
server: '*'
# Allowed cluster resources
clusterResourceWhitelist:
- group: ''
kind: Namespace
# Allowed namespace resources
namespaceResourceWhitelist:
- group: '*'
kind: '*'
# Denied resources
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
- group: ''
kind: LimitRange
# Role definitions
roles:
- name: developer
description: "Can sync and view applications"
policies:
- p, proj:team-orders:developer, applications, get, team-orders/*, allow
- p, proj:team-orders:developer, applications, sync, team-orders/*, allow
groups:
- team-orders-developers
- name: admin
description: "Full access to team applications"
policies:
- p, proj:team-orders:admin, applications, *, team-orders/*, allow
groups:
- team-orders-admins
Notifications
Configure ArgoCD notifications for deployment events:
# argocd-notifications-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
template.app-deployed: |
message: |
Application {{.app.metadata.name}} is now {{.app.status.sync.status}}.
{{if eq .app.status.sync.status "Synced"}}
:white_check_mark: Deployment successful!
{{end}}
slack:
attachments: |
[{
"title": "{{.app.metadata.name}}",
"color": "{{if eq .app.status.sync.status \"Synced\"}}good{{else}}warning{{end}}",
"fields": [
{"title": "Sync Status", "value": "{{.app.status.sync.status}}", "short": true},
{"title": "Repository", "value": "{{.app.spec.source.repoURL}}", "short": true}
]
}]
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
send: [app-deployed]
# Add annotation to Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: user-service
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: deployments-channel
In the next lesson, we'll explore progressive delivery patterns with Argo Rollouts for safer deployments. :::