{"id":820,"date":"2024-04-15T12:34:56","date_gmt":"2024-04-15T12:34:56","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=820"},"modified":"2024-04-15T12:34:56","modified_gmt":"2024-04-15T12:34:56","slug":"setup-prometheus-operator","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=820","title":{"rendered":"How to Setup Prometheus Operator on Kubernetes"},"content":{"rendered":"<p>In this blog, we are going to set up and configure the <strong>Prometheus Operator.<\/strong><\/p>\n<p>The Prometheus is not a native object of the Kubernetes, but we can make it a Kubernetes<strong> <\/strong>native object using the <strong>Prometheus operators.<\/strong><\/p>\n<h2 id=\"what-is-prometheus-operator\"><strong>What is Prometheus Operator<\/strong><\/h2>\n<p><strong>Prometheus Operator<\/strong> is a <strong>Kubernetes Custom Controller<\/strong> that can communicate with the <strong>Kubernetes API Server <\/strong>and allow Prometheus to do the operations.<\/p>\n<p>We will install Prometheus on our Kubernetes cluster but the main moto of installing the <strong>Prometheus Operator<\/strong> is to reduce the complexity of the configuration.<\/p>\n<p>In normal Prometheus deployment, <code>configMap<\/code> is an important object where we inform the targets and rules information to the Prometheus.<\/p>\n<p>Instead of that, the Prometheus Operator has dedicated objects for that. For example, <code>prometheusRuler<\/code> for rules, <code>podMonitor<\/code> object for monitoring the Pods, <code>scrapeConfig<\/code> object for static targets and more.<\/p>\n<p>In a normal Prometheus stack, if you want to make any modifications that will disturb the present configuration, but in the Prometheus Operator, we can make the configuration changes whenever we want, and also, the current state won&#8217;t be disturbed.<\/p>\n<p>If you set up the <strong>Prometheus operators<\/strong>, you won&#8217;t feel that the Prometheus<strong> <\/strong>is an external object, and it will simplify the overall integration and configuration process.<\/p>\n<p>If you want to install Prometheus on your Kubernetes cluster without the Operator, here is the <a href=\"https:\/\/devopscube.com\/setup-prometheus-monitoring-on-kubernetes\/\">blog<\/a>.<\/p>\n<h2 id=\"prometheus-operator-workflow\">Prometheus Operator Workflow<\/h2>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/operator-workflow-1.gif\" class=\"kg-image\" alt=\"prometheus operator workflow\n\" loading=\"lazy\" width=\"785\" height=\"851\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/operator-workflow-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/operator-workflow-1.gif 785w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<ol>\n<li>Prometheus Operator keeps watching its <strong>Custom Resource Definitions<\/strong>.<\/li>\n<li>We inform the Operator via Custom Resource what outcome we are expecting.<\/li>\n<li>For example, I am telling on a Custom Resource that I have a service, and the service&#8217;s endpoint should be monitored.<\/li>\n<li>The operator will get this information from the CRD and will do the required changes.<\/li>\n<li>But the Operator has all the logic in it, which means that the operator will identify the Service with the labels that we provide and collect the endpoint information then make a structure and place it on the Prometheus instance.<\/li>\n<\/ol>\n<h2 id=\"what-are-the-prometheus-supported-custom-resource-definitions\"><strong>What are the Prometheus Supported Custom Resource Definitions<\/strong><\/h2>\n<h3 id=\"prometheus\"><strong>Prometheus<\/strong><\/h3>\n<p><strong>Prometheus Custom Resource Definition <\/strong>(CRD) is used to create the <strong>Prometheus Custom Resource, <\/strong>or we can simply say the Prometheus deployment on the <strong>Kubernetes <\/strong>cluster also offers the replication and storage related configuration. <\/p>\n<h3 id=\"alertmanager\"><strong>Alertmanager<\/strong><\/h3>\n<p>Alertmanager CRD is used to create an Alertmanager deployment on the cluster.<\/p>\n<h3 id=\"thanosruler\"><strong>ThanosRuler<\/strong><\/h3>\n<p>ThanosRuler CRD manages and validates the Prometheus Recording Rules and the Alerting Rules.<\/p>\n<h3 id=\"servicemonitor\"><strong>ServiceMonitor<\/strong><\/h3>\n<p>ServiceMonitor CRD helps add the Kubernetes services to the Prometheus Custom Resources.<\/p>\n<h3 id=\"podmonitor\"><strong>PodMonitor<\/strong><\/h3>\n<p>PodMonitor CRD is used to add the Pods on the Prometheus Custom Resource.<\/p>\n<h3 id=\"probe\"><strong>Probe<\/strong><\/h3>\n<p>Probe CRD is used to add the static targets on the Prometheus Custom Resource.<\/p>\n<h3 id=\"prometheusrule\"><strong>PrometheusRule<\/strong><\/h3>\n<p>Add alerting rules and recording rules on the Prometheus.<\/p>\n<h3 id=\"alertmanagerconfig\"><strong>AlertmanagerConfig<\/strong><\/h3>\n<p>Alertmanager-related configuration such as inhibition, routing, silencing, etc.<\/p>\n<h2 id=\"prometheus-operator-setuphelm\"><strong>Prometheus Operator Setup &#8211; Helm<\/strong><\/h2>\n<p>The Helm chart will deploy all the Prometheus Operator components, such as Custom Resource Definitions and Deployments.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/prometheus-operato-components-1-1.gif\" class=\"kg-image\" alt=\"prometheus operator components\" loading=\"lazy\" width=\"1502\" height=\"1062\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/prometheus-operato-components-1-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/prometheus-operato-components-1-1.gif 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/prometheus-operato-components-1-1.gif 1502w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h3 id=\"prerequisites\"><strong>Prerequisites<\/strong><\/h3>\n<ol>\n<li>Kubernetes cluster v1.31 or higher.<\/li>\n<li>kubectl v1.31 or higher should be available on the local system.<\/li>\n<li>Helm v3.16 or higher should be available on the local system.<\/li>\n<\/ol>\n<blockquote><p>Note: If you are using an EKS cluster, suitable VPC-CNI should be available in the cluster.<\/p>\n<p>To install the VPC-CNI, use this <a href=\"https:\/\/github.com\/aws\/eks-charts\/blob\/master\/stable\/aws-vpc-cni\/README.md?ref=devopscube.com\">official documentation.<\/a><\/p><\/blockquote>\n<p>Add the Prometheus community Helm chart.<\/p>\n<pre><code>helm repo add prometheus-community https:\/\/prometheus-community.github.io\/helm-charts<\/code><\/pre>\n<p>Update the Helm repository<\/p>\n<pre><code>helm repo update<\/code><\/pre>\n<p>Before the installation of the operator, we need to get the values file of the helm chart so that we can make configuration changes if we want.<\/p>\n<p>To get the values file, use the following command.<\/p>\n<pre><code>helm show values prometheus-community\/kube-prometheus-stack &gt; values.yaml<\/code><\/pre>\n<p>Now, we can install the Prometheus Operator using the Helm<\/p>\n<pre><code>helm install prometheus prometheus-community\/kube-prometheus-stack -n prometheus-operator --create-namespace<\/code><\/pre>\n<p>It will take a few minutes to complete the setup; once it is completed, we can check the Pods.<\/p>\n<pre><code>kubectl get pods -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-100-5.png\" class=\"kg-image\" alt=\"prometheus operator pods\" loading=\"lazy\" width=\"1000\" height=\"545\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-100-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-100-5.png 1000w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>In this, <strong>Grafana, Prometheus Operator<\/strong> and <strong>Kube State Metrics<\/strong> are deployed as <strong>Deployment<\/strong> Objects.<\/p>\n<pre><code>kubectl get deployments -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-101-6.png\" class=\"kg-image\" alt=\"prometheus operator deployments\" loading=\"lazy\" width=\"809\" height=\"343\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-101-6.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-101-6.png 809w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Grafana:<\/strong> Visualize the metrics<\/p>\n<p><strong>Prometheus Operator:<\/strong> It is a controller to manage and configure the Prometheus stack<\/p>\n<p><strong>Kube state metrics:<\/strong> Collect the Kubernetes API Server metrics<\/p>\n<p><strong>Alertmanager<\/strong> and <strong>Prometheus<\/strong> are deployed as <strong>StatefulSets.<\/strong><\/p>\n<pre><code>kubectl get statefulsets -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-102-6.png\" class=\"kg-image\" alt=\"Prometheus operator statefulset objects\" loading=\"lazy\" width=\"807\" height=\"279\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-102-6.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-102-6.png 807w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Alertmanager:<\/strong> Sending alerts via email or notifications<\/p>\n<p><strong>Prometheus:<\/strong> Collect metrics<\/p>\n<p><!--kg-card-begin: html--><br \/>\n<span style=\"box-sizing: border-box; margin: 0px; padding: 0px;\">Prometheus and Alertmanager are deployed as&nbsp;<strong>StatefulSet<\/strong>&nbsp;objects because Prometheus has the&nbsp;<strong>Time Series Database<\/strong>&nbsp;that stores the metrics, and both these Objects have configurations, so it does need persistent volumes.<\/span><br \/>\n<!--kg-card-end: html--><\/p>\n<p>Because of the persistent volume, the data will persist even if the Pod is removed or rescheduled.<\/p>\n<p>The <strong>Node Exporter<\/strong> is deployed as a <strong>Daemonset<\/strong> because this object ensures that the Node Exporter is available on each node to collect the metrics.<\/p>\n<pre><code>kubectl get daemonsets -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-103-4.png\" class=\"kg-image\" alt=\"prometheus operator node exporter daemonset\" loading=\"lazy\" width=\"1154\" height=\"219\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-103-4.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-103-4.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-103-4.png 1154w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Now, let&#8217;s view their intended Services.<\/p>\n<pre><code>kubectl get svc -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-104-4.png\" class=\"kg-image\" alt=\"Prometheus operator object services\" loading=\"lazy\" width=\"1153\" height=\"588\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-104-4.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-104-4.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-104-4.png 1153w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Deploying the Prometheus Operator will create custom resources to monitor the default Kubernetes resources, such as nodes, API server, kube-proxy, kubelet, etc.<\/p>\n<p>We need to perform the port forwarding to see the web UI of Prometheus, Alertmanager, or Grafana.<\/p>\n<p>For that, we need the <strong>service name<\/strong> <code>prometheus-kube-prometheus-prometheus <\/code>and the related <strong>port number<\/strong> <code>9090<\/code>.<\/p>\n<p>To view the Dashboard of the <strong>Prometheus<\/strong>, use the following command.<\/p>\n<pre><code>kubectl port-forward -n prometheus-operator svc\/prometheus-kube-prometheus-prometheus 9090:9090<\/code><\/pre>\n<p>Now, open any of the web browsers from your local machine and paste the URL <code>localhost:9090<\/code>.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-196-2.png\" class=\"kg-image\" alt=\"prometheus operator dashobard 3.0\" loading=\"lazy\" width=\"1920\" height=\"1055\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-196-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-196-2.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-196-2.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-196-2.png 1920w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>In the target section of the dashboard, we can see some of the targets are pre-configured.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-197-2.png\" class=\"kg-image\" alt=\"the target section of the prometheus dashboard\" loading=\"lazy\" width=\"1529\" height=\"1055\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-197-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-197-2.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-197-2.png 1529w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>These <strong>Custom Resources<\/strong> are created by using the <code>ServiceMonitor<\/code> <strong>Custom Resource Definition<\/strong>.<\/p>\n<pre><code>kubectl get servicemonitors -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-107-4.png\" class=\"kg-image\" alt=\"Prometheus operator servicemonitor custom resource\" loading=\"lazy\" width=\"762\" height=\"649\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-107-4.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-107-4.png 762w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>To see the dashboard of the <strong>Alertmanager<\/strong>, use the following command.<\/p>\n<pre><code>kubectl port-forward --namespace prometheus-operator svc\/prometheus-kube-prometheus-alertmanager 9093:9093<\/code><\/pre>\n<p>Let&#8217;s try to access the dashboard from our local system <code>localhost:9093<\/code>.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-117-8.png\" class=\"kg-image\" alt=\"prometheus alertmanager dashboard\" loading=\"lazy\" width=\"1172\" height=\"1125\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-117-8.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-117-8.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-117-8.png 1172w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Most of the configurations are already defined and if you want modifications you can do it, also in this setup, by default, you can&#8217;t access the dashboards of the services such as Prometheus, Alertmanager, Grafana, etc.<\/p>\n<p>So, if you want to access the internet, you need to create a new Service object for them with the type <strong>NodePort <\/strong>or <strong>Loadbalancer.<\/strong><\/p>\n<p>To view the list of all the <strong>Custom Resource Definitions<\/strong> related to the Prometheus Operator.<\/p>\n<pre><code>kubectl get crds -n prometheus-operator<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-105-7.png\" class=\"kg-image\" alt=\"Prometheus operator custom resource definitions\n\" loading=\"lazy\" width=\"764\" height=\"527\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-105-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-105-7.png 764w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>With these custom resource definitions, you can create as many custom resources as you want.<\/p>\n<h2 id=\"how-to-install-prometheus-operatoryaml-manifest\"><strong>How to Install Prometheus Operator<\/strong> &#8211; YAML Manifest<\/h2>\n<p>In this method, you can customize the Prometheus Operator installation. For example, if you only want Prometheus but don&#8217;t need Alertmanager or Grafana, you can easily do that with this setup.<\/p>\n<p>Download the <strong>bundle.yaml<\/strong> file from the <strong>Prometheus Operator GitHub repository<\/strong> to define the <strong>Prometheus Custom Resource Definitions<\/strong> and the <strong>Prometheus Operator.<\/strong><\/p>\n<pre><code>wget https:\/\/github.com\/prometheus-operator\/prometheus-operator\/releases\/download\/v0.79.2\/bundle.yaml<\/code><\/pre>\n<p>Use the following command to deploy the <strong>Custom Resource Definitions (CRDs) <\/strong>to the cluster.<\/p>\n<pre><code>kubectl create -f bundle.yaml<\/code><\/pre>\n<p>These resources will be deployed in the <strong>default <\/strong>namespace, and currently, only the Prometheus Operator and the CRDs are deployed.<\/p>\n<pre><code>kubectl get deployments -n default<\/code><\/pre>\n<p>To view and filter the <strong>Prometheus Operator Custom Resource Definitions<\/strong>.<\/p>\n<pre><code>kubectl get crds | grep \"monitoring.coreos.com\"<\/code><\/pre>\n<h2 id=\"test-the-prometheus-operator-with-an-application\">Test the Prometheus Operator with an Application<\/h2>\n<p>To test the workflow of the Prometheus Operator, we need a target application.<\/p>\n<p>We are using an application for testing purposes, and you have to ensure that the application should be instrumented with the Prometheus Client Libraries. <\/p>\n<p>For testing purposes, I will deploy this application with three replicas and create a service for this deployment.<\/p>\n<p>Then, I will use the ServiceMonitor Custom Resource to collect the metrics from the service endpoints, basically the deployment&#8217;s three replica pods.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/prometheus-operator-crd-workflow-1.gif\" class=\"kg-image\" alt=\"prometheus custom resource workflow\n\" loading=\"lazy\" width=\"794\" height=\"933\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/prometheus-operator-crd-workflow-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/prometheus-operator-crd-workflow-1.gif 794w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>First, we need to create a Deployment manifest for the application <code>instrumented-app-deploy.yaml<\/code><\/p>\n<pre><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: example-app\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: example-app\n  template:\n    metadata:\n      labels:\n        app: example-app\n    spec:\n      containers:\n      - name: example-app\n        image: fabxc\/instrumented_app\n        ports:\n        - name: web\n          containerPort: 8080<\/code><\/pre>\n<p>This application will expose the metrics at <strong>Port 8080,<\/strong> and I am providing three replicas for this application.<\/p>\n<p>To deploy this application, use the following command.<\/p>\n<pre><code>kubectl apply -f instrumented-app-deploy.yaml<\/code><\/pre>\n<p>Check the Deployment and Pods to ensure the deployment is properly done.<\/p>\n<p>Now, I am creating a service file for this application <code>instrumented-app-svc.yaml<\/code><\/p>\n<pre><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: example-app\n  labels:\n    app: example-app\nspec:\n  selector:\n    app: example-app\n  ports:\n  - name: web\n    port: 8080<\/code><\/pre>\n<p>To deploy this application service, use the following command.<\/p>\n<pre><code>kubectl apply -f instrumented-app-svc.yaml<\/code><\/pre>\n<p>We need to ensure this application service is running properly.<\/p>\n<pre><code>kubectl get svc<\/code><\/pre>\n<h2 id=\"create-service-monitor-custom-resource\"><strong>Create Service Monitor Custom Resource<\/strong><\/h2>\n<p><strong>ServiceMonitor<\/strong> Custom Resource is used to collect the metrics from the service endpoints.<\/p>\n<p><strong>Labels<\/strong> play an important role in these configurations, so provide your labels simple and meaningful.<\/p>\n<p>I am going to use the labels of the Service as the Selector of the <code>ServiceMonitor<\/code> object.<\/p>\n<p>Now, we have to create the ServiceMonitor Custom Resource file <code>service-monitor-cr.yaml<\/code><\/p>\n<pre><code>apiVersion: monitoring.coreos.com\/v1\nkind: ServiceMonitor\nmetadata:\n  name: example-app\n  labels:\n    team: frontend\nspec:\n  selector:\n    matchLabels:\n      app: example-app\n  endpoints:\n  - port: web<\/code><\/pre>\n<p>Here, you can see, under the <code>spec<\/code> section, I have provided the label of the application service <code>app: example-app<\/code>. This is how ServiceMonitor identifies the service object and its endpoints.<\/p>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f service-monitor-cr.yaml<\/code><\/pre>\n<p>To list the ServiceMonitor object.<\/p>\n<pre><code>kubectl get servicesmonitor<\/code><\/pre>\n<h2 id=\"create-a-service-account\"><strong>Create a Service Account<\/strong><\/h2>\n<p>If you are performing <strong>RBAC authorization<\/strong> on your cluster, then first you need to set up the <strong>ClusterRole<\/strong> and <strong>ClusterRoleBinding<\/strong> with a <strong>ServiceAccount.<\/strong><\/p>\n<p>Create a service account file <code>service-account.yaml<\/code><\/p>\n<pre><code>apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: prometheus-operator-svc-ac<\/code><\/pre>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f service-account.yaml<\/code><\/pre>\n<p>To list the service accounts in the current namespace.<\/p>\n<pre><code>kubectl get serviceaccount<\/code><\/pre>\n<h2 id=\"create-clusterrole\"><strong>Create ClusterRole<\/strong><\/h2>\n<p>Create a ClusterRole file <code>clusterrole.yaml<\/code> and provide the necessary permission for the cluster-scoped resources.<\/p>\n<pre><code>apiVersion: rbac.authorization.k8s.io\/v1\nkind: ClusterRole\nmetadata:\n  name: prometheus\nrules:\n- apiGroups: [\"\"]\n  resources:\n  - nodes\n  - nodes\/metrics\n  - services\n  - endpoints\n  - pods\n  verbs: [\"get\", \"list\", \"watch\"]\n- apiGroups: [\"\"]\n  resources:\n  - configmaps\n  verbs: [\"get\"]\n- apiGroups:\n  - networking.k8s.io\n  resources:\n  - ingresses\n  verbs: [\"get\", \"list\", \"watch\"]\n- nonResourceURLs: [\"\/metrics\"]\n  verbs: [\"get\"]<\/code><\/pre>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f clusterrole.yaml<\/code><\/pre>\n<p>To list the cluster roles in the current namespace.<\/p>\n<pre><code>kubectl get clusterrole prometheus<\/code><\/pre>\n<h2 id=\"create-clusterrolebinding\"><strong>Create ClusterRoleBinding<\/strong><\/h2>\n<p>Create a ClusterRoleBinding file <code>clusterrolebinding.yaml<\/code> and integrate the information about the ClusterRole and the ServiceAccount.<\/p>\n<pre><code>apiVersion: rbac.authorization.k8s.io\/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: prometheus\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: prometheus\nsubjects:\n- kind: ServiceAccount\n  name: prometheus-operator-svc-ac\n  namespace: default<\/code><\/pre>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f clusterrolebinding.yaml<\/code><\/pre>\n<p>To view the details about the ClusterRoleBinding<strong>.<\/strong><\/p>\n<pre><code>kubectl describe clusterrolebinding prometheus<\/code><\/pre>\n<p>If the configuration is properly done, you can able to see the<strong> ClusterRole, ServiceAccount, and Namespace<\/strong> names in the details of the ClusterRoleBinding.<\/p>\n<h2 id=\"create-a-prometheus-custom-resource\"><strong>Create a Prometheus Custom Resource<\/strong><\/h2>\n<p>Now, we need to create the Prometheus Custom Resources and also add the information about the <strong>ServiceAccount<\/strong> and the <strong>ServiceMonitor<\/strong>.<\/p>\n<p>Create a configuration file to deploy the Prometheus Custom Resource<strong> <\/strong><code>Prometheus-cr.yaml<\/code><\/p>\n<pre><code>apiVersion: monitoring.coreos.com\/v1\nkind: Prometheus\nmetadata:\n  name: prometheus\nspec:\n  serviceAccountName: prometheus-operator-svc-ac\n  serviceMonitorSelector:\n    matchLabels:\n      team: frontend\n  resources:\n    requests:\n      memory: 400Mi\n  enableAdminAPI: false<\/code><\/pre>\n<p>In this configuration, I am providing the value for the <code>spec.serviceMonitorSelector.matchLabels <\/code>is the label of the ServiceMonitor Object that we created earlier.<\/p>\n<p>This is how the Prometheus grabs the target details with the help of the<strong> ServiceMonitor Custom Resource<\/strong><\/p>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f prometheus-cr.yaml<\/code><\/pre>\n<p>To list the Prometheus object.<\/p>\n<pre><code>kubectl get prometheus<\/code><\/pre>\n<p>I want to access<strong> <\/strong>Prometheus over the internet, so I am creating a service with <strong>nodePort<\/strong>. Create a service file <code>prometheus-cr-svc.yaml<\/code><\/p>\n<pre><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: prometheus\nspec:\n  type: NodePort\n  ports:\n  - name: web\n    nodePort: 30900\n    port: 9090\n    protocol: TCP\n    targetPort: web\n  selector:\n    prometheus: prometheus<\/code><\/pre>\n<p>To deploy this service, use the following command.<\/p>\n<pre><code>kubectl apply -f prometheus-cr-svc.yaml<\/code><\/pre>\n<p>List the services to ensure they are running and note down the <strong>nodePort<\/strong> number.<\/p>\n<p>Open any browser and paste any of the instance&#8217;s public IPs and the port number, and then you will get this same output.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/untitled-1.png\" class=\"kg-image\" alt=\"prometheus dashboard\n\" loading=\"lazy\" width=\"1184\" height=\"1125\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/untitled-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/untitled-1.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/untitled-1.png 1184w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here, we can see three Pods have been monitored because I gave three replicas for the application. ServiceMonitor got the endpoint information of the three of them as well, and Prometheus got it from the ServiceMonitor<strong>.<\/strong><\/p>\n<p>If the Pods dont&#8217; have service, we can use the <strong>PodMonitor Custom Resource <\/strong>to monitor them directly.<\/p>\n<h2 id=\"create-alertmanagerconfig-custom-resource\"><strong>Create AlertmanagerConfig Custom Resource<\/strong><\/h2>\n<p>We need Alertmanager to send the notifications to the receiver based on the Prometheus rules<strong>.<\/strong><\/p>\n<p>But before that, we need to create the <strong>AlertmanagerConfig<\/strong> Custom Resource with the routing and receiver information.<\/p>\n<p>Create a manifest for the <strong>AlertmanagerConfig<\/strong> Object <code>alertmanager-config-cr.yaml<\/code><\/p>\n<pre><code>apiVersion: monitoring.coreos.com\/v1alpha1\nkind: AlertmanagerConfig\nmetadata:\n  name: config-example\n  labels:\n    alertmanagerConfig: example\nspec:\n  route:\n    groupBy: ['job']\n    groupWait: 30s\n    groupInterval: 5m\n    repeatInterval: 12h\n    receiver: 'webhook'\n  receivers:\n  - name: 'webhook'\n    webhookConfigs:\n    - url: 'http:\/\/example.com\/'<\/code><\/pre>\n<p>To deploy this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f alertmanager-config-cr.yaml<\/code><\/pre>\n<p>To list the <strong>AlertmanagerConfig<\/strong> object.<\/p>\n<pre><code>kubectl get alertmanager<\/code><\/pre>\n<p>AlertmanagerConfig contains the configuration information for Alertmanager.<\/p>\n<h2 id=\"create-alertmanager-custom-resource\"><strong>Create Alertmanager Custom Resource<\/strong><\/h2>\n<p>Create a manifest for the <strong>Alertmanager<\/strong> Object <code>alertmanager-cr.yaml<\/code><strong> <\/strong>and add the following contents.<\/p>\n<pre><code>apiVersion: monitoring.coreos.com\/v1\nkind: Alertmanager\nmetadata:\n  name: example\nspec:\n  replicas: 3\n  alertmanagerConfigSelector:\n    matchLabels:\n      alertmanagerConfig: example<\/code><\/pre>\n<p>Here, you can see that <code>spec.alertmanagerConfigSelector<\/code> pointing to the <strong>AlertmanagerConfig <\/strong>Custom Resource labels.<\/p>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f alertmanager-cr.yaml<\/code><\/pre>\n<p>To view the Alertmanager Custom Resource.<\/p>\n<pre><code>kubectl get alertmanager<\/code><\/pre>\n<p>I am creating a service for the <strong>Alertmanager Custom Resource<\/strong> to access it over the internet.<\/p>\n<p>Create a service file <code>alertmanager-cr-svc.yaml<\/code><\/p>\n<pre><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: alertmanager-example\nspec:\n  type: NodePort\n  ports:\n  - name: web\n    nodePort: 30903\n    port: 9093\n    protocol: TCP\n    targetPort: web\n  selector:\n    alertmanager: example<\/code><\/pre>\n<p>To apply this configuration, use the following command.<\/p>\n<pre><code>kubectl apply -f alertmanager-cr-svc.yaml<\/code><\/pre>\n<p>Now, we can access the Alertmanager dashboard over the internet, but before that, ensure the Pod is running properly.<\/p>\n<p>To access the dashboard, we need the <strong>nodePort<\/strong> number <code>30903<\/code> and the <strong>Public IP<\/strong> of any one of the instances.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/untitled-1-2.png\" class=\"kg-image\" alt=\"prometheus alertmanager alerts\" loading=\"lazy\" width=\"1208\" height=\"1125\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/untitled-1-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/untitled-1-2.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/untitled-1-2.png 1208w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Initially, when we deployed the <strong>Prometheus Custom Resource<\/strong>, didn&#8217;t mention anything about the <strong>Alertmanager,<\/strong> so now, we need to make some changes in the existing Prometheus configuration file <code>prometheus-cr.yaml.<\/code><\/p>\n<pre><code>apiVersion: monitoring.coreos.com\/v1\nkind: Prometheus\nmetadata:\n  name: prometheus\nspec:\n  serviceAccountName: prometheus-operator-svc-ac\n\n  replicas: 2\n\n  alerting:\n    alertmanagers:\n    - namespace: default\n      name: alertmanager-example\n      port: web\n\n  serviceMonitorSelector:\n    matchLabels:\n      team: frontend\n  resources:\n    requests:\n      memory: 400Mi\n  enableAdminAPI: false<\/code><\/pre>\n<p>Now, we have to redeploy this manifest to update the changes, and this modification will not affect the existing setup.<\/p>\n<pre><code>kubectl apply -f prometheus-cr.yaml<\/code><\/pre>\n<p>If we check the Prometheus dashboard now, we can see the Alertmanager information in the dashboard.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/untitled-3-1.png\" class=\"kg-image\" alt=\"prometheus alertmanager status\" loading=\"lazy\" width=\"1209\" height=\"1125\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/untitled-3-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/untitled-3-1.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/untitled-3-1.png 1209w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h2 id=\"advantages-of-prometheus-operator\"><strong>Advantages Of Prometheus Operator<\/strong><\/h2>\n<p>Here are the few advantages of Prometheus Operator.<\/p>\n<ol>\n<li>If you are fed up with the manual integration of the Prometheus in the Kubernetes, you can use the operators because the setup process is really easy.<\/li>\n<li>In the manual configuration, you might face some inconsistencies if you are working in multiple clusters, but if you are using operators, then the Custom Resource Definition (CRD) will ensure consistency across the cluster.<\/li>\n<li>Manual configuration modification is complex if you are required to handle the scaling process in the Prometheus stack, but the operators will simplify the process and automate the job.<\/li>\n<li>Integrating other components, such as Alertmanager and Grafana, is also easy when compared to manual integration, and you will not be confused about the configurations because the Prometheus manifests are the same as the Kubernetes native objects manifest.<\/li>\n<\/ol>\n<h2 id=\"conclusion\"><strong>Conclusion<\/strong><\/h2>\n<p>I have tried this setup to learn how to configure the <strong>Prometheus Custom Resource. <\/strong>I have also done a test setup to explain the concept, but you can do more in the configuration segment.<\/p>\n<p>Also, try the other Custom Resources such as PodMonitor, Probe, ThanosRuler, etc.<\/p>\n<p>Know about their use cases and implement them if your requirements need them. You can also create your custom resources if you want.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/setup-prometheus-operator\/\" target=\"_blank\" rel=\"noopener noreferrer\">How to Setup Prometheus Operator on Kubernetes \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/setup-prometheus-operator\/<\/p>\n","protected":false},"author":1,"featured_media":821,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-820","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/820","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=820"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/820\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/821"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=820"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=820"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=820"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}