{"id":5197,"date":"2026-09-14T12:26:25","date_gmt":"2026-09-14T09:26:25","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/?p=5197"},"modified":"2026-09-14T06:17:29","modified_gmt":"2026-09-14T03:17:29","slug":"how-to-set-up-kubernetes-monitoring","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/how-to-set-up-kubernetes-monitoring\/","title":{"rendered":"How to Set Up Kubernetes Monitoring"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><div id=\"toc_container\" role=\"navigation\" aria-label=\"Table of Contents\" data-nosnippet class=\"toc_transparent no_bullets toc_numbered toc_title_center\"><p class=\"toc_title\">\u0130\u00e7indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Where_should_Kubernetes_monitoring_begin\"><span class=\"toc_number toc_depth_1\">1.<\/span> Where should Kubernetes monitoring begin?<\/a><\/li><li><a href=\"#What_each_component_actually_does\"><span class=\"toc_number toc_depth_1\">2.<\/span> What each component actually does<\/a><\/li><li><a href=\"#Check_the_cluster_before_installing_anything\"><span class=\"toc_number toc_depth_1\">3.<\/span> Check the cluster before installing anything<\/a><\/li><li><a href=\"#Installing_kube-prometheus-stack_with_Helm\"><span class=\"toc_number toc_depth_1\">4.<\/span> Installing kube-prometheus-stack with Helm<\/a><ul><li><a href=\"#A_starting_values_file\"><span class=\"toc_number toc_depth_2\">4.1.<\/span> A starting values file<\/a><\/li><\/ul><\/li><li><a href=\"#Verify_the_installation_instead_of_trusting_Helm\"><span class=\"toc_number toc_depth_1\">5.<\/span> Verify the installation instead of trusting Helm<\/a><\/li><li><a href=\"#Expose_application_metrics_not_only_cluster_metrics\"><span class=\"toc_number toc_depth_1\">6.<\/span> Expose application metrics, not only cluster metrics<\/a><\/li><li><a href=\"#Alert_rules_should_lead_to_an_action\"><span class=\"toc_number toc_depth_1\">7.<\/span> Alert rules should lead to an action<\/a><\/li><li><a href=\"#Prometheus_has_a_cardinality_problem_to_manage\"><span class=\"toc_number toc_depth_1\">8.<\/span> Prometheus has a cardinality problem to manage<\/a><\/li><li><a href=\"#What_a_DDoS_night_taught_me_about_useful_signals\"><span class=\"toc_number toc_depth_1\">9.<\/span> What a DDoS night taught me about useful signals<\/a><\/li><li><a href=\"#Security_access_and_retention\"><span class=\"toc_number toc_depth_1\">10.<\/span> Security, access, and retention<\/a><\/li><li><a href=\"#Operating_the_stack_after_installation\"><span class=\"toc_number toc_depth_1\">11.<\/span> Operating the stack after installation<\/a><\/li><li><a href=\"#Frequently_asked_questions\"><span class=\"toc_number toc_depth_1\">12.<\/span> Frequently asked questions<\/a><ul><li><a href=\"#What_is_the_difference_between_Prometheus_and_Metrics_Server\"><span class=\"toc_number toc_depth_2\">12.1.<\/span> What is the difference between Prometheus and Metrics Server?<\/a><\/li><li><a href=\"#Is_Grafana_required_for_Kubernetes_monitoring\"><span class=\"toc_number toc_depth_2\">12.2.<\/span> Is Grafana required for Kubernetes monitoring?<\/a><\/li><li><a href=\"#How_long_should_Prometheus_data_be_retained\"><span class=\"toc_number toc_depth_2\">12.3.<\/span> How long should Prometheus data be retained?<\/a><\/li><li><a href=\"#How_can_I_reduce_the_number_of_alerts\"><span class=\"toc_number toc_depth_2\">12.4.<\/span> How can I reduce the number of alerts?<\/a><\/li><\/ul><\/li><\/ul><\/div>\n<h2><span id=\"Where_should_Kubernetes_monitoring_begin\">Where should Kubernetes monitoring begin?<\/span><\/h2>\n<p>I have seen plenty of Kubernetes clusters where every pod was reported as <code>Running<\/code> while customers were already receiving errors. The scheduler was happy. The application was not. CPU throttling, memory pressure, rising HTTP errors, and a nearly full filesystem can all hide behind a green-looking pod list.<\/p>\n<p>If you discover those symptoms only after a user opens a ticket, you are investigating an incident rather than monitoring the service. My usual starting point is the Prometheus, Grafana, and Alertmanager stack, with kube-state-metrics for Kubernetes object state.<\/p>\n<p>Let me put it this way: monitoring is not a contest to produce the largest number of graphs. I want to know which signals deserve to wake me at 3 a.m., which ones need a daytime review, and which ones are only useful during troubleshooting. A pod restart matters. The restart count, its owning Deployment, and the effect on users matter more.<\/p>\n<h2><span id=\"What_each_component_actually_does\">What each component actually does<\/span><\/h2>\n<p>These components are related, but they do different jobs. Keeping that distinction clear makes troubleshooting much less confusing.<\/p>\n<table>\n<thead>\n<tr>\n<th>Component<\/th>\n<th>What it provides<\/th>\n<th>Typical use<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Prometheus<\/td>\n<td>Time-series metrics from nodes, pods, applications, and Kubernetes endpoints<\/td>\n<td>Queries, recording rules, and alert evaluation<\/td>\n<\/tr>\n<tr>\n<td>Grafana<\/td>\n<td>Dashboards based on Prometheus and other data sources<\/td>\n<td>Visualization and operational investigation<\/td>\n<\/tr>\n<tr>\n<td>Alertmanager<\/td>\n<td>Notifications created by Prometheus alert rules<\/td>\n<td>Grouping, silencing, deduplication, and routing<\/td>\n<\/tr>\n<tr>\n<td>kube-state-metrics<\/td>\n<td>Metrics about Deployments, Pods, Jobs, Nodes, and other Kubernetes objects<\/td>\n<td>Comparing the desired and observed state<\/td>\n<\/tr>\n<tr>\n<td>Node Exporter<\/td>\n<td>Linux operating system metrics<\/td>\n<td>CPU, memory, filesystem, and network monitoring<\/td>\n<\/tr>\n<tr>\n<td>Metrics Server<\/td>\n<td>Current CPU and memory usage summaries<\/td>\n<td><code>kubectl top<\/code> and the Horizontal Pod Autoscaler<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Metrics Server and Prometheus are not interchangeable. Metrics Server provides a current resource-use view through the Kubernetes API. Prometheus stores historical time series, collects application metrics, and evaluates detailed alert rules.<\/p>\n<p>A working <code>kubectl top nodes<\/code> command is useful. It is not proof that monitoring is complete.<\/p>\n<h2><span id=\"Check_the_cluster_before_installing_anything\">Check the cluster before installing anything<\/span><\/h2>\n<p>I test monitoring changes on the Proxmox cluster in my home lab before touching production. My second-hand HP EliteDesk has taken plenty of failed chart upgrades so customer workloads did not have to. That is a much cheaper place to learn what a bad values file does.<\/p>\n<p>First confirm that the API server, nodes, and Helm client are usable:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">kubectl cluster-info\nkubectl get nodes -o wide\nkubectl version\nhelm version<\/code><\/pre>\n<p>The first command checks API connectivity. The node listing shows scheduling capacity and node conditions, while the version commands tell you what clients and servers you are working with. Kubernetes client output varies by release, so I do not rely on one exact format.<\/p>\n<p>Create a dedicated namespace for the stack:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">kubectl create namespace monitoring\nkubectl get namespace monitoring<\/code><\/pre>\n<p>If the namespace already exists, <code>AlreadyExists<\/code> is harmless. In a production workflow, I normally manage this through a manifest or GitOps repository instead of treating imperative commands as the source of truth.<\/p>\n<h2><span id=\"Installing_kube-prometheus-stack_with_Helm\">Installing kube-prometheus-stack with Helm<\/span><\/h2>\n<p>The <code>kube-prometheus-stack<\/code> chart from the Prometheus Community packages Prometheus Operator, Prometheus, Grafana, Alertmanager, Node Exporter, and kube-state-metrics together. The exact resources and chart defaults change over time, so I pin the chart version rather than allowing an unexpected update to alter CRDs during maintenance.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">helm repo add prometheus-community https:\/\/prometheus-community.github.io\/helm-charts\nhelm repo update\nhelm search repo prometheus-community\/kube-prometheus-stack<\/code><\/pre>\n<p>Record the chart version shown by the search command. Then inspect its values before installing:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">helm show values prometheus-community\/kube-prometheus-stack &gt; kube-prometheus-stack.values.example.yaml<\/code><\/pre>\n<p>For a disposable test cluster, the defaults are enough to get started:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">helm install monitoring prometheus-community\/kube-prometheus-stack \\\n  --namespace monitoring \\\n  --create-namespace<\/code><\/pre>\n<p>This creates a Helm release called <code>monitoring<\/code>. I would not use those defaults for a production cluster. Storage, resource requests, retention, access, and alert routing should be deliberate.<\/p>\n<h3><span id=\"A_starting_values_file\">A starting values file<\/span><\/h3>\n<p>The following configuration is only a starting point. Replace <code>standard<\/code> with a StorageClass that exists in your cluster, as shown by <code>kubectl get storageclass<\/code>. On some managed clusters, the default StorageClass has a different name; on a bare-metal cluster, there may be none at all.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">grafana:\n  admin:\n    existingSecret: grafana-admin\n  persistence:\n    enabled: true\n    storageClassName: standard\n    size: 10Gi\n  resources:\n    requests:\n      cpu: 100m\n      memory: 256Mi\n    limits:\n      cpu: 500m\n      memory: 512Mi\n\nprometheus:\n  prometheusSpec:\n    retention: 15d\n    retentionSize: 40GB\n    storageSpec:\n      volumeClaimTemplate:\n        spec:\n          storageClassName: standard\n          accessModes:\n            - ReadWriteOnce\n          resources:\n            requests:\n              storage: 50Gi\n    resources:\n      requests:\n        cpu: 500m\n        memory: 1Gi\n      limits:\n        cpu: 2\n        memory: 4Gi\n\nalertmanager:\n  alertmanagerSpec:\n    storage:\n      volumeClaimTemplate:\n        spec:\n          storageClassName: standard\n          accessModes:\n            - ReadWriteOnce\n          resources:\n            requests:\n              storage: 10Gi<\/code><\/pre>\n<p>This keeps Grafana settings, Prometheus data, and Alertmanager state on persistent volumes. It does not make the data a backup. I still back up the underlying storage or export the configuration separately.<\/p>\n<p>Disk sizing depends on scrape interval, retention, metric cardinality, and the number of targets, not just pod count. I learned that after treating a small cluster as if every metric had the same storage cost.<\/p>\n<p>Install or update the release with the values file:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">helm upgrade --install monitoring prometheus-community\/kube-prometheus-stack \\\n  --namespace monitoring \\\n  --values values.yaml \\\n  --wait \\\n  --timeout 10m<\/code><\/pre>\n<p>The <code>--wait<\/code> flag waits for resources to become ready, but it cannot repair a missing StorageClass or an unschedulable pod. If Helm times out, inspect pods, events, and PVCs before running the command again.<\/p>\n<h2><span id=\"Verify_the_installation_instead_of_trusting_Helm\">Verify the installation instead of trusting Helm<\/span><\/h2>\n<p>Start by watching the monitoring namespace:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">kubectl get pods -n monitoring -w<\/code><\/pre>\n<p>Most components should reach <code>Running<\/code>. A short-lived setup job may show <code>Completed<\/code>. A pod stuck in <code>Pending<\/code> usually points to insufficient resources, an unsuitable node, or a PVC that cannot bind.<\/p>\n<p>Check storage, Services, and recent events:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">kubectl get pvc -n monitoring\nkubectl get svc -n monitoring\nkubectl get events -n monitoring --sort-by=.lastTimestamp<\/code><\/pre>\n<p>Messages such as <code>FailedScheduling<\/code>, <code>FailedMount<\/code>, and image-pull errors usually narrow the problem quickly. They have saved me from repeatedly reinstalling a chart when the real issue was a missing disk provisioner.<\/p>\n<p>For an initial test, use port forwarding. Run each command in a separate terminal:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">kubectl port-forward -n monitoring svc\/monitoring-kube-prometheus-prometheus 9090:9090\nkubectl port-forward -n monitoring svc\/monitoring-grafana 3000:80<\/code><\/pre>\n<p>Open <code>http:\/\/127.0.0.1:9090<\/code> and <code>http:\/\/127.0.0.1:3000<\/code> locally. Port forwarding is suitable for a temporary check, not for publishing Grafana to the internet. Use a VPN, bastion host, or authenticated reverse proxy instead. The same principle applies to the panel access described in <a href=\"https:\/\/www.dchost.com\/blog\/en\/secure-remote-access-to-hosting-panels-with-vpn-and-bastion-hosts\/\">Secure Remote Access to Hosting Panels with VPN and Bastion Hosts<\/a>.<\/p>\n<p>Run the <code>up<\/code> query in Prometheus. A value of <code>1<\/code> means that Prometheus reached a target; <code>0<\/code> means the scrape failed. Change the time range and confirm that samples are arriving. A dashboard that loads is not evidence that its queries are returning current data.<\/p>\n<h2><span id=\"Expose_application_metrics_not_only_cluster_metrics\">Expose application metrics, not only cluster metrics<\/span><\/h2>\n<p>Node and Kubernetes object metrics tell me what the platform is doing. They do not tell me whether an order endpoint is slow or whether checkout is returning errors. The application needs to expose request count, latency, error rate, and other service-specific measurements, commonly through a <code>\/metrics<\/code> endpoint.<\/p>\n<p>With Prometheus Operator, a <code>ServiceMonitor<\/code> describes how that endpoint should be scraped. The Service must have a matching label and a named metrics port:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apiVersion: monitoring.coreos.com\/v1\nkind: ServiceMonitor\nmetadata:\n  name: orders-api\n  namespace: monitoring\n  labels:\n    release: monitoring\nspec:\n  namespaceSelector:\n    matchNames:\n      - production\n  selector:\n    matchLabels:\n      app: orders-api\n  endpoints:\n    - port: metrics\n      path: \/metrics\n      interval: 30s<\/code><\/pre>\n<p>The <code>release: monitoring<\/code> label must match the selector used by the Prometheus resource created by the Helm release. If you changed that selector in <code>values.yaml<\/code>, use the matching value here. The Service in the <code>production<\/code> namespace also needs a port named <code>metrics<\/code>; a ServiceMonitor can look perfectly valid and still produce no target without it.<\/p>\n<p>Check the Prometheus <em>Status<\/em> and <em>Targets<\/em> pages. If the target is not <em>UP<\/em>, check the Service selector, DNS name, port, path, and NetworkPolicy. The endpoint does not need to be exposed outside the cluster. Prometheus only needs network access to it.<\/p>\n<h2><span id=\"Alert_rules_should_lead_to_an_action\">Alert rules should lead to an action<\/span><\/h2>\n<p>Writing Prometheus rules without configuring Alertmanager leaves the job half finished. Prometheus evaluates the expression. Alertmanager groups, silences, and routes the resulting notifications.<\/p>\n<p>A <code>for<\/code> period prevents a brief fluctuation from waking someone unnecessarily. This example reports a sustained gap between available and desired Deployment replicas:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apiVersion: monitoring.coreos.com\/v1\nkind: PrometheusRule\nmetadata:\n  name: application-alerts\n  namespace: monitoring\n  labels:\n    release: monitoring\nspec:\n  groups:\n    - name: application.rules\n      rules:\n        - alert: DeploymentReplicasMismatch\n          expr: kube_deployment_status_replicas_available{namespace=&quot;production&quot;} &lt; kube_deployment_spec_replicas{namespace=&quot;production&quot;}\n          for: 10m\n          labels:\n            severity: warning\n          annotations:\n            summary: &quot;Deployment has fewer pods than expected&quot;\n            description: &quot;The number of available pods for {{ $labels.deployment }} has been low for 10 minutes.&quot;\n\n        - alert: InstanceDown\n          expr: up{job=~&quot;critical-.*&quot;} == 0\n          for: 5m\n          labels:\n            severity: critical\n          annotations:\n            summary: &quot;Critical monitoring target is unreachable&quot;\n            description: &quot;The target {{ $labels.instance }} cannot be scraped.&quot;<\/code><\/pre>\n<p>The first rule measures reduced Deployment capacity. The second is deliberately scoped to jobs named <code>critical-*<\/code>; applying <code>up == 0<\/code> to every target can create a noisy alert storm during planned maintenance.<\/p>\n<p>Store SMTP credentials and webhook tokens in a Kubernetes Secret or a dedicated secret-management system. Do not place them directly in a values file committed to Git. After configuring a receiver, trigger a controlled test alert and verify the message arrives.<\/p>\n<p>A silent Alertmanager is a fire alarm with no battery.<\/p>\n<h2><span id=\"Prometheus_has_a_cardinality_problem_to_manage\">Prometheus has a cardinality problem to manage<\/span><\/h2>\n<p>Prometheus needs monitoring too. When its memory use keeps climbing, I first inspect retention, scrape volume, and label cardinality. A unique URL, customer ID, or order number used as a label can create a new time series for every request.<\/p>\n<p>These two labels have very different consequences:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">http_requests_total{path=&quot;\/orders\/847291&quot;}\nhttp_requests_total{route=&quot;\/orders\/:id&quot;}<\/code><\/pre>\n<p>The first can produce one series per order. The second normalizes the route and is much easier to control. Metric names and labels deserve review during application development; removing a high-cardinality metric after Prometheus is already under pressure is unpleasant.<\/p>\n<p>If the Prometheus pod restarts, inspect the pod and its previous container logs:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">kubectl describe pod -n monitoring -l app.kubernetes.io\/name=prometheus\nkubectl logs -n monitoring -l app.kubernetes.io\/name=prometheus --previous\nkubectl top pod -n monitoring<\/code><\/pre>\n<p>The <code>--previous<\/code> flag shows logs from the container instance that exited. If the pod was <code>OOMKilled<\/code>, increasing the memory limit may only postpone the same failure. Check retention, scrape interval, and labels first.<\/p>\n<h2><span id=\"What_a_DDoS_night_taught_me_about_useful_signals\">What a DDoS night taught me about useful signals<\/span><\/h2>\n<p>During my first major DDoS incident, node dashboards looked reasonably normal while application errors climbed. At first glance, the traffic increase could have been genuine demand. When we compared request sources and response codes, a large portion of the traffic clearly did not resemble normal visitor behavior.<\/p>\n<p>We enabled rate limits, geographic filtering, and connection limits at the ingress layer. I also had to explain one point to the customer: not every HTTP request represents a real visitor.<\/p>\n<p>Since that night, I have kept ingress <code>5xx<\/code> rate, request volume, response time, and external availability separate from node-health alerts. Prometheus target failures, Grafana data-source failures, and Alertmanager delivery failures deserve their own checks.<\/p>\n<p>The dashboards were not the problem. We were watching the wrong layer.<\/p>\n<h2><span id=\"Security_access_and_retention\">Security, access, and retention<\/span><\/h2>\n<p>Grafana dashboards can expose namespace names, node names, service names, and metric labels that should not be public. I disable anonymous access and avoid exposing Grafana directly to the internet.<\/p>\n<p>A ServiceAccount with broad Kubernetes API permissions creates another unnecessary risk. Review the RBAC objects installed by the chart and grant only the access the components need.<\/p>\n<p>NetworkPolicy introduces a practical trap. If you enable restrictive policies, confirm that Prometheus can reach kube-state-metrics, Node Exporter, and application metric Services. I usually begin with the required paths documented and tested, then tighten policies gradually. Blocking everything at once makes the failure harder to locate.<\/p>\n<p>Retention has a storage cost. Seven to fifteen days may be a reasonable starting range for a small cluster, but the correct value depends on your incident history and disk capacity. Set both <code>retention<\/code> and <code>retentionSize<\/code>; do not let the Prometheus volume grow without a boundary.<\/p>\n<h2><span id=\"Operating_the_stack_after_installation\">Operating the stack after installation<\/span><\/h2>\n<p>A dashboard is not a maintenance plan. Every week, review alert history, silences, disk usage, and the alerts that resulted in no action. If the same rule wakes someone for a condition nobody can act on, change the query or remove the rule.<\/p>\n<p>When you create a maintenance silence, give it an expiry and a reason. A silence without an end time is just a polished way of disabling an alarm.<\/p>\n<p>After chart or application changes, I check:<\/p>\n<ul>\n<li>Prometheus target status<\/li>\n<li>Grafana data-source access<\/li>\n<li>Test notifications through Alertmanager receivers<\/li>\n<li>PVC utilization<\/li>\n<li>Pod restart counts and <code>OOMKilled<\/code> events<\/li>\n<li>Node disk, CPU, and memory pressure<\/li>\n<li>Ingress HTTP <code>5xx<\/code> rate and response time<\/li>\n<\/ul>\n<p>Keep an external synthetic check as well. Every pod can be healthy while the payment endpoint is broken. An outside HTTP check combined with internal metrics gives you two different views of the same service.<\/p>\n<p>The separation between a warning and an affected user journey matters outside Kubernetes too. The method described in <a href=\"https:\/\/www.dchost.com\/blog\/en\/how-to-read-and-fix-wordpress-site-health-report\/\">WordPress Site Health: How to Read and Fix the Report<\/a> applies here: identify the component, then identify the user flow it affects.<\/p>\n<p>In my lab, I install chart updates into a separate namespace, fire a test alert, and compare dashboard queries before touching the live release. I once spent hours chasing an apparently empty graph before noticing that the new Deployment no longer matched the query&#8217;s label selector. The graph was honest. My assumption was not.<\/p>\n<h2><span id=\"Frequently_asked_questions\">Frequently asked questions<\/span><\/h2>\n<h3><span id=\"What_is_the_difference_between_Prometheus_and_Metrics_Server\">What is the difference between Prometheus and Metrics Server?<\/span><\/h3>\n<p>Metrics Server exposes current CPU and memory usage through the Kubernetes API and supports commands such as <code>kubectl top<\/code> and features such as the Horizontal Pod Autoscaler. Prometheus stores time-series data, collects application metrics, and evaluates alert rules.<\/p>\n<h3><span id=\"Is_Grafana_required_for_Kubernetes_monitoring\">Is Grafana required for Kubernetes monitoring?<\/span><\/h3>\n<p>No. Prometheus queries and Alertmanager can work without Grafana. Grafana is useful because it puts related metrics into dashboards that are faster to read during an investigation.<\/p>\n<h3><span id=\"How_long_should_Prometheus_data_be_retained\">How long should Prometheus data be retained?<\/span><\/h3>\n<p>That depends on cluster size, disk capacity, scrape volume, and the historical questions you need to answer. Starting with seven to fifteen days and watching disk usage is safer than allowing unlimited retention.<\/p>\n<h3><span id=\"How_can_I_reduce_the_number_of_alerts\">How can I reduce the number of alerts?<\/span><\/h3>\n<p>Check whether several rules report the same event. Add a <code>for<\/code> period for short-lived conditions, separate critical alerts from informational ones, and remove alerts that never require an action. The best alert is not the loudest one; it is the one that tells me what needs doing next.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>A practical Kubernetes monitoring setup with Prometheus, Grafana, Alertmanager, application metrics, alert rules, cardinality controls, and operational checks.<\/p>\n","protected":false},"author":4,"featured_media":5194,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[176],"tags":[518,521,519,517,52,515,516],"class_list":["post-5197","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud-computing","tag-alertmanager","tag-container-monitoring","tag-devops","tag-grafana","tag-kubernetes","tag-kubernetes-monitoring","tag-prometheus"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/5197","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=5197"}],"version-history":[{"count":1,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/5197\/revisions"}],"predecessor-version":[{"id":5199,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/5197\/revisions\/5199"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/5194"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=5197"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=5197"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=5197"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}