Skip to content

Commit 077fbc3

Browse files
committed
add user content for managed-by-url annotation
Signed-off-by: Atif Ali <[email protected]>
1 parent f5eaae7 commit 077fbc3

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# Managed By URL Annotation
2+
3+
## Overview
4+
5+
The `argocd.argoproj.io/managed-by-url` annotation allows an Application resource to specify which Argo CD instance manages it. This is useful when you have multiple Argo CD instances and need application links in the UI to point to the correct managing instance.
6+
7+
## Use Case
8+
9+
When using multiple Argo CD instances with the [app-of-apps pattern](cluster-bootstrapping.md):
10+
11+
1. A primary Argo CD instance creates a parent Application
12+
2. That parent Application deploys child Applications managed by a secondary Argo CD instance
13+
3. Without the annotation, clicking on child Applications in the primary instance's UI tries to open them in the primary instance (incorrect)
14+
4. The child Applications should open in the secondary instance instead
15+
16+
The `managed-by-url` annotation ensures application links redirect to the correct Argo CD instance.
17+
18+
> [!NOTE]
19+
> This annotation is particularly useful in multi-tenant setups where different teams have their own Argo CD instances, or in hub-and-spoke architectures where a central instance manages multiple edge instances.
20+
21+
## Example
22+
23+
This example demonstrates the [app-of-apps pattern](cluster-bootstrapping.md) where a parent Application deploys child Applications from a Git repository.
24+
25+
### Step 1: Create Parent Application
26+
27+
Create a parent Application in your primary Argo CD instance:
28+
29+
```yaml
30+
apiVersion: argoproj.io/v1alpha1
31+
kind: Application
32+
metadata:
33+
name: parent-app
34+
namespace: argocd
35+
spec:
36+
project: default
37+
source:
38+
repoURL: https://github.com/YOUR-ORG/my-apps-repo.git
39+
targetRevision: main
40+
path: path-to-child-app
41+
destination:
42+
server: https://kubernetes.default.svc
43+
namespace: namespace-b
44+
syncPolicy:
45+
automated:
46+
selfHeal: true
47+
prune: true
48+
```
49+
50+
### Step 2: Create Child Application in Git Repository
51+
52+
In your Git repository at `apps/child-apps/child-app.yaml`, add the `managed-by-url` annotation:
53+
54+
```yaml
55+
apiVersion: argoproj.io/v1alpha1
56+
kind: Application
57+
metadata:
58+
name: child-app
59+
namespace: namespace-b
60+
annotations:
61+
argocd.argoproj.io/managed-by-url: "http://localhost:8081" # replace with actual secondary ArgoCD URL in real setup
62+
spec:
63+
project: default
64+
source:
65+
repoURL: https://github.com/YOUR-ORG/my-apps-repo.git
66+
targetRevision: HEAD
67+
path: path-to-child-app
68+
destination:
69+
server: https://kubernetes.default.svc
70+
namespace: namespace-b
71+
syncPolicy:
72+
automated:
73+
selfHeal: true
74+
prune: true
75+
```
76+
77+
### Result
78+
79+
When viewing the parent Application in the primary instance's UI:
80+
- The parent Application syncs from Git and deploys the child Application
81+
- Clicking on `child-app` in the resource tree navigates to `https://secondary-argocd.example.com/applications/namespace-b/child-app`
82+
- The link opens the child Application in the correct Argo CD instance that actually manages it
83+
84+
## Configuration
85+
86+
### Annotation Format
87+
88+
| Field | Value |
89+
|-------|-------|
90+
| **Annotation** | `argocd.argoproj.io/managed-by-url` |
91+
| **Target** | Application |
92+
| **Value** | Valid HTTP(S) URL |
93+
| **Required** | No |
94+
95+
### URL Validation
96+
97+
The annotation value **must** be a valid HTTP(S) URL:
98+
99+
- ✅ `https://argocd.example.com`
100+
- ✅ `https://argocd.example.com:8080`
101+
- ✅ `http://localhost:8080` (for development)
102+
- ❌ `argocd.example.com` (missing protocol)
103+
- ❌ `javascript:alert(1)` (invalid protocol)
104+
105+
Invalid URLs will prevent the Application from being created or updated.
106+
107+
### Behavior
108+
109+
When generating application links, Argo CD:
110+
- **Without annotation**: Uses the current instance's base URL
111+
- **With annotation**: Uses the URL from the annotation
112+
- **Invalid annotation**: Falls back to the current instance's base URL and logs a warning
113+
114+
> [!WARNING]
115+
> Ensure the URL in the annotation is accessible from users' browsers. For internal deployments, use internal DNS names or configure appropriate network access.
116+
117+
## Testing Locally
118+
119+
To test the annotation with two local Argo CD instances:
120+
121+
```bash
122+
# Install primary instance
123+
kubectl create namespace argocd
124+
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
125+
126+
# Install secondary instance
127+
kubectl create namespace namespace-b
128+
kubectl apply -n namespace-b -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
129+
130+
# Port forward both instances
131+
kubectl port-forward -n argocd svc/argocd-server 8080:443 &
132+
kubectl port-forward -n namespace-b svc/argocd-server 8081:443 &
133+
134+
# Wait for Argo CD to be ready
135+
kubectl wait --for=condition=available --timeout=300s deployment/argocd-server -n argocd
136+
137+
# Get the admin password for primary instance
138+
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
139+
140+
```
141+
142+
Then:
143+
1. Open `http://localhost:8080` in your browser
144+
2. Login with username `admin` and the password from the command above
145+
3. Navigate to the `parent-app` Application
146+
4. Click on the `child-app` in the resource tree
147+
5. It should redirect to `http://localhost:8081/applications/namespace-b/child-app`
148+
149+
You will need to repeat the command to get the password for secondary instance to login and access the child-app
150+
151+
```bash
152+
# Get the admin password for secondary instance
153+
kubectl -n namespace-b get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
154+
```
155+
156+
## Troubleshooting
157+
158+
### Links Still Point to Wrong Instance
159+
160+
**Check if the annotation is present:**
161+
162+
```bash
163+
kubectl get application child-app -n instance-b -o jsonpath='{.metadata.annotations.argocd\.argoproj\.io/managed-by-url}'
164+
```
165+
166+
Expected output: A complete URL like `http://localhost:8081` or the url that has been set
167+
i.e `https://secondary-argocd.example.com`
168+
169+
**If the annotation is present but links still don't work:**
170+
- Verify the URL is accessible from your browser
171+
- Check browser console for errors
172+
- Ensure the URL format is correct (includes `http://` or `https://`)
173+
174+
### Application Creation Fails
175+
176+
If Application creation fails with "invalid managed-by URL" error:
177+
178+
- ✅ URL includes protocol (`https://` or `http://`)
179+
- ✅ URL contains no typos
180+
- ✅ URL uses only valid characters
181+
- ✅ URL is not a potentially malicious scheme (e.g., `javascript:`)
182+
183+
### Nested Applications Not Working
184+
185+
For app-of-apps patterns, ensure:
186+
1. The child Application YAML in Git includes the annotation
187+
2. The parent Application has synced successfully
188+
3. The child Application has been created in the cluster
189+
190+
Verify the child Application exists:
191+
192+
```bash
193+
kubectl get application CHILD-APP-NAME -n NAMESPACE
194+
```
195+
196+
## See Also
197+
198+
- [Application Annotations](../user-guide/annotations-and-labels.md)
199+
- [App of Apps Pattern](cluster-bootstrapping.md)
200+
- [Deep Links](deep_links.md)

docs/user-guide/annotations-and-labels.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| argocd.argoproj.io/hook | any | [see resource hooks docs](resource_hooks.md) | Used to configure [resource hooks](resource_hooks.md). |
1010
| argocd.argoproj.io/hook-delete-policy | any | [see resource hooks docs](resource_hooks.md#hook-deletion-policies) | Used to set a [resource hook's deletion policy](resource_hooks.md#hook-deletion-policies). |
1111
| argocd.argoproj.io/manifest-generate-paths | Application | [see scaling docs](../operator-manual/high_availability.md#webhook-and-manifest-paths-annotation) | Used to avoid unnecessary Application refreshes, especially in mono-repos. |
12+
| argocd.argoproj.io/managed-by-url | Application | A valid http(s) URL | Specifies the URL of the Argo CD instance managing the application. Used to correctly link to applications managed by a different Argo CD instance. See [managed-by-url docs](../operator-manual/managed-by-url.md) for details. |
1213
| argocd.argoproj.io/refresh | Application | `normal`, `hard` | Indicates that app needs to be refreshed. Removed by application controller after app is refreshed. Value `"hard"` means manifest cache and target cluster state cache should be invalidated before refresh. |
1314
| argocd.argoproj.io/skip-reconcile | Application | `"true"` | Indicates to the Argo CD application controller that the Application should not be reconciled. See the [skip reconcile documentation](skip_reconcile.md) for use cases. |
1415
| argocd.argoproj.io/sync-options | any | [see sync options docs](sync-options.md) | Provides a variety of settings to determine how an Application's resources are synced. |

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ nav:
6363
- operator-manual/web_based_terminal.md
6464
- operator-manual/config-management-plugins.md
6565
- operator-manual/deep_links.md
66+
- operator-manual/managed-by-url.md
6667
- Notifications:
6768
- Overview: operator-manual/notifications/index.md
6869
- operator-manual/notifications/triggers.md

0 commit comments

Comments
 (0)