An ArgoCD controller that implements a pull-based application delivery model for multi-cluster environments using Open Cluster Management (OCM).
Traditional ArgoCD deployments use a "push" model where applications are pushed from a centralized ArgoCD instance to remote clusters. This controller enables a "pull" model where remote clusters pull their applications from a central hub, providing better scalability, security, and resilience.
- Scalability: Hub-spoke architecture scales better than centralized push
- Security: Cluster credentials are not stored in a centralized location
- Resilience: Reduces single point of failure impact
- Decentralization: Remote clusters maintain autonomy while staying synchronized
The controller consists of three main components:
- Application Controller: Watches ArgoCD Applications with specific labels/annotations and wraps them in OCM ManifestWork objects
- Application Status Controller: Syncs application status from ManifestWork back to the hub Application
- Cluster Controller: Manages cluster registration and ArgoCD cluster secrets
- ArgoCD Applications on the hub cluster are marked with special labels and annotations
- The Application Controller detects these applications and creates ManifestWork objects containing the Application as payload
- OCM agents on managed clusters pull these ManifestWork objects and apply the contained Applications
- Application status is synced back from managed clusters to the hub through ManifestWork status feedback
- Open Cluster Management (OCM): Multi-cluster environment with hub and managed clusters
- See OCM Quick Start for setup instructions
- ArgoCD: Installed on both hub and managed clusters
- See ArgoCD Getting Started for installation
For Applications to be processed by the pull controller, they must include:
metadata:
labels:
apps.open-cluster-management.io/pull-to-ocm-managed-cluster: "true"
annotations:
argocd.argoproj.io/skip-reconcile: "true"
apps.open-cluster-management.io/ocm-managed-cluster: "<target-cluster-name>"
pull-to-ocm-managed-cluster
label: Enables the pull controller to process this Applicationskip-reconcile
annotation: Prevents the Application from reconciling on the hub clusterocm-managed-cluster
annotation: Specifies which managed cluster should receive this Application
Option A: Disable Hub ArgoCD Application Controller (Legacy Method)
If your ArgoCD version doesn't support the skip-reconcile
annotation:
kubectl -n argocd scale statefulset/argocd-application-controller --replicas 0
Option B: Use Skip Reconcile (Recommended)
For ArgoCD versions that support skip reconcile, no additional configuration needed.
kubectl apply -f https://raw.githubusercontent.com/open-cluster-management-io/argocd-pull-integration/main/deploy/install.yaml
Check that the controller is running:
kubectl -n open-cluster-management get deploy | grep pull
Expected output:
argocd-pull-integration-controller-manager 1/1 1 1 106s
Create an ArgoCD cluster secret representing each managed cluster:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: <cluster-name>-secret
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: <cluster-name>
server: https://<cluster-name>-control-plane:6443
EOF
Note: Replace <cluster-name>
with your actual managed cluster name. This step can be automated using the OCM auto import controller.
kubectl apply -f example/hub
Apply the required RBAC and configuration on each managed cluster:
kubectl apply -f example/managed
Deploy the included guestbook example to test the pull integration:
kubectl apply -f example/guestbook-app-set.yaml
The ApplicationSet template must include the required annotations and labels:
spec:
template:
metadata:
labels:
apps.open-cluster-management.io/pull-to-ocm-managed-cluster: "true"
annotations:
argocd.argoproj.io/skip-reconcile: "true"
apps.open-cluster-management.io/ocm-managed-cluster: "{{name}}"
kubectl -n argocd get appset
Expected output:
NAME AGE
guestbook-app 84s
kubectl -n argocd get app
Expected output:
NAME SYNC STATUS HEALTH STATUS
cluster1-guestbook-app Unknown Unknown
On the hub cluster, verify ManifestWork objects are created:
kubectl -n <cluster-name> get manifestwork
Expected output:
NAME AGE
cluster1-guestbook-app-d0e5 2m41s
On the managed cluster, verify the Application is pulled and deployed:
kubectl -n argocd get app
Expected output:
NAME SYNC STATUS HEALTH STATUS
cluster1-guestbook-app Synced Healthy
Verify the actual application resources are deployed:
kubectl -n guestbook get deploy
Expected output:
NAME READY UP-TO-DATE AVAILABLE AGE
guestbook-ui 1/1 1 1 7m36s
Back on the hub cluster, verify status is synced from the managed cluster:
kubectl -n argocd get app
Expected output:
NAME SYNC STATUS HEALTH STATUS
cluster1-guestbook-app Synced Healthy
Applications not being processed:
- Verify the required labels and annotations are present
- Check that the managed cluster name in annotations matches an actual OCM managed cluster
- Ensure the pull controller is running in the
open-cluster-management
namespace
ManifestWork not created:
- Check controller logs:
kubectl -n open-cluster-management logs deployment/argocd-pull-integration-controller-manager
- Verify OCM is properly installed and managed clusters are registered
Status not syncing back:
- Ensure the Application Status Controller is running
- Check ManifestWork status feedback configuration on managed clusters
kubectl -n open-cluster-management logs deployment/argocd-pull-integration-controller-manager -f
For development setup and contribution guidelines, see the CONTRIBUTING.md document.
make build
make test
make docker-build
- Slack: #open-cluster-mgmt on Kubernetes Slack
- GitHub Discussions: Use GitHub Issues for bug reports and feature requests
- Mailing List: OCM Community
We welcome contributions! Please see our Contributing Guide for details on:
- Code of conduct
- Development process
- Submitting pull requests
- Reporting issues
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.