Kubernetes-Monitoring und -Alarmierung - Deployment- und Pod-Status - Telegram-Alarmierung
Fortgeschritten
Dies ist ein Automatisierungsworkflow mit 14 Nodes. Hauptsächlich werden If, Code, Telegram, ExecuteCommand, ScheduleTrigger und andere Nodes verwendet. Kubernetes-Bereitstellung und Pod-Überwachung mit Telegram-Alarmen
Voraussetzungen
- •Telegram Bot Token
Verwendete Nodes (14)
Kategorie
-
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
"id": "cM2tIagg9TD8Jc0l",
"meta": {
"instanceId": "5c7ce220523e8664f49208a8be668a8dc6fab5f747ce4de865fa1309727919f1"
},
"name": "Kubernetes Monitoring & Alert - Deplyoment & Pods Status - Telegram Alert",
"tags": [],
"nodes": [
{
"id": "f0b0f7f0-b5e1-4bfd-85a0-6c0f90336a6e",
"name": "Zeitplan-Auslöser",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-480,
208
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes"
}
]
}
},
"typeVersion": 1
},
{
"id": "976ee100-553e-4b40-8b9f-09a3afd980a9",
"name": "Kubeconfig-Einrichtung",
"type": "n8n-nodes-base.code",
"position": [
-224,
208
],
"parameters": {
"jsCode": "// PASTE YOUR KUBECONFIG CONTENT HERE\nconst kubeconfigContent = `\napiVersion: v1\nkind: Config\nclusters:\n- cluster:\n certificate-authority-data: YOUR_CA_DATA\n server: https://your-k8s-api-server:6443\n name: your-cluster\ncontexts:\n- context:\n cluster: your-cluster\n user: your-user\n name: your-context\ncurrent-context: your-context\nusers:\n- name: your-user\n user:\n token: YOUR_TOKEN\n`;\n\n// Configuration\nconst namespace = 'production';\n\nreturn [{\n json: {\n kubeconfig: kubeconfigContent,\n namespace: namespace\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b95b994d-00b2-4bb7-9d4b-9f417f8bd1e1",
"name": "Pods abrufen",
"type": "n8n-nodes-base.executeCommand",
"position": [
0,
0
],
"parameters": {
"command": "=apk add curl\nKUBECONFIG_PATH=\"/tmp/kubeconfig-$RANDOM.yaml\"\necho '{{$json.kubeconfig}}' > $KUBECONFIG_PATH\ncurl -LO https://dl.k8s.io/release/v1.34.0/bin/linux/amd64/kubectl\nchmod +x ./kubectl\n./kubectl --kubeconfig=$KUBECONFIG_PATH get pods -n {{$json.namespace}} -o json\nrm -f $KUBECONFIG_PATH"
},
"typeVersion": 1
},
{
"id": "0b5b3388-2de0-479e-a9d3-a1b136b0cf56",
"name": "Bereitstellungen abrufen",
"type": "n8n-nodes-base.executeCommand",
"position": [
-16,
432
],
"parameters": {
"command": "=apk add curl\nKUBECONFIG_PATH=\"/tmp/kubeconfig-$RANDOM.yaml\"\necho '{{$json.kubeconfig}}' > $KUBECONFIG_PATH\ncurl -LO https://dl.k8s.io/release/v1.34.0/bin/linux/amd64/kubectl\nchmod +x ./kubectl\n./kubectl --kubeconfig=$KUBECONFIG_PATH get deployments -n {{$json.namespace}} -o json\nrm -f $KUBECONFIG_PATH"
},
"typeVersion": 1
},
{
"id": "f0a55a90-5bcf-42dc-96b0-3a21bd83c12e",
"name": "Bericht verarbeiten und generieren",
"type": "n8n-nodes-base.code",
"position": [
208,
224
],
"parameters": {
"jsCode": "// Debug: Check inputs\nconst inputs = $input.all();\n\n// Try to identify which input is which\nlet podsData, deploymentsData;\n\nfor (let i = 0; i < inputs.length; i++) {\n try {\n const input = inputs[i];\n \n if (!input.json?.stdout) continue;\n \n const data = JSON.parse(input.json.stdout);\n \n if (data.items && data.items.length > 0) {\n const firstKind = data.items[0].kind;\n \n if (firstKind === 'Pod') {\n podsData = data;\n } else if (firstKind === 'Deployment') {\n deploymentsData = data;\n }\n }\n } catch (e) {\n console.log(`Error parsing input ${i}:`, e.message);\n }\n}\n\nconst pods = podsData?.items || [];\nconst deployments = deploymentsData?.items || [];\nconst namespace = podsData?.items?.[0]?.metadata?.namespace || deploymentsData?.items?.[0]?.metadata?.namespace || 'N/A';\n\nconst deploymentStatus = {};\nconst otherWorkloads = {};\nconst standalonePods = [];\nconst alerts = [];\n\n// Process deployments from deployment objects\ndeployments.forEach(deployment => {\n const name = deployment.metadata.name;\n const ns = deployment.metadata.namespace;\n const replicas = deployment.spec.replicas || 0;\n const readyReplicas = deployment.status.readyReplicas || 0;\n const availableReplicas = deployment.status.availableReplicas || 0;\n \n deploymentStatus[name] = {\n name: name,\n namespace: ns,\n replicas: replicas,\n readyReplicas: readyReplicas,\n availableReplicas: availableReplicas,\n pods: []\n };\n \n if (readyReplicas < 1) {\n alerts.push({\n workload: name,\n kind: 'Deployment',\n issue: `No ready pods available! (Ready: ${readyReplicas}/${replicas})`\n });\n }\n});\n\n// Process pods - group by owner\npods.forEach(pod => {\n const podName = pod.metadata.name;\n const phase = pod.status.phase;\n const nodeName = pod.spec.nodeName || 'N/A';\n const conditions = pod.status.conditions || [];\n const readyCondition = conditions.find(c => c.type === 'Ready');\n const isReady = readyCondition?.status === 'True';\n const restartCount = pod.status.containerStatuses?.reduce((sum, c) => sum + c.restartCount, 0) || 0;\n \n const podInfo = {\n name: podName,\n phase: phase,\n ready: isReady,\n node: nodeName,\n restarts: restartCount\n };\n \n // Find owner from ownerReferences\n const ownerRefs = pod.metadata.ownerReferences || [];\n let ownerName = null;\n let ownerKind = null;\n \n for (const owner of ownerRefs) {\n if (owner.kind === 'ReplicaSet') {\n // Extract deployment name from ReplicaSet name\n const parts = owner.name.split('-');\n if (parts.length > 1) {\n parts.pop();\n ownerName = parts.join('-');\n ownerKind = 'Deployment';\n }\n break;\n } else if (['DaemonSet', 'StatefulSet', 'Node'].includes(owner.kind)) {\n ownerName = owner.name;\n ownerKind = owner.kind;\n break;\n }\n }\n \n // Add pod to appropriate owner\n if (ownerKind === 'Deployment') {\n // If deployment exists in deploymentStatus, add there\n if (deploymentStatus[ownerName]) {\n deploymentStatus[ownerName].pods.push(podInfo);\n } else {\n // Otherwise create a deployment entry (discovered from pods)\n if (!deploymentStatus[ownerName]) {\n const readyCount = 0; // Will be calculated later\n deploymentStatus[ownerName] = {\n name: ownerName,\n namespace: namespace,\n replicas: 0,\n readyReplicas: 0,\n availableReplicas: 0,\n pods: [],\n discoveredFromPods: true\n };\n }\n deploymentStatus[ownerName].pods.push(podInfo);\n }\n } else if (ownerName) {\n // Group by other owner types\n const key = `${ownerKind}/${ownerName}`;\n if (!otherWorkloads[key]) {\n otherWorkloads[key] = {\n kind: ownerKind,\n name: ownerName,\n pods: []\n };\n }\n otherWorkloads[key].pods.push(podInfo);\n } else {\n standalonePods.push(podInfo);\n }\n});\n\n// Calculate stats for deployments discovered from pods\nObject.values(deploymentStatus).forEach(dep => {\n if (dep.discoveredFromPods) {\n const totalPods = dep.pods.length;\n const readyPods = dep.pods.filter(p => p.ready).length;\n dep.replicas = totalPods;\n dep.readyReplicas = readyPods;\n dep.availableReplicas = readyPods;\n \n if (readyPods < 1) {\n alerts.push({\n workload: dep.name,\n kind: 'Deployment',\n issue: `No ready pods available! (Ready: ${readyPods}/${totalPods})`\n });\n }\n }\n});\n\n// Check for alerts in non-deployment workloads\nObject.values(otherWorkloads).forEach(owner => {\n const readyCount = owner.pods.filter(p => p.ready).length;\n if (readyCount < 1) {\n alerts.push({\n workload: owner.name,\n kind: owner.kind,\n issue: `No ready pods available! (Ready: ${readyCount}/${owner.pods.length})`\n });\n }\n});\n\n// Generate report\nlet markdown = `# Kubernetes Cluster Status Report\\n\\n`;\nmarkdown += `**Namespace:** ${namespace}\\n`;\nmarkdown += `**Timestamp:** ${new Date().toISOString()}\\n\\n`;\n\nconst deploymentCount = Object.keys(deploymentStatus).length;\nconst otherWorkloadCount = Object.keys(otherWorkloads).length;\nmarkdown += `**Total:** ${deploymentCount} deployments, ${otherWorkloadCount} other workloads, ${pods.length} pods\\n\\n`;\n\n// Deployments section\nif (deploymentCount > 0) {\n markdown += `## Deployments\\n\\n`;\n Object.values(deploymentStatus).forEach(dep => {\n const status = dep.readyReplicas >= 1 ? '✅' : '❌';\n markdown += `### ${status} ${dep.name}\\n`;\n markdown += `- **Replicas:** ${dep.readyReplicas}/${dep.replicas}\\n`;\n markdown += `- **Available:** ${dep.availableReplicas}\\n`;\n markdown += `- **Pods:**\\n`;\n \n if (dep.pods.length === 0) {\n markdown += ` - *No pods*\\n`;\n } else {\n dep.pods.forEach(pod => {\n const podStatus = pod.ready ? '✅' : '❌';\n markdown += ` - ${podStatus} ${pod.name} (${pod.phase}) - Node: ${pod.node}, Restarts: ${pod.restarts}\\n`;\n });\n }\n markdown += `\\n`;\n });\n}\n\n// Other workloads section (DaemonSets, StatefulSets, Static Pods)\nif (otherWorkloadCount > 0) {\n markdown += `## Other Workloads (DaemonSets, StatefulSets, Static Pods)\\n\\n`;\n Object.values(otherWorkloads).forEach(owner => {\n const readyCount = owner.pods.filter(p => p.ready).length;\n const totalCount = owner.pods.length;\n const status = readyCount >= 1 ? '✅' : '❌';\n \n markdown += `### ${status} ${owner.name} (${owner.kind})\\n`;\n markdown += `- **Ready:** ${readyCount}/${totalCount}\\n`;\n markdown += `- **Pods:**\\n`;\n \n owner.pods.forEach(pod => {\n const podStatus = pod.ready ? '✅' : '❌';\n markdown += ` - ${podStatus} ${pod.name} (${pod.phase}) - Node: ${pod.node}, Restarts: ${pod.restarts}\\n`;\n });\n markdown += `\\n`;\n });\n}\n\n// Standalone pods\nif (standalonePods.length > 0) {\n markdown += `## Standalone Pods\\n\\n`;\n standalonePods.forEach(pod => {\n const podStatus = pod.ready ? '✅' : '❌';\n markdown += `- ${podStatus} ${pod.name} (${pod.phase}) - Node: ${pod.node}, Restarts: ${pod.restarts}\\n`;\n });\n markdown += `\\n`;\n}\n\n// Alerts section\nif (alerts.length > 0) {\n markdown += `## ⚠️ Alerts\\n\\n`;\n alerts.forEach(alert => {\n markdown += `- **${alert.workload}** (${alert.kind}): ${alert.issue}\\n`;\n });\n}\n\n// Convert markdown to binary data\nconst buffer = Buffer.from(markdown, 'utf-8');\nconst binaryData = {\n data: buffer.toString('base64'),\n mimeType: 'text/markdown',\n fileName: 'report.md'\n};\n\nreturn [{\n json: {\n markdown: markdown,\n hasAlerts: alerts.length > 0,\n alerts: alerts,\n deploymentCount: deploymentCount,\n podCount: pods.length,\n namespace: namespace\n },\n binary: {\n data: binaryData\n }\n}];"
},
"typeVersion": 2
},
{
"id": "22af800d-d130-4d13-9e6b-6a9176b886b9",
"name": "Alarme vorhanden?",
"type": "n8n-nodes-base.if",
"position": [
432,
224
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.hasAlerts}}",
"value2": true
}
]
}
},
"typeVersion": 1
},
{
"id": "deb746c1-42b4-4e12-8530-d0340cf52e90",
"name": "Telegram-Alarm senden",
"type": "n8n-nodes-base.telegram",
"position": [
704,
16
],
"webhookId": "ad590700-edca-4911-84c0-bbfd3f1971a0",
"parameters": {
"text": "=🚨 *Kubernetes Alert*\\n\\n*Namespace:* {{$json.namespace}}\\n\\n{{$json.alerts.map(a => `⚠️ *${a.deployment}*: ${a.issue}`).join('\\n')}}\\n\\n---\\n\\n{{$json.markdown}}",
"chatId": "YOUR_TELEGRAM_CHAT_ID",
"additionalFields": {
"parse_mode": "Markdown"
}
},
"credentials": {
"telegramApi": {
"id": "FUXl519hpM0FsK8j",
"name": "Telegram account"
}
},
"typeVersion": 1
},
{
"id": "c8cf22c0-7954-4a5c-84fc-3513ece1e376",
"name": "Bericht speichern",
"type": "n8n-nodes-base.writeBinaryFile",
"position": [
704,
480
],
"parameters": {
"options": {},
"fileName": "=k8s-report-{{$now.format('YYYY-MM-DD-HHmmss')}}.md",
"dataPropertyName": "=data"
},
"typeVersion": 1
},
{
"id": "277ca9f2-b6bf-4c87-8d56-1734c0fecae0",
"name": "Haftnotiz",
"type": "n8n-nodes-base.stickyNote",
"position": [
-752,
0
],
"parameters": {
"width": 360,
"height": 180,
"content": "## Kubernetes Monitoring Workflow\n\nAutomatically monitors your K8s cluster and sends Telegram alerts when workloads have zero ready pods.\n\nReports are saved as markdown files for every execution."
},
"typeVersion": 1
},
{
"id": "da5b3125-2dfd-4ee5-9732-27404ef98455",
"name": "Haftnotiz1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
352
],
"parameters": {
"width": 300,
"height": 240,
"content": "## CONFIGURATION REQUIRED\n\n1. Paste your kubeconfig content\n2. Set target namespace (default: 'production')\n\nThe workflow will automatically download kubectl during execution."
},
"typeVersion": 1
},
{
"id": "848a775e-d3c7-4c5b-8b1b-6ad4200b9687",
"name": "Haftnotiz2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-96,
-208
],
"parameters": {
"width": 280,
"height": 188,
"content": "## Data Collection\n\nBoth nodes run in parallel to fetch:\n- All pods\n- All deployments\n\nfrom the specified namespace"
},
"typeVersion": 1
},
{
"id": "5e94eb86-fb7a-4cde-a2b5-3778f057c316",
"name": "Haftnotiz3",
"type": "n8n-nodes-base.stickyNote",
"position": [
192,
384
],
"parameters": {
"width": 280,
"content": "## Processing & Alert Detection\n\nGroups pods by owner (Deployment, DaemonSet, StatefulSet, Node)\n\nDetects alerts: workloads with 0 ready pods\n\nGenerates comprehensive markdown report"
},
"typeVersion": 1
},
{
"id": "83b169f1-7bf5-497d-bdb8-9b999baaa980",
"name": "Haftnotiz4",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
-224
],
"parameters": {
"width": 464,
"height": 216,
"content": "## TELEGRAM CONFIGURATION\n\n1. Create bot via @BotFather\n2. Get bot token & add as credential\n3. Replace YOUR_TELEGRAM_CHAT_ID with your actual chat ID\n\nFind chat ID: message your bot, then visit:\nhttps://api.telegram.org/bot<TOKEN>/getUpdates"
},
"typeVersion": 1
},
{
"id": "00a9cb9f-6e0b-4537-adee-b2b6cef02f86",
"name": "Haftnotiz5",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
624
],
"parameters": {
"width": 280,
"height": 220,
"content": "## Report Output\n\nSaves markdown report with timestamp:\nk8s-report-YYYY-MM-DD-HHmmss.md\n\nExecutes on every run regardless of alert status"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "0f3068a8-25a9-42af-b277-7deb8c6844f1",
"connections": {
"b95b994d-00b2-4bb7-9d4b-9f417f8bd1e1": {
"main": [
[
{
"node": "f0a55a90-5bcf-42dc-96b0-3a21bd83c12e",
"type": "main",
"index": 0
}
]
]
},
"22af800d-d130-4d13-9e6b-6a9176b886b9": {
"main": [
[
{
"node": "deb746c1-42b4-4e12-8530-d0340cf52e90",
"type": "main",
"index": 0
}
],
[
{
"node": "c8cf22c0-7954-4a5c-84fc-3513ece1e376",
"type": "main",
"index": 0
}
]
]
},
"0b5b3388-2de0-479e-a9d3-a1b136b0cf56": {
"main": [
[
{
"node": "f0a55a90-5bcf-42dc-96b0-3a21bd83c12e",
"type": "main",
"index": 0
}
]
]
},
"976ee100-553e-4b40-8b9f-09a3afd980a9": {
"main": [
[
{
"node": "b95b994d-00b2-4bb7-9d4b-9f417f8bd1e1",
"type": "main",
"index": 0
},
{
"node": "0b5b3388-2de0-479e-a9d3-a1b136b0cf56",
"type": "main",
"index": 0
}
]
]
},
"f0b0f7f0-b5e1-4bfd-85a0-6c0f90336a6e": {
"main": [
[
{
"node": "976ee100-553e-4b40-8b9f-09a3afd980a9",
"type": "main",
"index": 0
}
]
]
},
"deb746c1-42b4-4e12-8530-d0340cf52e90": {
"main": [
[
{
"node": "c8cf22c0-7954-4a5c-84fc-3513ece1e376",
"type": "main",
"index": 0
}
]
]
},
"f0a55a90-5bcf-42dc-96b0-3a21bd83c12e": {
"main": [
[
{
"node": "22af800d-d130-4d13-9e6b-6a9176b886b9",
"type": "main",
"index": 0
}
]
]
}
}
}Häufig gestellte Fragen
Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Fortgeschritten
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Telegramm-KI-Kanal-Bot - TGPT-Generator mit Unterstützung für Text- und Bildantworten
Generieren von Text- und Bildantworten in einem Telegram-Kanal mit GPT-4 und TGPT
If
Set
Code
+
If
Set
Code
22 NodesVigh Sandor
Automatisierte Kubernetes-Tests mit Robot Framework, ArgoCD und vollem KinD-Lebenszyklus
Automatisierte Kubernetes-Tests auf Basis von Robot Framework, ArgoCD und einem vollständigen KinD-Lebenszyklus
If
Set
Gitlab
+
If
Set
Gitlab
73 NodesVigh Sandor
DevOps
Automatisiertes Rsync-Backup mit Passwortauthentifizierung und Alarmsystem
Automatisierte Rsync-Sicherung für Passwortauthentifizierung und Warnsysteme
If
Set
Manual Trigger
+
If
Set
Manual Trigger
21 NodesVigh Sandor
KI-gesteuerte Videowerkzeugung und Upload zu Instagram, TikTok und YouTube
AI-gestützte Videoerstellung aus Google Drive und hochladen zu Instagram, TikTok und YouTube
If
Set
Code
+
If
Set
Code
53 NodesDevCode Journey
Content-Erstellung
Tägliches Sport-Update
Konvertieren Sie RSS-Feeds mit Google Gemini, Kokoro TTS und FFmpeg in Podcasts
If
Set
Code
+
If
Set
Code
34 NodesJonas
Content-Erstellung
Mit RSS-Feed und ElevenLabs-Sprachfunktion ausgestatteter KI-Podcast-Generator
KI-Podcast-Generator: Integriert RSS-Feeds und ElevenLabs-Sprachfunktionen
If
Code
Gmail
+
If
Code
Gmail
11 NodesDavid Olusola
Künstliche Intelligenz
Workflow-Informationen
Schwierigkeitsgrad
Fortgeschritten
Anzahl der Nodes14
Kategorie-
Node-Typen7
Autor
Vigh Sandor
@vighsandorExterne Links
Auf n8n.io ansehen →
Diesen Workflow teilen