Enterprise GitOps with ArgoCD and Harbor on RKE2: Complete Integration Guide

Introduction: Building the Complete GitOps Stack

In Part 1 of this series, we established a robust Harbor container registry on RKE2 using SUSE Application Collection. Now we’ll complete the enterprise GitOps stack by integrating ArgoCD with Harbor, creating a secure, automated continuous deployment pipeline that meets enterprise requirements.

This integration combines Harbor’s enterprise-grade container security features with ArgoCD’s declarative GitOps workflows, providing a comprehensive platform for automated application deployment with built-in security scanning, policy enforcement, and compliance capabilities.

Why ArgoCD with Harbor for Enterprise GitOps

The ArgoCD-Harbor integration provides critical enterprise capabilities:

  • Secure Image Management: Automated vulnerability scanning before deployment
  • Policy Enforcement: Pre-deployment security validation and compliance checks
  • Image Promotion: Controlled progression from development to production registries
  • Audit Trail: Complete deployment history with image provenance tracking
  • Multi-Environment GitOps: Consistent deployment patterns across environments

Architecture Overview: Complete GitOps Stack

┌────────────────────────────────────────────────────────────────────────┐
│                          GitOps Workflow Architecture                     │
├────────────────────────────────────────────────────────────────────────┤
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐ │
│  │   GitHub    │    │  CI Pipeline │    │   Harbor    │    │   ArgoCD    │ │
│  │ Repository  │───▶│ Build & Test │───▶│  Registry   │───▶│ Deployment  │ │
│  │ - Apps      │    │ - Security   │    │ - Scanning  │    │ - Sync      │ │
│  │ - Manifests │    │ - Quality    │    │ - Signing   │    │ - Rollback  │ │
│  └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘ │
├────────────────────────────────────────────────────────────────────────┤
│                           RKE2 Kubernetes Cluster                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │   ArgoCD     │  │    Harbor    │  │  Application │  │  Monitoring  │  │
│  │  - Server    │  │  - Core      │  │  Workloads   │  │  - Prometheus│  │
│  │  - Repo Srv  │  │  - Registry  │  │  - Services  │  │  - Grafana   │  │
│  │  - App Ctrl  │  │  - Scanner   │  │  - Ingress   │  │  - Alerts    │  │
│  │  - Redis     │  │  - Notary    │  │  - Storage   │  │  - Logs      │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘  │
└────────────────────────────────────────────────────────────────────────┘

Part 1: ArgoCD Installation and Configuration

Prerequisites and Environment Validation

Before proceeding, ensure you have the Harbor setup from Part 1 and validate your environment:

# Verify Harbor is running and accessible
kubectl get pods -n harbor-system
kubectl get ingress -n harbor-system

# Test Harbor API connectivity
curl -k https://harbor.yourdomain.com/api/v2.0/systeminfo

# Verify sufficient cluster resources for ArgoCD
kubectl top nodes
kubectl get storageclass

ArgoCD Installation via SUSE Application Collection

Install ArgoCD using the SUSE Application Collection for enterprise support:

# Verify SUSE Application Collection repository
helm repo list | grep suse-application-collection
helm search repo suse-application-collection/argo-cd

# Create ArgoCD namespace with proper labels
kubectl create namespace argocd-system
kubectl label namespace argocd-system name=argocd-system

# Label nodes for ArgoCD workload placement
kubectl label nodes worker-node-1 argocd.io/workload=server
kubectl label nodes worker-node-2 argocd.io/workload=server
kubectl label nodes worker-node-3 argocd.io/workload=repo-server

Create ArgoCD values configuration:

# argocd-values.yaml
global:
  domain: argocd.yourdomain.com
  
server:
  replicas: 2
  nodeSelector:
    argocd.io/workload: server
  
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt-prod-harbor"
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
    hosts:
    - argocd.yourdomain.com
    tls:
    - secretName: argocd-server-tls
      hosts:
      - argocd.yourdomain.com

repoServer:
  replicas: 2
  nodeSelector:
    argocd.io/workload: repo-server
  
  # Harbor registry access configuration
  env:
  - name: DOCKER_CONFIG
    value: /tmp/.docker
  
  volumeMounts:
  - name: harbor-registry-config
    mountPath: /tmp/.docker
    readOnly: true
  
  volumes:
  - name: harbor-registry-config
    secret:
      secretName: harbor-registry-config
# Install ArgoCD
helm upgrade --install argocd \
  suse-application-collection/argo-cd \
  --namespace argocd-system \
  --values argocd-values.yaml \
  --timeout 20m \
  --wait

# Get initial admin password
kubectl -n argocd-system get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

Part 2: Harbor-ArgoCD Integration

Creating Harbor Robot Accounts

Create dedicated robot accounts in Harbor for ArgoCD automation via Harbor UI:

  1. Navigate to Harbor UI → Administration → Robot Accounts
  2. Create new robot account: argocd-deployer
  3. Set expiration to 1 year
  4. Grant permissions: Pull on all projects, Push on dev projects
  5. Save robot token securely

Configuring Registry Credentials

# Create Harbor registry secret for ArgoCD
kubectl create secret docker-registry harbor-registry-config \
  --docker-server=harbor.yourdomain.com \
  --docker-username="robot\$argocd-deployer" \
  --docker-password="[robot-token-from-harbor]" \
  --namespace=argocd-system

# Create image pull secrets for application namespaces
for ns in default production staging development; do
  kubectl create namespace $ns --dry-run=client -o yaml | kubectl apply -f -
  
  kubectl create secret docker-registry harbor-registry-secret \
    --docker-server=harbor.yourdomain.com \
    --docker-username="robot\$argocd-deployer" \
    --docker-password="[robot-token-from-harbor]" \
    --namespace=$ns \
    --dry-run=client -o yaml | kubectl apply -f -
  
  kubectl patch serviceaccount default -n $ns \
    -p '{"imagePullSecrets": [{"name": "harbor-registry-secret"}]}'
done

Part 3: GitOps Workflows and Applications

Sample Application with Harbor Images

# sample-app/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      imagePullSecrets:
      - name: harbor-registry-secret
      containers:
      - name: web-app
        image: harbor.yourdomain.com/library/nginx:1.25.3
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi
        securityContext:
          runAsNonRoot: true
          runAsUser: 101
          readOnlyRootFilesystem: true
---
apiVersion: v1
kind: Service
metadata:
  name: web-app-service
spec:
  selector:
    app: web-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

ArgoCD Application Configuration

# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app
  namespace: argocd-system
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/k8s-manifests.git
    targetRevision: HEAD
    path: sample-app
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
# Deploy ArgoCD Application
kubectl apply -f argocd-application.yaml

# Monitor application sync
kubectl get application web-app -n argocd-system

Part 4: CI/CD Pipeline Integration

Complete GitHub Actions Workflow

# .github/workflows/ci-cd-pipeline.yaml
name: CI/CD Pipeline with Harbor and ArgoCD

on:
  push:
    branches: [ main, develop ]

env:
  HARBOR_REGISTRY: harbor.yourdomain.com
  HARBOR_PROJECT: library
  IMAGE_NAME: web-app

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
      
    - name: Login to Harbor
      uses: docker/login-action@v3
      with:
        registry: ${{ env.HARBOR_REGISTRY }}
        username: ${{ secrets.HARBOR_USERNAME }}
        password: ${{ secrets.HARBOR_PASSWORD }}
        
    - name: Build and push image
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
        
    - name: Wait for Harbor scan
      run: |
        sleep 30
        # Check vulnerability scan results
        SCAN_RESULT=$(curl -s -u "${{ secrets.HARBOR_USERNAME }}:${{ secrets.HARBOR_PASSWORD }}" \
          "${{ env.HARBOR_REGISTRY }}/api/v2.0/projects/${{ env.HARBOR_PROJECT }}/repositories/${{ env.IMAGE_NAME }}/artifacts/${{ github.sha }}/scan")
        
        CRITICAL=$(echo $SCAN_RESULT | jq -r '.scan_overview."application/vnd.security.vulnerability.report; version=1.1".summary.critical // 0')
        
        if [ "$CRITICAL" -gt 0 ]; then
          echo "❌ Image has $CRITICAL critical vulnerabilities"
          exit 1
        fi

  update-manifests:
    needs: build-and-scan
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Checkout manifests repository
      uses: actions/checkout@v4
      with:
        repository: your-org/k8s-manifests
        token: ${{ secrets.MANIFEST_REPO_TOKEN }}
        
    - name: Update image tag
      run: |
        sed -i "s|image: ${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMAGE_NAME }}:.*|image: ${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/${{ env.IMAGE_NAME }}:${{ github.sha }}|" sample-app/deployment.yaml
        
    - name: Commit and push changes
      run: |
        git config user.name "GitHub Actions"
        git config user.email "actions@github.com"
        git add .
        git commit -m "Update ${{ env.IMAGE_NAME }} to ${{ github.sha }}"
        git push

Part 5: Production Operations

Monitoring and Observability

# Key ArgoCD metrics to monitor:
- argocd_app_health_status      # Application health
- argocd_app_sync_total         # Sync operations
- argocd_git_request_duration   # Repository performance
- argocd_app_reconcile_bucket   # Controller performance

# Essential alerts:
- ArgoCD application sync failures
- Harbor registry downtime
- Critical vulnerabilities in deployed images
- Certificate expiration warnings

Security and Compliance

# OPA Gatekeeper policy for Harbor images only
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: harborimageorigin
spec:
  crd:
    spec:
      names:
        kind: HarborImageOrigin
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package harborimageorigin
        
        violation[{"msg": msg}] {
          input.review.kind.kind == "Deployment"
          container := input.review.object.spec.template.spec.containers[_]
          image := container.image
          not startswith(image, "harbor.yourdomain.com/")
          msg := sprintf("Image %v must come from Harbor registry", [image])
        }

Backup and Disaster Recovery

# ArgoCD backup script
#!/bin/bash
echo "Starting ArgoCD backup..."

# Export applications, projects, repositories, clusters
argocd app list -o json > applications.json
argocd proj list -o json > projects.json  
argocd repo list -o json > repositories.json
argocd cluster list -o json > clusters.json

# Create backup archive
tar -czf argocd-backup-$(date +%Y%m%d).tar.gz *.json

# Upload to backup storage
aws s3 cp argocd-backup-$(date +%Y%m%d).tar.gz s3://backup-bucket/argocd/

Troubleshooting Common Issues

# Common troubleshooting commands:

# Check ArgoCD application status
kubectl get applications -n argocd-system
argocd app get web-app

# Verify image pull secrets
kubectl get secrets | grep harbor
kubectl describe pod [failing-pod]

# Test Harbor registry connectivity
kubectl run -it --rm debug --image=busybox --restart=Never -- \
  wget -O- https://harbor.yourdomain.com/v2/

# Check ArgoCD sync issues
argocd app diff web-app
argocd app sync web-app --dry-run

# Review logs
kubectl logs -n argocd-system deployment/argocd-application-controller
kubectl logs -n harbor-system deployment/harbor-core

Production Best Practices

Security Best Practices

  • Image Security: Mandatory vulnerability scanning with severity thresholds
  • Access Control: Dedicated robot accounts with minimal permissions
  • Network Security: Network policies restricting component communication
  • Content Trust: Image signing for production deployments
  • Secret Management: Regular credential rotation

Operational Excellence

  • Monitoring: Application health and sync status monitoring
  • Alerting: Proactive alerts for failures and security issues
  • Backup: Automated configuration and data backups
  • Documentation: Current runbooks and procedures
  • Testing: Regular disaster recovery testing

Conclusion

You now have a production-ready GitOps platform that combines Harbor’s enterprise container security with ArgoCD’s declarative deployment automation. This integration provides:

  • Complete Security Pipeline: From vulnerability scanning to policy enforcement
  • Automated Operations: Self-healing deployments with monitoring
  • Enterprise Integration: Authentication, RBAC, and audit trails
  • Scalable Architecture: High-availability supporting large deployments
  • Developer Productivity: GitOps workflows enabling rapid delivery

This platform serves as the foundation for modern DevOps practices, enabling secure, automated application delivery that scales with enterprise requirements. The Harbor-ArgoCD integration creates a robust deployment pipeline suitable for demanding production environments.

Next Steps

Consider exploring these advanced topics to further enhance your GitOps platform:

  • Multi-Cluster Management: Extend ArgoCD across multiple Kubernetes clusters
  • Progressive Delivery: Implement canary and blue-green deployments with Argo Rollouts
  • Policy as Code: Expand governance with comprehensive OPA policies
  • Supply Chain Security: Integrate SLSA compliance and SBOM generation
  • Advanced Observability: Implement distributed tracing and APM