Configuring Crossplane with Argo CD
Argo CD and Crossplane are a great combination. Argo CD provides GitOps while Crossplane turns any Kubernetes cluster into a Universal Control Plane for all your resources. Configuration details are required in order for the two to work together properly. This doc will help you understand these requirements. It is recommended to use Argo CD version 2.4.8 or later with Crossplane.
Argo CD synchronizes Kubernetes resource manifests stored in a Git repository with those running in a Kubernetes cluster (GitOps). Argo CD has different ways to configure how it tracks resources. With Crossplane, you need to configure Argo CD to use Annotation based resource tracking. See the Argo CD docs for additional detail.
Configuring Argo CD with Crossplane
Set resource tracking method
In order for Argo CD to track Application resources that contain Crossplane related objects, configure it to use the annotation mechanism.
To configure it, edit the argocd-cm ConfigMap in the argocd Namespace as such:
Set health status
Argo CD has a built-in health assessment for Kubernetes resources. The community directly supports some checks
in Argo’s repository. For example the Provider
from pkg.crossplane.io already exists which means there no further configuration needed.
Argo CD also enable customising these checks per instance, and that’s the mechanism used to provide support of Provider’s CRDs.
To configure it, edit the argocd-cm ConfigMap in the argocd Namespace.
ProviderConfig may have no status or a status.users field. 1apiVersion: v1
2kind: ConfigMap
3data:
4 application.resourceTrackingMethod: annotation
5 resource.customizations: |
6 "*.upbound.io/*":
7 health.lua: |
8 health_status = {
9 status = "Progressing",
10 message = "Provisioning ..."
11 }
12
13 local function contains (table, val)
14 for i, v in ipairs(table) do
15 if v == val then
16 return true
17 end
18 end
19 return false
20 end
21
22 local has_no_status = {
23 "ClusterProviderConfig",
24 "ProviderConfig",
25 "ProviderConfigUsage"
26 }
27
28 if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
29 health_status.status = "Healthy"
30 health_status.message = "Resource is up-to-date."
31 return health_status
32 end
33
34 if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
35 if (obj.kind == "ProviderConfig" or obj.kind == "ClusterProviderConfig") and obj.status.users ~= nil then
36 health_status.status = "Healthy"
37 health_status.message = "Resource is in use."
38 return health_status
39 end
40 return health_status
41 end
42
43 for i, condition in ipairs(obj.status.conditions) do
44 if condition.type == "LastAsyncOperation" then
45 if condition.status == "False" then
46 health_status.status = "Degraded"
47 health_status.message = condition.message
48 return health_status
49 end
50 end
51
52 if condition.type == "Synced" then
53 if condition.status == "False" then
54 health_status.status = "Degraded"
55 health_status.message = condition.message
56 return health_status
57 end
58 end
59
60 if condition.type == "Ready" then
61 if condition.status == "True" then
62 health_status.status = "Healthy"
63 health_status.message = "Resource is up-to-date."
64 end
65 end
66 end
67
68 return health_status
69
70 "*.crossplane.io/*":
71 health.lua: |
72 health_status = {
73 status = "Progressing",
74 message = "Provisioning ..."
75 }
76
77 local function contains (table, val)
78 for i, v in ipairs(table) do
79 if v == val then
80 return true
81 end
82 end
83 return false
84 end
85
86 local has_no_status = {
87 "Composition",
88 "CompositionRevision",
89 "DeploymentRuntimeConfig",
90 "ClusterProviderConfig",
91 "ProviderConfig",
92 "ProviderConfigUsage"
93 }
94 if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
95 health_status.status = "Healthy"
96 health_status.message = "Resource is up-to-date."
97 return health_status
98 end
99
100 if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
101 if (obj.kind == "ProviderConfig" or obj.kind == "ClusterProviderConfig") and obj.status.users ~= nil then
102 health_status.status = "Healthy"
103 health_status.message = "Resource is in use."
104 return health_status
105 end
106 return health_status
107 end
108
109 for i, condition in ipairs(obj.status.conditions) do
110 if condition.type == "LastAsyncOperation" then
111 if condition.status == "False" then
112 health_status.status = "Degraded"
113 health_status.message = condition.message
114 return health_status
115 end
116 end
117
118 if condition.type == "Synced" then
119 if condition.status == "False" then
120 health_status.status = "Degraded"
121 health_status.message = condition.message
122 return health_status
123 end
124 end
125
126 if contains({"Ready", "Healthy", "Offered", "Established", "ValidPipeline", "RevisionHealthy"}, condition.type) then
127 if condition.status == "True" then
128 health_status.status = "Healthy"
129 health_status.message = "Resource is up-to-date."
130 end
131 end
132 end
133
134 return health_status
Set resource exclusion
Crossplane providers generate a ProviderConfigUsage for each managed resource (MR) they handle. This resource
enables representing the relationship between MR and a ProviderConfig so that the controller can use it as a finalizer when you delete a
ProviderConfig. End users of Crossplane don’t need to interact with this resource.
A growing number of resources and types can impact Argo CD UI reactivity. To help keep this number low, Crossplane
recommend hiding all ProviderConfigUsage resources from Argo CD UI.
To configure resource exclusion edit the argocd-cm ConfigMap in the argocd Namespace as such:
1apiVersion: v1
2kind: ConfigMap
3data:
4 resource.exclusions: |
5 - apiGroups:
6 - "*"
7 kinds:
8 - ProviderConfigUsage
The use of "*" as apiGroups enables the mechanism for all Crossplane Providers.
Increase Kubernetes client QPS
As the number of CRDs grow on a control plane it increases the amount of queries Argo CD Application Controller needs to send to the Kubernetes API. If this is the case you can increase the rate limits of the Argo CD Kubernetes client.
Set the environment variable ARGOCD_K8S_CLIENT_QPS to 300 for improved compatibility with multiple CRDs.
The default value of ARGOCD_K8S_CLIENT_QPS is 50, modifying the value also updates ARGOCD_K8S_CLIENT_BURST as it
is default to ARGOCD_K8S_CLIENT_QPS x 2.