GitOps Module — Presentation 2 of 4

Installing ArgoCD on AKS

From Empty Cluster to GitOps-Ready Platform

Civica Training Program

Where We Are in the Journey

You understand GitOps principles. Now it's time to get your hands dirty.

The Mission

You have a fresh AKS cluster. Your team lead says: "Get ArgoCD running by end of day. We need it production-ready — HA, secured, accessible to the team." Let's do this step by step.

Phase 1

Prerequisites & installation method

Phase 2

Configure, secure, and expose ArgoCD

Phase 3

Connect Git repos & verify

Prerequisites Checklist

What you need before installing ArgoCD.

Infrastructure

  • AKS cluster (Kubernetes 1.25+)
  • At least 2 nodes (for HA)
  • Cluster admin access via az aks get-credentials
  • Azure subscription with contributor rights

CLI Tools

  • kubectl — Kubernetes CLI
  • helm v3+ — Package manager
  • az — Azure CLI (authenticated)
  • argocd — ArgoCD CLI (install later)

Verify Your Setup

# Confirm cluster access
az aks get-credentials --resource-group myRG --name myAKS
kubectl get nodes
kubectl cluster-info

# Confirm Helm
helm version

Installation Methods

Two primary approaches to installing ArgoCD on Kubernetes.

Method 1: kubectl apply

kubectl create namespace argocd

kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/
  argoproj/argo-cd/stable/
  manifests/install.yaml
  • Simple, quick to get started
  • Official manifests from Argo project
  • Harder to customise at scale
  • Good for dev/learning environments

Method 2: Helm Chart

helm repo add argo \
  https://argoproj.github.io/argo-helm

helm install argocd argo/argo-cd \
  --namespace argocd \
  --create-namespace \
  -f values.yaml
  • Highly customisable via values.yaml
  • Easy to upgrade and manage
  • HA configuration built-in
  • Recommended for production

ArgoCD Helm Chart: Key Components

Understanding what gets deployed.

Core Components

  • argocd-server — API server + Web UI
  • argocd-repo-server — Clones Git repos, generates manifests
  • argocd-application-controller — Watches apps, syncs to cluster

Supporting Components

  • argocd-redis — Caching layer
  • argocd-dex-server — OIDC/SSO provider
  • argocd-applicationset-controller — Generates apps from templates
  • argocd-notifications-controller — Sends alerts

In HA mode, the server and controller run with multiple replicas for fault tolerance.

Helm Values: Production Configuration

Essential values.yaml settings for a production-ready ArgoCD.

# values-production.yaml
global:
  image:
    tag: "v2.10.0"  # Pin to specific version

server:
  replicas: 2
  resources:
    requests:
      cpu: "250m"
      memory: "256Mi"
    limits:
      cpu: "500m"
      memory: "512Mi"

controller:
  replicas: 1  # Only 1 active (leader election)
  resources:
    requests:
      cpu: "500m"
      memory: "512Mi"

repoServer:
  replicas: 2
  resources:
    requests:
      cpu: "250m"
      memory: "256Mi"

High Availability Configuration

Making ArgoCD resilient to node failures.

HA Components

redis-ha:
  enabled: true
  haproxy:
    enabled: true

controller:
  env:
    - name: ARGOCD_CONTROLLER_REPLICAS
      value: "2"

server:
  replicas: 2
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 5

Pod Disruption Budgets

server:
  pdb:
    enabled: true
    minAvailable: 1

repoServer:
  pdb:
    enabled: true
    minAvailable: 1

PDBs ensure at least one pod stays running during node drains or upgrades.

Tip: Use topologySpreadConstraints to spread pods across availability zones on AKS.

Knowledge Check #1

Installation basics.

Q1: Which ArgoCD installation method is recommended for production?

Answer: B) Helm chart with custom values.yaml. Helm provides the most customisable and maintainable installation. You can configure HA, resources, RBAC, and SSO through values.yaml.

Q2: Which component is responsible for cloning Git repositories and generating manifests?

Answer: C) argocd-repo-server. The repo-server clones Git repositories, runs Helm template / Kustomize build, and provides rendered manifests to the application controller.

Q3: In HA mode, how many ArgoCD application controller replicas should be active?

Answer: B) Only 1 active (with leader election). The application controller uses leader election. Multiple replicas can be deployed for failover, but only one is active at a time to avoid conflicting reconciliation.

Running the Helm Installation

Step-by-step commands to deploy ArgoCD.

# Step 1: Add the Argo Helm repository
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

# Step 2: Create the namespace
kubectl create namespace argocd

# Step 3: Install with production values
helm install argocd argo/argo-cd \
  --namespace argocd \
  --version 6.0.0 \
  -f values-production.yaml

# Step 4: Verify the installation
kubectl get pods -n argocd
kubectl get svc -n argocd

# Expected: All pods Running, services created

Expected Output

NAME                                              READY   STATUS
argocd-application-controller-0                   1/1     Running
argocd-dex-server-xxx                             1/1     Running
argocd-redis-xxx                                  1/1     Running
argocd-repo-server-xxx                            1/1     Running
argocd-server-xxx                                 1/1     Running

Exposing ArgoCD: Access Options

Making the ArgoCD UI and API accessible to your team.

Option 1: Port Forward

kubectl port-forward \
  svc/argocd-server \
  -n argocd 8080:443

Quick for development. Not suitable for team access.

Option 2: LoadBalancer

server:
  service:
    type: LoadBalancer

Simple. Gets an Azure public IP. Add NSG rules for security.

Option 3: Ingress

server:
  ingress:
    enabled: true
    hostname: argocd.company.com

Production-grade. TLS termination, path routing. Recommended.

Exposing with Ingress (Recommended)

Using NGINX Ingress Controller with TLS.

# values-production.yaml (continued)
server:
  ingress:
    enabled: true
    ingressClassName: nginx
    hostname: argocd.civica.internal
    tls: true
    annotations:
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
      cert-manager.io/cluster-issuer: "letsencrypt-prod"

  # Important: ArgoCD needs --insecure flag if TLS terminates at ingress
  extraArgs:
    - --insecure  # Only if using TLS termination at ingress level

Azure Application Gateway Alternative

If using Azure Application Gateway Ingress Controller (AGIC), replace ingressClassName: nginx with ingressClassName: azure-application-gateway and configure the appropriate annotations.

Initial Admin Password & Login

Getting into ArgoCD for the first time.

Retrieve the Initial Admin Password

# The initial password is stored in a Kubernetes secret
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

# Login via CLI
argocd login argocd.civica.internal \
  --username admin \
  --password <initial-password>

# IMPORTANT: Change the password immediately!
argocd account update-password

Security Best Practice

  • Change the admin password immediately
  • Set up SSO (Azure AD OIDC) to replace password auth
  • Disable the admin account after SSO is configured
  • Delete the initial-admin-secret

Disable Admin After SSO

configs:
  params:
    accounts.admin: ""
  cm:
    admin.enabled: "false"

ArgoCD CLI Setup

Installing and configuring the ArgoCD command-line interface.

Install the CLI

# macOS
brew install argocd

# Linux
curl -sSL -o argocd \
  https://github.com/argoproj/argo-cd/
  releases/latest/download/
  argocd-linux-amd64
chmod +x argocd
sudo mv argocd /usr/local/bin/

# Windows (Chocolatey)
choco install argocd-cli

Common CLI Commands

# Login
argocd login argocd.civica.internal

# List applications
argocd app list

# Get app details
argocd app get my-app

# Sync an application
argocd app sync my-app

# View app diff
argocd app diff my-app

# View cluster info
argocd cluster list

ArgoCD Architecture on AKS

How all the pieces fit together in your cluster.

External

Git Repository (Azure DevOps / GitHub)
Container Registry (ACR)
Users (Browser / CLI)

AKS Cluster — argocd namespace

argocd-server
API + UI
repo-server
Git clone + render
app-controller
Reconciliation
Redis
Cache
↓ applies manifests to
Target Namespaces (dev, staging, prod)

Knowledge Check #2

Exposing and accessing ArgoCD.

Q1: Where is the initial ArgoCD admin password stored?

Answer: B) In the argocd-initial-admin-secret Kubernetes Secret. The initial admin password is auto-generated and stored as a base64-encoded Kubernetes secret in the argocd namespace.

Q2: What is the recommended way to expose ArgoCD in production?

Answer: C) Ingress with TLS. Ingress provides a stable DNS hostname, TLS termination (via cert-manager), and can be secured with authentication and network policies.

Q3: After setting up SSO, what should you do with the admin account?

Answer: C) Disable it and delete the initial-admin-secret. The admin account should be disabled once SSO is configured. This follows the principle of least privilege and reduces the attack surface.

Connecting Your First Git Repository

ArgoCD needs access to the Git repo containing your Kubernetes manifests.

Via CLI

# Add a private repo with HTTPS
argocd repo add \
  https://github.com/civica/gitops-config \
  --username git \
  --password <PAT-token>

# Add with SSH
argocd repo add \
  [email protected]:civica/gitops-config.git \
  --ssh-private-key-path ~/.ssh/id_ed25519

# Verify
argocd repo list

Via UI

  1. Navigate to SettingsRepositories
  2. Click Connect Repo
  3. Choose connection method (HTTPS or SSH)
  4. Enter repository URL
  5. Provide credentials (PAT or SSH key)
  6. Click Connect
  7. Verify status shows Successful

Authentication: SSH Keys

The most secure method for Git repository access.

Generate a Deploy Key

# Generate an Ed25519 key pair (no passphrase for automation)
ssh-keygen -t ed25519 -C "argocd-deploy-key" -f argocd-key -N ""

# argocd-key      = private key (stays in ArgoCD)
# argocd-key.pub  = public key (goes to Git provider)

# Add private key to ArgoCD
argocd repo add [email protected]:civica/gitops-config.git \
  --ssh-private-key-path ./argocd-key

# Add public key to GitHub/Azure DevOps as a Deploy Key (read-only)

Why Deploy Keys?

  • Scoped to a single repository (least privilege)
  • Can be read-only (ArgoCD only needs to read)
  • Don't expire like personal access tokens
  • Not tied to a personal user account

Authentication: HTTPS Tokens

Using personal access tokens or app credentials for HTTPS repos.

GitHub Personal Access Token

# Create a fine-grained PAT with:
# - Repository access: read-only
# - Contents: read

argocd repo add \
  https://github.com/civica/gitops-config \
  --username git \
  --password ghp_xxxYourTokenHere

GitHub uses "git" as the username with PAT as password.

Azure DevOps

# Create a PAT in Azure DevOps with:
# - Code: Read

argocd repo add \
  https://dev.azure.com/civica/project/
    _git/gitops-config \
  --username azure \
  --password <PAT>

Azure DevOps PATs can be scoped to specific organisations and projects.

Warning: HTTPS tokens can expire. Set up rotation procedures or use SSH deploy keys for long-lived access. Store credentials as Kubernetes secrets, never in values.yaml.

How ArgoCD Stores Credentials

Understanding where repo credentials live in the cluster.

Kubernetes Secrets

ArgoCD stores repository credentials as Kubernetes Secrets in the argocd namespace. Each repository connection creates a secret with specific labels.

# View repo credentials (secret names)
kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository

# Or use declarative config:
apiVersion: v1
kind: Secret
metadata:
  name: my-repo-creds
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: [email protected]:civica/gitops-config.git
  sshPrivateKey: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...

Credential Templates: Use secret-type: repo-creds to define credentials once for all repos under a URL prefix (e.g., all repos in github.com/civica/).

Creating Your First ArgoCD Application

Now let's deploy something! Defining an Application resource.

# my-first-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Application Spec: Field by Field

Understanding every important field in the Application resource.

FieldPurpose
spec.projectArgoCD Project for RBAC scoping. default allows everything.
spec.source.repoURLGit repository URL (must be registered in ArgoCD).
spec.source.targetRevisionBranch, tag, or commit SHA to track. HEAD = latest on default branch.
spec.source.pathDirectory within the repo containing manifests.
spec.destination.serverCluster API URL. https://kubernetes.default.svc = same cluster.
spec.destination.namespaceTarget namespace for deployment.
syncPolicy.automatedEnable auto-sync. Without this, sync is manual.
syncPolicy.automated.pruneDelete resources removed from Git.
syncPolicy.automated.selfHealRevert manual changes (drift correction).

Apply and Verify

Deploying the application and checking its status.

Deploy via CLI

# Apply the Application manifest
kubectl apply -f my-first-app.yaml

# Or create via ArgoCD CLI
argocd app create guestbook \
  --repo https://github.com/argoproj/
    argocd-example-apps \
  --path guestbook \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace guestbook \
  --sync-policy automated \
  --auto-prune \
  --self-heal

Verify Status

# Check application status
argocd app get guestbook

# Expected output:
Name:       guestbook
Server:     https://kubernetes.default.svc
Namespace:  guestbook
URL:        https://argocd.civica.internal/
            applications/guestbook
Sync Status:  Synced
Health Status: Healthy

# Verify in cluster
kubectl get all -n guestbook

Knowledge Check #3

Git repositories and ArgoCD applications.

Q1: What is the recommended authentication method for ArgoCD to access Git repos?

Answer: B) SSH deploy keys (read-only, per-repo). Deploy keys follow the principle of least privilege: scoped to one repo, read-only access, not tied to a personal account, and don't expire.

Q2: What does syncPolicy.automated.selfHeal: true do?

Answer: B) Reverts manual changes in the cluster to match Git. selfHeal detects drift (manual kubectl edits, etc.) and automatically reconciles the cluster state back to what Git declares.

Q3: What does spec.source.targetRevision: HEAD mean?

Answer: B) Track the latest commit on the default branch. HEAD refers to the tip of the default branch (usually main or master). You can also specify a branch name, tag, or commit SHA.

Sync Policies and Options

Fine-tuning how ArgoCD deploys your applications.

Sync Policies

automatedAuto-sync on Git change
automated.pruneDelete removed resources
automated.selfHealFix drift automatically
automated.allowEmptyAllow syncing to empty state

Sync Options

CreateNamespace=trueAuto-create target namespace
PruneLast=trueDelete resources after all others are healthy
ApplyOutOfSyncOnly=trueOnly apply changed resources
Validate=falseSkip schema validation
Replace=trueUse replace instead of apply

Caution: For production, consider manual sync (no automated) with required PR approvals. Auto-sync is great for dev/staging but adds risk in production without proper safeguards.

Source Types: Helm & Kustomize

ArgoCD isn't limited to plain YAML — it understands Helm charts and Kustomize overlays natively.

Helm Source

spec:
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: nginx
    targetRevision: 15.0.0
    helm:
      values: |
        replicaCount: 3
        service:
          type: ClusterIP

Point directly at a Helm chart repository.

Kustomize Source

spec:
  source:
    repoURL: [email protected]:civica/gitops-config
    targetRevision: main
    path: apps/my-app/overlays/dev
    kustomize:
      images:
        - myacr.azurecr.io/my-app:v1.2.3

ArgoCD detects kustomization.yaml and runs kustomize build.

Multi-Source Applications

Combining multiple sources in a single ArgoCD Application (ArgoCD 2.6+).

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  sources:  # Note: "sources" (plural)
    - repoURL: https://charts.bitnami.com/bitnami
      chart: nginx
      targetRevision: 15.0.0
      helm:
        valueFiles:
          - $values/apps/nginx/values-prod.yaml  # From second source
    - repoURL: [email protected]:civica/gitops-config
      targetRevision: main
      ref: values  # Referenced as $values above
  destination:
    server: https://kubernetes.default.svc
    namespace: nginx

This pattern lets you use a Helm chart from a public registry while keeping your custom values in your own Git repo.

Upgrading ArgoCD

Keeping ArgoCD up to date safely.

Helm Upgrade Process

# Check current version
argocd version

# Update Helm repo
helm repo update

# Review changes
helm diff upgrade argocd argo/argo-cd \
  --namespace argocd \
  -f values-production.yaml \
  --version 6.1.0

# Apply upgrade
helm upgrade argocd argo/argo-cd \
  --namespace argocd \
  -f values-production.yaml \
  --version 6.1.0

Upgrade Best Practices

  • Always read the release notes for breaking changes
  • Test upgrades in a non-production cluster first
  • Use helm diff plugin to preview changes
  • Back up ArgoCD resources before upgrading
  • Pin chart versions in your values file
  • Upgrade one minor version at a time

Namespace-Scoped vs Cluster-Scoped

Choosing the right installation scope.

Cluster-Scoped (Default)

  • ArgoCD can manage resources in any namespace
  • Needs cluster-admin privileges
  • One ArgoCD instance per cluster
  • Best for centralised platform teams
# Default installation
helm install argocd argo/argo-cd \
  --namespace argocd

Namespace-Scoped

  • ArgoCD can only manage resources in specified namespaces
  • Reduced RBAC requirements
  • Multiple ArgoCD instances per cluster
  • Best for multi-tenant clusters
configs:
  params:
    application.namespaces: "team-a-*"

Knowledge Check #4

Applications and advanced configuration.

Q1: What does syncPolicy.automated.prune: true do?

Answer: B) Deletes Kubernetes resources that were removed from Git. When prune is enabled, if you delete a resource from Git, ArgoCD will also delete it from the cluster. Without prune, orphaned resources remain.

Q2: How does ArgoCD handle Helm charts?

Answer: B) It runs helm template to render manifests, then applies them. ArgoCD uses helm template in the repo-server to render the chart into plain Kubernetes manifests, then applies those manifests. It does not use helm install or Helm releases.

Q3: What is the benefit of multi-source Applications?

Answer: B) They combine a Helm chart from one repo with values from another. Multi-source Applications let you reference a public Helm chart while keeping custom values.yaml in your private GitOps repo.

Troubleshooting Installation Issues

Common problems and how to fix them.

Pods Not Starting

# Check pod events
kubectl describe pod -n argocd \
  argocd-server-xxx

# Check logs
kubectl logs -n argocd \
  argocd-server-xxx

# Common causes:
# - Insufficient resources
# - Image pull errors (ACR auth)
# - PVC not binding (Redis HA)

Can't Connect to Repo

# Test from repo-server
kubectl exec -n argocd \
  deploy/argocd-repo-server -- \
  git ls-remote <repo-url>

# Common causes:
# - Wrong SSH key / PAT
# - Network policy blocking egress
# - SSH host key not trusted
# - Firewall blocking port 22/443

Module 2 Summary

What we accomplished today.

Installed

ArgoCD via Helm with production-ready configuration, HA, and resource limits.

Exposed

ArgoCD UI via Ingress with TLS. Set up initial login and CLI access.

Connected

Git repository with SSH deploy keys. Created and verified first Application.

Next: Bootstrapping the GitOps Workflow — App of Apps, Kustomize overlays, sealed secrets, and environment management.

Questions & Discussion

Installing ArgoCD on AKS

Next up: Bootstrapping the GitOps Workflow

Civica Training Program GitOps Module — 2 of 4
1 / 32
← Back