{"id":1837,"date":"2025-07-24T09:35:00","date_gmt":"2025-07-24T06:35:00","guid":{"rendered":"https:\/\/upcloud.com\/global\/us\/resources\/tutorials\/monitoring-upcloud-prometheus-part-2\/"},"modified":"2025-07-24T09:35:00","modified_gmt":"2025-07-24T06:35:00","slug":"monitoring-upcloud-prometheus-part-2","status":"publish","type":"tutorial","link":"https:\/\/upcloud.com\/global\/resources\/tutorials\/monitoring-upcloud-prometheus-part-2\/","title":{"rendered":"Monitoring on UpCloud with Prometheus: Part 2"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">After <a href=\"https:\/\/upcloud.com\/global\/resources\/tutorials\/monitoring-upcloud-prometheus-part-1\/\">setting up Prometheus in Part 1<\/a> on a dedicated UpCloud Managed Kubernetes cluster, with support for both Kubernetes-native workloads and external VMs, you now have a flexible monitoring foundation in place. But collecting metrics is only as good as the visibility it provides. To truly understand what\u2019s happening on your virtual machines, you\u2019ll need host-level metrics like CPU usage, memory availability, and disk I\/O.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s where <a href=\"https:\/\/github.com\/prometheus\/node_exporter\" target=\"_blank\" rel=\"noopener\">Node Exporter<\/a> comes in. Node Exporter is the standard Prometheus exporter for gathering detailed system metrics from Linux servers. It runs as a lightweight daemon on each VM and exposes resource usage statistics on port 9100.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this article, you\u2019ll learn how to install Node Exporter on <a href=\"https:\/\/upcloud.com\/global\/docs\/products\/cloud-servers\/\">UpCloud Cloud Servers<\/a>, configure Prometheus to scrape these metrics, and write PromQL queries to analyze performance. By the end, you\u2019ll have a monitoring setup that gives you real-time insight into both your Kubernetes cluster and the underlying VM infrastructure.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing Node Exporter on UpCloud Cloud Server<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To collect host-level metrics like CPU, memory, and disk usage from your Cloud Server, you\u2019ll install and run the Node Exporter on each server. Node Exporter is a lightweight and efficient agent designed specifically for Prometheus, and it works on most Linux distributions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before getting started, make sure you have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>One or more UpCloud Cloud Servers running a supported OS (e.g., Ubuntu, Debian, RHEL, or CentOS).<\/li>\n\n\n\n<li>SSH access to each server.<\/li>\n\n\n\n<li>Prometheus running in your Kubernetes cluster.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">You can create a new Cloud Server quickly using <code>upctl<\/code> by running the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">upctl server create \\\n  --title \"Target Server 1\" \\\n  --zone sg-sin1 \\\n  --os \"AlmaLinux 9\" \\\n  --hostname targetserver1 \\\n  --ssh-keys key.pub \\\n  --plan DEV-1xCPU-1GB-10GB <\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Download and Install Node Exporter<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To start off, SSH into your Cloud Server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">ssh &lt;user&gt;@&lt;your-server-ip&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then, create a new system user account for your node exporter service (which you will create later):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">sudo useradd --system --shell \/bin\/false node_exporter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Next, you need to download and install the latest Node Exporter release. To do that, you will first need to install <code>tar<\/code>, the command line utility for managing archives:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">sudo dnf install tar -y<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Next, set the version of Node Exporter to download and install:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">NODE_EXPORTER_VERSION=\"1.8.1\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, use <code>curl<\/code> to download the zipped binary, <code>tar<\/code> to decompress it and move it to <code>\/user\/local\/bin<\/code>, and <code>chown<\/code> to provide the user you created earlier with the permissions to execute the binary:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">curl -fsSL https:\/\/github.com\/prometheus\/node_exporter\/releases\/download\/v${NODE_EXPORTER_VERSION}\/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz \\\n| sudo tar -zxvf - -C \/usr\/local\/bin --strip-components=1 node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64\/node_exporter \\\n&amp;&amp; sudo chown node_exporter:node_exporter \/usr\/local\/bin\/node_exporter<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Set It up as a systemd Service<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Next, create a <code>systemd<\/code> service file by running the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">sudo tee \/etc\/systemd\/system\/node_exporter.service &gt; \/dev\/null &lt;&lt;EOF\n[Unit]\nDescription=Node Exporter\n\n[Service]\nUser=node_exporter\nGroup=node_exporter\nExecStart=\/usr\/local\/bin\/node_exporter\n\n[Install]\nWantedBy=multi-user.target\nEOF<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This file defines the executable file path and the allowed users for the service. Reload the daemon and start the service by running the following commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">sudo systemctl daemon-reload\nsudo systemctl start node_exporter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can check the status of the running service with the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">sudo systemctl status node_exporter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, set up the service to start on boot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">sudo systemctl enable node_exporter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Node Exporter should now be running and listening for HTTP requests on port 9100.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Updating Prometheus Configuration to Scrape Node Exporter<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Now that Node Exporter is installed and running on at least one of your UpCloud Cloud Servers, it\u2019s time to configure Prometheus to start collecting metrics from them. In Part 1, you saw how to use a static list of target exporters in the <code>values.yaml<\/code> file of your kube-prometheus-stack deployment to scrape data from servers. In this part, you will see a dynamic, file-based service discovery system.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create the Targets File<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">First of all, you need to create a list of target IPs that you want your Prometheus operator to scrape data from. To do that, you will need to use the Kubernetes ConfigMap resource. Create a new file named <code>targets-list.yaml<\/code> and save the following contents in it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">apiVersion: v1\nkind: ConfigMap\nmetadata:\n&nbsp;&nbsp;name: scrape-file-sd-targets\n&nbsp;&nbsp;namespace: monitoring\n&nbsp;&nbsp;labels:\n&nbsp;&nbsp;&nbsp;&nbsp;prometheus: vm-monitoring\ndata:\n&nbsp;&nbsp;targets.yaml: |\n&nbsp;&nbsp;&nbsp;&nbsp;- labels:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;job: node-demo\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;targets:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- \"&lt;public ip&gt;:9100\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Make sure to replace the <code>&lt;public ip&gt;<\/code> placeholder with the public IPv4 IP of your Cloud Server. Also, please feel free to set the metadata labels for each of your targets here as you wish. These labels will be attached to all scraped metrics from the target and will help categorize and filter your metrics later.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once done, run the following command to create the config map on your Kubernetes cluster:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">kubectl apply -f targets-list.yaml<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Create a Prometheus ScrapeConfig<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Kubernetes Prometheus Operator ships with the <a href=\"https:\/\/prometheus-operator.dev\/docs\/developer\/scrapeconfig\/\" target=\"_blank\" rel=\"noopener\">ScrapeConfig CRD<\/a> that is meant to make it convenient to scrape targets external to the Kubernetes cluster. You will need to create one that collects the list of targets from your configmap and configures the Prometheus operator to scrape them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To do that, create a new file named <code>scrapeconfig.yaml<\/code> and save the following contents in it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">apiVersion: monitoring.coreos.com\/v1alpha1\nkind: ScrapeConfig\nmetadata:\n&nbsp;&nbsp;name: file-sd\n&nbsp;&nbsp;namespace: monitoring\n&nbsp;&nbsp;labels:\n&nbsp;&nbsp;&nbsp;&nbsp;prometheus: vm-monitoring\n&nbsp;&nbsp;&nbsp;&nbsp;app.kubernetes.io\/name: file-sd-scrape-config\nspec:\n&nbsp;&nbsp;fileSDConfigs:\n&nbsp;&nbsp;&nbsp;&nbsp;- files:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- \/etc\/prometheus\/configmaps\/scrape-file-sd-targets\/targets.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, you can use one of <code>spec.static_config<\/code>, <code>spec.fileSDConfigs<\/code>, and <code>spec.httpSDConfigs<\/code> to configure the method of providing the targets\u2019 information. For file-based discovery, you need to use <code>spec.fileSDConfigs<\/code> and specify the files to be used for discovering external services.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once you\u2019ve saved this file, create the <code>ScrapeConfig<\/code> resource in your cluster by running the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">kubectl apply -f scrapeconfig.yaml<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Update the Helm Installation Values<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In the <code>values.yaml<\/code> file for your Helm kube-prometheus-stack, you now need to specify the <code>scrapeConfigSelector<\/code> to specify the <code>ScrapeConfig<\/code> objects to be used by the Prometheus operator, along with the config maps that need to be mounted on it. To do that, update the <code>values.yaml<\/code> file to the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">prometheus:\n&nbsp;&nbsp;prometheusSpec:\n&nbsp;&nbsp;&nbsp;&nbsp;serviceMonitorSelectorNilUsesHelmValues: false\n&nbsp;&nbsp;&nbsp;&nbsp;ruleSelectorNilUsesHelmValues: false\n&nbsp;&nbsp;&nbsp;&nbsp;scrapeConfigSelector:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matchLabels:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prometheus: vm-monitoring\n&nbsp;&nbsp;&nbsp;&nbsp;configMaps:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- scrape-file-sd-targets<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Once done, run the <code>helm upgrade<\/code> command to update the installation with the new <code>values.yaml<\/code> file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">helm upgrade prometheus-stack prometheus-community\/kube-prometheus-stack \\&nbsp;&nbsp;\n&nbsp;&nbsp;--namespace monitoring \\\n&nbsp;&nbsp;-f values.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s it! You should now be able to visit the <code>\/targets<\/code> endpoint on your Prometheus server, and the new target should show on the targets list:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/1-target-list-prometheus-server-1024x786.png\" alt=\"-\" class=\"wp-image-59164\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This means that you have set it up correctly. In the next section, you\u2019ll learn how to use Prometheus to explore these new metrics via the web UI and PromQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Querying Metrics via Prometheus UI or API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With Node Exporter running on your UpCloud Cloud Servers and Prometheus configured to scrape their metrics, you can now start exploring system performance using <a href=\"https:\/\/prometheus.io\/docs\/prometheus\/latest\/querying\/basics\/\" target=\"_blank\" rel=\"noopener\">PromQL<\/a>, the query language built into Prometheus.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Accessing the Prometheus Web Interface<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you haven\u2019t set up an Ingress yet, you can access Prometheus locally using kubectl port-forward:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">kubectl port-forward svc\/prometheus-stack-kube-prometheus-prometheus 9090 -n monitoring<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then open your browser to: <code>http:\/\/localhost:9090<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Try Sample PromQL Queries<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Head to the \u201cGraph\u201d tab or the \u201cExpression\u201d input under \u201cTargets\u201d. Here are a few useful queries to try:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Check Node Exporter Targets<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">up{job=\"node-demo\"}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This returns the current status of all Node Exporter targets. Each result should show <code>value = 1<\/code> if the target is up and scraping successfully:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/2-check-node-exporter-targets-1024x386.png\" alt=\"-\" class=\"wp-image-59167\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">2. CPU Usage by Mode<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">rate(node_cpu_seconds_total{mode!=\"idle\", job=\"node-demo\"}[5m])<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This query shows the CPU usage rate (per mode) across all scraped servers, excluding idle time:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/3-cpu-usage-by-mode-1024x786.png\" alt=\"-\" class=\"wp-image-59170\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">3. Memory Usage Percentage<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">(1 - (node_memory_MemAvailable_bytes \/ node_memory_MemTotal_bytes)) * 100<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This query gives you a live percentage of memory used on each Cloud Server.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/4-memory-usage-percentage-1024x786.png\" alt=\"-\" class=\"wp-image-59173\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">4. Disk Usage<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">node_filesystem_size_bytes - node_filesystem_free_bytes<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This query shows raw disk usage per filesystem, which can be filtered further by device or mount point.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/5-disk-usage-1024x786.png\" alt=\"-\" class=\"wp-image-59176\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Optional: Query via the HTTP API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Prometheus also exposes a REST API you can use to programmatically fetch metrics. You can use it by appending your PromQL query as the value of the query parameter <code>query<\/code> in the <code>\/api\/v1\/query<\/code> endpoint of your Prometheus server. For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">\u279c&nbsp; upcloud-prometheus curl http:\/\/localhost:9090\/api\/v1\/query\\?query\\=up%7Bjob\\=%27node-demo%27%7D\n{\"status\":\"success\",\"data\":{\"resultType\":\"vector\",\"result\":[{\"metric\":{\"__name__\":\"up\",\"instance\":\"213.163.197.142:9100\",\"job\":\"node-demo\"},\"value\":[1751576969.348,\"1\"]}]}}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is useful if you want to integrate metrics into external tools or trigger automated responses based on system health.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using Metrics to Monitor CPU and Memory Usage<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Once Prometheus is successfully collecting metrics from Node Exporter, you can start turning that data into meaningful insights. These host-level metrics help you detect bottlenecks, track system performance over time, and respond to issues before they become outages.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Monitor CPU Load<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">CPU metrics from Node Exporter show how your Cloud Server processors are being used across different modes: user, system, idle, etc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, to get a quick view of CPU load over time, you can try the CPU usage query you saw earlier:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">rate(node_cpu_seconds_total{mode!=\"idle\", job=\"node-demo\"}[5m])<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/6-monitor-cpu-load-1024x786.png\" alt=\"-\" class=\"wp-image-59179\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This shows how much time (per second) the CPUs spend doing non-idle work, averaged over 5 minutes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To simplify this into a single metric for alerting or dashboarding, try doing an average by instance type:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">avg(rate(node_cpu_seconds_total{mode!=\"idle\", job=\"node-demo\"}[5m])) by (instance)<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/7-average-cpu-usage-per-server-instance-1024x786.png\" alt=\"-\" class=\"wp-image-59180\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This gives average CPU usage per Cloud Server instance, which can be a good way to detect overutilized servers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Monitor Memory Usage<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Node Exporter also exposes detailed memory stats. For a high-level usage percentage, you already saw a query before:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">100 * (1 - (node_memory_MemAvailable_bytes \/ node_memory_MemTotal_bytes))<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This gives you memory usage as a percentage, which you can filter by instance, environment, or any label you added in your targets file.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/8-monitor-memory-usage-1024x786.png\" alt=\"-\" class=\"wp-image-59182\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Monitor Disk Usage<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Disk space problems are often missed until they\u2019re critical. To check usage, you used this query before:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">node_filesystem_size_bytes - node_filesystem_free_bytes<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/9-monitor-disk-usage-1024x786.png\" alt=\"-\" class=\"wp-image-59184\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">To express it as a percentage, you can run the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">100 * (1 - (node_filesystem_free_bytes \/ node_filesystem_size_bytes))<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/10-monitor-disk-usage-as-percdentage-1024x786.png\" alt=\"-\" class=\"wp-image-59187\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">You can filter by mountpoint or device if needed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Set Up Basic Alerts (Optional for Now)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">While full alerting configuration will be covered in a later part of this series, it\u2019s worth thinking about thresholds now. For example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CPU usage &gt; 80% over 10 minutes<\/li>\n\n\n\n<li>Memory usage &gt; 90%<\/li>\n\n\n\n<li>Disk usage &gt; 85%<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">You can configure alerts on these later in Prometheus or Alertmanager to notify your team via email, Slack, or other channels.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this second part of the series, you\u2019ve extended your Prometheus-based monitoring setup on UpCloud to include detailed, host-level visibility into your virtual machines using Node Exporter. By installing Node Exporter on each Cloud Server, configuring Prometheus to scrape its metrics using file-based service discovery, and querying those metrics via PromQL, you\u2019ve gained real-time insights into CPU load, memory availability, and disk usage across your infrastructure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The key advantage of this setup is unification. The setup allows you to use a single Prometheus instance to monitor both your Kubernetes workloads and traditional server-based services. This eliminates silos, simplifies alerting, and prepares your monitoring system for growth as your architecture evolves.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/upcloud.com\/global\/resources\/tutorials\/monitoring-upcloud-prometheus-part-3\/\">Part 3, we\u2019ll integrate Grafana with your Prometheus deployment<\/a> to create beautiful, actionable dashboards. You\u2019ll also learn how to import ready-made dashboards for Node Exporter, customize visualizations, and begin building a visual monitoring layer that works across environments.<\/p>\n","protected":false},"author":82,"featured_media":0,"comment_status":"open","ping_status":"closed","template":"","community-category":[223,238],"class_list":["post-1837","tutorial","type-tutorial","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/1837","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/types\/tutorial"}],"author":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/users\/82"}],"replies":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/comments?post=1837"}],"version-history":[{"count":0,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/1837\/revisions"}],"wp:attachment":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/media?parent=1837"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/community-category?post=1837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}