Skip to content

Commit fc64180

Browse files
authored
Grafana Helm Setup Guide (#255)
* Grafana helm setup * pop up for Brand New: Grafana Helm Setup Guide * refactoring to address comments
1 parent dd0ddb9 commit fc64180

File tree

6 files changed

+685
-0
lines changed

6 files changed

+685
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
layout: default
3+
title: Grafana Helm Setup
4+
permalink: /docs/concepts/grafana-helm-setup
5+
---
6+
7+
# Grafana Helm Setup
8+
9+
<details>
10+
<summary><h2>Introduction</h2></summary>
11+
12+
This guide explains how to set up Grafana for monitoring Cadence workflows and services using Helm charts. Helm simplifies the deployment and management of Grafana in Kubernetes environments. Pre-configured dashboards for Cadence are available to visualize metrics effectively.
13+
14+
</details>
15+
16+
<details>
17+
<summary><h2>Prerequisites</h2></summary>
18+
19+
Before proceeding, ensure the following:
20+
21+
- Kubernetes cluster is up and running.
22+
- Helm is installed on your system. Refer to the [Helm installation guide](https://helm.sh/docs/intro/install/).
23+
- Access to the Cadence Helm charts repository.
24+
25+
</details>
26+
27+
<details>
28+
<summary><h2>Setup Steps</h2></summary>
29+
30+
### Step 1: Add Cadence Helm Repository
31+
32+
```bash
33+
helm repo add cadence-workflow https://cadenceworkflow.github.io/cadence-charts
34+
helm repo update
35+
```
36+
37+
### Step 2: Deploy Prometheus Operator
38+
39+
```bash
40+
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
41+
helm install prometheus-operator prometheus-community/kube-prometheus-stack \
42+
--namespace monitoring --create-namespace
43+
```
44+
45+
### Step 3: Deploy Cadence with ServiceMonitor
46+
47+
Create a `values.yaml` file to enable ServiceMonitor for automatic metrics scraping:
48+
49+
```yaml
50+
# Enable metrics collection
51+
metrics:
52+
enabled: true
53+
port: 9090
54+
portName: metrics
55+
56+
serviceMonitor:
57+
enabled: true
58+
# Replace with the namespace where Prometheus is deployed
59+
namespace: "monitoring"
60+
namespaceSelector:
61+
# Ensure this matches Prometheus's namespace
62+
matchNames:
63+
- monitoring
64+
scrapeInterval: 10s
65+
additionalLabels:
66+
# Ensure this matches Prometheus's Helm release name
67+
release: prometheus-operator
68+
annotations: {}
69+
jobLabel: "app.kubernetes.io/name"
70+
targetLabels:
71+
- app.kubernetes.io/name
72+
relabelings: []
73+
metricRelabelings: []
74+
```
75+
76+
Deploy Cadence:
77+
```bash
78+
helm install cadence cadence-workflow/cadence \
79+
--namespace cadence --create-namespace \
80+
--values values.yaml
81+
```
82+
83+
**Note:** Update the `namespace`, `matchNames`, and `release` values to match your Prometheus deployment.
84+
85+
### Step 4: Access Grafana
86+
87+
Get Grafana admin password:
88+
```bash
89+
kubectl get secret --namespace monitoring prometheus-operator-grafana \
90+
-o jsonpath="{.data.admin-password}" | base64 --decode
91+
```
92+
93+
Access Grafana:
94+
```bash
95+
kubectl port-forward --namespace monitoring svc/prometheus-operator-grafana 3000:80
96+
```
97+
98+
Open http://localhost:3000 (admin/password from above)
99+
100+
### Step 5: Import Cadence Dashboards
101+
102+
1. **Download the Cadence Grafana Dashboard JSON:**
103+
```bash
104+
curl https://raw.githubusercontent.com/cadence-workflow/cadence/refs/heads/master/docker/grafana/provisioning/dashboards/cadence-server.json -o cadence-server.json
105+
```
106+
107+
2. **Import in Grafana:** **Dashboards****Import** → Upload JSON files
108+
3. **Select Prometheus** as data source when prompted
109+
4. Try the same steps for other dashboards
110+
111+
</details>
112+
113+
<details>
114+
<summary><h2>Customization</h2></summary>
115+
116+
The Grafana dashboards can be customized by editing the JSON files or modifying panels directly in Grafana. Additionally, Helm values can be overridden during installation to customize Grafana settings.
117+
118+
### Example: Override Helm Values
119+
Create a `values.yaml` file to customize Grafana settings:
120+
```yaml
121+
grafana:
122+
adminPassword: "your-password"
123+
dashboards:
124+
enabled: true
125+
```
126+
127+
Install Grafana with the custom values:
128+
```bash
129+
helm install grafana cadence/grafana -n cadence-monitoring -f values.yaml
130+
```
131+
132+
</details>
133+
134+
<details>
135+
<summary><h2>Additional Information</h2></summary>
136+
137+
- [Cadence Helm Charts Repository](https://github.com/cadence-workflow/cadence-charts)
138+
- [Grafana Documentation](https://grafana.com/docs/)
139+
- [Helm Documentation](https://helm.sh/docs/)
140+
141+
</details>

sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const sidebars: SidebarsConfig = {
6161
{ type: 'doc', id: 'concepts/cross-dc-replication' },
6262
{ type: 'doc', id: 'concepts/search-workflows' },
6363
{ type: 'doc', id: 'concepts/http-api' },
64+
{ type: 'doc', id: 'concepts/grafana-helm-setup' },
6465
],
6566
},
6667
{
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
import NewFeaturePopup from '../NewFeaturePopup';
3+
4+
const GrafanaSetupPopup: React.FC = () => {
5+
const [shouldRender, setShouldRender] = React.useState(false);
6+
7+
// Prevent multiple instances and add debug logging
8+
React.useEffect(() => {
9+
// Check if popup is already being rendered
10+
const existingPopup = document.querySelector('[data-popup-id="grafana_helm_setup_2025_ultra_v2"]');
11+
if (!existingPopup) {
12+
console.log('🚀 GrafanaSetupPopup component mounted - rendering popup');
13+
setShouldRender(true);
14+
} else {
15+
console.log('⚠️ Popup already exists, skipping render');
16+
}
17+
}, []);
18+
19+
if (!shouldRender) {
20+
return null;
21+
}
22+
23+
return (
24+
<div data-popup-id="grafana_helm_setup_2025_ultra_v2">
25+
<NewFeaturePopup
26+
featureId="grafana_helm_setup_2025_ultra_v2"
27+
title="✨ Brand New: Grafana Helm Setup Guide"
28+
description="🎯 Get production-ready monitoring for your Cadence workflows! Our comprehensive guide covers ServiceMonitor setup, automated metrics scraping, and pre-built dashboards. Perfect for Kubernetes deployments."
29+
linkUrl="/docs/concepts/grafana-helm-setup"
30+
linkText="🚀 Explore the Guide"
31+
showDays={365}
32+
/>
33+
</div>
34+
);
35+
};
36+
37+
export default GrafanaSetupPopup;
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import React, { useState, useEffect } from 'react';
2+
import { useHistory } from '@docusaurus/router';
3+
import styles from './styles.module.css';
4+
5+
interface NewFeaturePopupProps {
6+
featureId: string;
7+
title: string;
8+
description: string;
9+
linkUrl: string;
10+
linkText: string;
11+
showDays?: number;
12+
}
13+
14+
const NewFeaturePopup: React.FC<NewFeaturePopupProps> = ({
15+
featureId,
16+
title,
17+
description,
18+
linkUrl,
19+
linkText,
20+
showDays = 7,
21+
}) => {
22+
const [isVisible, setIsVisible] = useState(false);
23+
const [isAnimating, setIsAnimating] = useState(false);
24+
const history = useHistory();
25+
26+
useEffect(() => {
27+
// Check if popup should be shown
28+
const lastShown = localStorage.getItem(`popup_${featureId}_lastShown`);
29+
const dismissed = localStorage.getItem(`popup_${featureId}_dismissed`);
30+
31+
console.log('🚀 Popup check:', { featureId, lastShown, dismissed, showDays });
32+
33+
if (dismissed) {
34+
console.log('✅ Popup dismissed, not showing');
35+
return;
36+
}
37+
38+
const now = new Date().getTime();
39+
40+
if (!lastShown) {
41+
// First time - show popup with delay for better UX
42+
console.log('🎯 First time, showing popup');
43+
setTimeout(() => {
44+
setIsVisible(true);
45+
setTimeout(() => setIsAnimating(true), 100);
46+
}, 2000); // 2 second delay
47+
localStorage.setItem(`popup_${featureId}_lastShown`, now.toString());
48+
} else {
49+
const daysSinceLastShown = (now - parseInt(lastShown)) / (1000 * 60 * 60 * 24);
50+
console.log('📅 Days since last shown:', daysSinceLastShown);
51+
if (daysSinceLastShown < showDays) {
52+
console.log('✨ Within show period, showing popup');
53+
setTimeout(() => {
54+
setIsVisible(true);
55+
setTimeout(() => setIsAnimating(true), 100);
56+
}, 2000);
57+
} else {
58+
console.log('⏰ Outside show period, not showing popup');
59+
}
60+
}
61+
}, [featureId, showDays]);
62+
63+
const handleClose = () => {
64+
setIsAnimating(false);
65+
setTimeout(() => setIsVisible(false), 400);
66+
};
67+
68+
const handleDismiss = () => {
69+
localStorage.setItem(`popup_${featureId}_dismissed`, 'true');
70+
setIsAnimating(false);
71+
setTimeout(() => setIsVisible(false), 400);
72+
};
73+
74+
const handleNavigate = () => {
75+
history.push(linkUrl);
76+
setIsAnimating(false);
77+
setTimeout(() => setIsVisible(false), 400);
78+
};
79+
80+
if (!isVisible) {
81+
return null;
82+
}
83+
84+
return (
85+
<>
86+
<div
87+
className={`${styles.overlay} ${isAnimating ? styles.overlayVisible : styles.overlayHidden}`}
88+
onClick={handleClose}
89+
/>
90+
<div className={`${styles.popup} ${isAnimating ? styles.popupVisible : styles.popupHidden}`}>
91+
{/* Decorative elements */}
92+
<div className={styles.decorativeTop}></div>
93+
<div className={styles.floatingOrbs}>
94+
<div className={styles.orb1}></div>
95+
<div className={styles.orb2}></div>
96+
<div className={styles.orb3}></div>
97+
</div>
98+
99+
{/* Header */}
100+
<div className={styles.header}>
101+
<div className={styles.iconContainer}>
102+
<div className={styles.sparkles}></div>
103+
<div className={styles.iconGlow}></div>
104+
</div>
105+
<button className={styles.closeButton} onClick={handleClose} aria-label="Close popup">
106+
<svg width="18" height="18" viewBox="0 0 18 18" fill="currentColor">
107+
<path d="M9 7.5l3.5-3.5a1 1 0 111.414 1.414L10.414 9l3.5 3.5a1 1 0 11-1.414 1.414L9 10.414l-3.5 3.5a1 1 0 11-1.414-1.414L7.586 9 4.086 5.5A1 1 0 115.5 4.086L9 7.5z"/>
108+
</svg>
109+
</button>
110+
</div>
111+
112+
{/* Content */}
113+
<div className={styles.content}>
114+
{/* Premium badge */}
115+
<div className={styles.badge}>
116+
<div className={styles.badgeInner}>
117+
<span className={styles.badgeText}>NEW FEATURE</span>
118+
<div className={styles.badgeShine}></div>
119+
</div>
120+
<div className={styles.badgePulse}></div>
121+
</div>
122+
123+
{/* Title */}
124+
<h3 className={styles.title}>{title}</h3>
125+
126+
{/* Description */}
127+
<p className={styles.description}>{description}</p>
128+
129+
{/* Feature highlights */}
130+
<div className={styles.features}>
131+
<div className={styles.feature}>
132+
<div className={styles.featureIcon}></div>
133+
<span>Quick Setup</span>
134+
</div>
135+
<div className={styles.feature}>
136+
<div className={styles.featureIcon}>📊</div>
137+
<span>Pre-built Dashboards</span>
138+
</div>
139+
<div className={styles.feature}>
140+
<div className={styles.featureIcon}>🔄</div>
141+
<span>Auto ServiceMonitor</span>
142+
</div>
143+
</div>
144+
145+
{/* Actions */}
146+
<div className={styles.actions}>
147+
<button className={styles.primaryButton} onClick={handleNavigate}>
148+
<span className={styles.buttonText}>{linkText}</span>
149+
<div className={styles.buttonShine}></div>
150+
<svg className={styles.buttonIcon} width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
151+
<path d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>
152+
<path d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>
153+
</svg>
154+
</button>
155+
<button className={styles.secondaryButton} onClick={handleDismiss}>
156+
<span>Maybe later</span>
157+
</button>
158+
</div>
159+
</div>
160+
161+
{/* Bottom gradient border */}
162+
<div className={styles.gradientBorder}></div>
163+
</div>
164+
</>
165+
);
166+
};
167+
168+
export default NewFeaturePopup;

0 commit comments

Comments
 (0)