Configuring Crossplane with Argo CD
This document applies to Crossplane v2.0-preview and not to the latest release v1.19.
Don't use Crossplane v2.0-preview in production.
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 of 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 correctly track Application resources that contain Crossplane related objects it needs to be configured 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. Some checks are supported by the community directly
in Argo’s repository. For example the Provider
from pkg.crossplane.io
has already been declared 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 "ProviderConfig",
24 "ProviderConfigUsage"
25 }
26
27 if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
28 health_status.status = "Healthy"
29 health_status.message = "Resource is up-to-date."
30 return health_status
31 end
32
33 if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
34 if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
35 health_status.status = "Healthy"
36 health_status.message = "Resource is in use."
37 return health_status
38 end
39 return health_status
40 end
41
42 for i, condition in ipairs(obj.status.conditions) do
43 if condition.type == "LastAsyncOperation" then
44 if condition.status == "False" then
45 health_status.status = "Degraded"
46 health_status.message = condition.message
47 return health_status
48 end
49 end
50
51 if condition.type == "Synced" then
52 if condition.status == "False" then
53 health_status.status = "Degraded"
54 health_status.message = condition.message
55 return health_status
56 end
57 end
58
59 if condition.type == "Ready" then
60 if condition.status == "True" then
61 health_status.status = "Healthy"
62 health_status.message = "Resource is up-to-date."
63 return health_status
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 "ProviderConfig",
91 "ProviderConfigUsage"
92 }
93 if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
94 health_status.status = "Healthy"
95 health_status.message = "Resource is up-to-date."
96 return health_status
97 end
98
99 if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
100 if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
101 health_status.status = "Healthy"
102 health_status.message = "Resource is in use."
103 return health_status
104 end
105 return health_status
106 end
107
108 for i, condition in ipairs(obj.status.conditions) do
109 if condition.type == "LastAsyncOperation" then
110 if condition.status == "False" then
111 health_status.status = "Degraded"
112 health_status.message = condition.message
113 return health_status
114 end
115 end
116
117 if condition.type == "Synced" then
118 if condition.status == "False" then
119 health_status.status = "Degraded"
120 health_status.message = condition.message
121 return health_status
122 end
123 end
124
125 if contains({"Ready", "Healthy", "Offered", "Established"}, condition.type) then
126 if condition.status == "True" then
127 health_status.status = "Healthy"
128 health_status.message = "Resource is up-to-date."
129 return health_status
130 end
131 end
132 end
133
134 return health_status
Set Resource Exclusion
Crossplane providers generates a ProviderConfigUsage
for each of the managed resource (MR) it handles. This resource
enable representing the relationship between MR and a ProviderConfig so that the controller can use it as finalizer when a
ProviderConfig is deleted. End users of Crossplane aren’t expected to interact with this resource.
Argo CD UI reactivity can be impacted as the number of resource and types grow. To help keep this number low we
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 will enable the mechanism for all Crossplane Providers.
Increase Kubernetes Client QPS
As the number of CRDs grow on a control plane it will increase 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 a large number of CRDs.
The default value of ARGOCD_K8S_CLIENT_QPS
is 50, modifying the value will also update ARGOCD_K8S_CLIENT_BURST
as it
is default to ARGOCD_K8S_CLIENT_QPS
x 2.