{"id":30967,"date":"2026-03-17T15:29:23","date_gmt":"2026-03-17T09:59:23","guid":{"rendered":"https:\/\/opstree.com\/blog\/?p=30967"},"modified":"2026-03-17T15:29:38","modified_gmt":"2026-03-17T09:59:38","slug":"automate-node-exporter-ansible","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2026\/03\/17\/automate-node-exporter-ansible\/","title":{"rendered":"Automating Node Exporter and VMagent Deployment with Ansible"},"content":{"rendered":"<div style=\"background: #f8fafc; padding: 18px; border: 1px solid #e2e8f0; border-radius: 6px; font-family: Inter, Arial, sans-serif; margin: 20px 0;\">\n<h2 style=\"margin-top: 0; font-size: 18px;\">Table of Contents<\/h2>\n<ol style=\"margin: 0; padding-left: 18px; line-height: 1.7; font-size: 14px;\">\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#introduction\">Introduction<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#why-use-ansible-monitoring\">Why Use Ansible for Monitoring Setup<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#core-idea-setup\">Core Idea of This Setup<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#components-installed\">Components Installed<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#project-structure\">Project Structure<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#how-to-use-setup\">How to Use This Setup<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#why-approach-works\">Why This Approach Works Well<\/a><\/li>\n<li><a style=\"text-decoration: none; color: #2563eb;\" href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ol>\n<\/div>\n<h2 id=\"introduction\">Introduction<\/h2>\n<p>Keeping your infrastructure healthy means keeping a close eye on it\u2014and that is where monitoring tools like Node Exporter and VictoriaMetrics VMagent come in. They are great at collecting and shipping system metrics from your servers, but here is the catch: installing and configuring them manually across dozens of machines is tedious, messy, and frankly, a recipe for inconsistency. That is where automation saves the day. In this guide, we will walk through how to use <a href=\"https:\/\/opstree.com\/blog\/2022\/10\/18\/understanding-ansible-helm-diff-plugin\/\" target=\"_blank\" rel=\"noopener\">Ansible<\/a> to deploy Node Exporter and VMagent cleanly and reliably, following best practices that are ready for real-world production environments.<!--more--><\/p>\n<h2 id=\"why-use-ansible-monitoring\">Why Use Ansible for Monitoring Setup<\/h2>\n<p>Using Ansible provides several advantages:<\/p>\n<ul>\n<li>No manual installation on servers<\/li>\n<li>Consistent configuration across all environments<\/li>\n<li>Easy to reuse the same setup for multiple projects<\/li>\n<li>Clean separation between configuration and dependencies<\/li>\n<\/ul>\n<p>Most importantly, this approach ensures that roles are not permanently stored on the system but are downloaded dynamically at runtime.<\/p>\n<div style=\"border: 1px solid #d1d5db; padding: 16px; margin: 20px 0; background-color: #f0f4f8;\">\n<p style=\"margin: 0; font-weight: 600; font-size: 16px;\">\u00a0<strong data-start=\"89\" data-end=\"225\">Are you looking for the best <a href=\"https:\/\/opstree.com\/services\/database-and-data-engineering\/\" target=\"_blank\" rel=\"noopener\">data engineering solutions provider<\/a> in India?<\/strong><\/p>\n<\/div>\n<h2 id=\"core-idea-setup\">Core Idea of This Setup<\/h2>\n<p>The key principles followed in this setup are:<\/p>\n<ul>\n<li>Do NOT store roles permanently on your system<\/li>\n<li>Declare only role dependencies<\/li>\n<li>Download roles on-demand from <a href=\"https:\/\/opstree.com\/blog\/2024\/11\/18\/guide-to-implementing-gitops-with-argocd\/\" target=\"_blank\" rel=\"noopener\">Git repositories<\/a><\/li>\n<li>Keep the local system lightweight and clean<\/li>\n<\/ul>\n<p>All required roles and dependencies are fetched automatically when the playbook is executed.<\/p>\n<h2 id=\"components-installed\">Components Installed<\/h2>\n<h3>Node Exporter<\/h3>\n<ul>\n<li>Exposes <a href=\"https:\/\/opstree.com\/blog\/2021\/08\/24\/proc-file-system-in-linux\/\" target=\"_blank\" rel=\"noopener\">Linux<\/a> system metrics such as CPU, memory, disk, and network<\/li>\n<li>Runs as a systemd service<\/li>\n<li>Metrics are available on port 9100<\/li>\n<li>Used by monitoring systems like VictoriaMetrics or Prometheus<\/li>\n<\/ul>\n<h3>VMagent<\/h3>\n<ul>\n<li>Lightweight metrics collection agent from VictoriaMetrics<\/li>\n<li>Scrapes metrics from Node Exporter<\/li>\n<li>Pushes metrics to a remote VictoriaMetrics server<\/li>\n<li>Optimized for low CPU and memory usage<\/li>\n<\/ul>\n<div style=\"border: 1px solid #d1d5db; padding: 16px; margin: 20px 0; background-color: #f0f4f8;\">\n<p style=\"margin: 0; font-weight: 600; font-size: 16px;\">Also Read &#8211; <a href=\"https:\/\/opstree.com\/blog\/2022\/10\/18\/understanding-ansible-helm-diff-plugin\/\" target=\"_blank\" rel=\"noopener\">Understanding the Ansible Helm Diff Plugin for Kubernetes Deployments<\/a><\/p>\n<\/div>\n<h2 id=\"project-structure\">Project Structure<\/h2>\n<p>This setup intentionally uses only two files, keeping everything simple, readable, and production-ready.<\/p>\n<h3><strong>Playbook.yml \u2013 What Gets Installed<\/strong><\/h3>\n<p>The playbook.yml file defines<\/p>\n<ul>\n<li>Target hosts<\/li>\n<li>Required privileges<\/li>\n<li>Configuration variables<\/li>\n<li>Which roles should be executed<\/li>\n<\/ul>\n<p><strong>Configuration Like this<\/strong><\/p>\n<pre style=\"background: #0f172a; color: #e5e7eb; padding: 16px; border-radius: 8px; font-size: 13px; line-height: 1.6; overflow-x: auto; max-width: 100%;\">---\r\n- hosts: all\r\n  become: true\r\n  gather_facts: true\r\n\r\n  vars:\r\n    bare_metal: false\r\n    dc: \"{{ dc | default('default_dc') }}\"\r\n    env: \"{{ env | default('default_env') }}\"\r\n    owner: default_owner\r\n    node_exporter_version: \"1.8.2\"\r\n    vmagent_remote_write_url: \"{{ remote_write_url }}\"\r\n    vminsert_ip: \"34.68.92.89\"\r\n    vminsert_hostname: \"vminsert.k8s.opstree.dev\"\r\n\r\n    vmagent_scrape_config:\r\n      global:\r\n        scrape_interval: 15s\r\n        external_labels:\r\n          bare_metal: \"{{ bare_metal }}\"\r\n          dc: \"{{ dc }}\"\r\n          env: \"{{ env }}\"\r\n          owner: \"{{ owner }}\"\r\n      scrape_configs:\r\n        - job_name: node_exporter\r\n          static_configs:\r\n            - targets:\r\n                - \"localhost:9100\"\r\n              labels:\r\n                service: node_exporter\r\n\r\n  pre_tasks:\r\n    - name: Add vminsert host entry in \/etc\/hosts\r\n      lineinfile:\r\n        path: \/etc\/hosts\r\n        line: \"{{ vminsert_ip }} {{ vminsert_hostname }}\"\r\n        state: present\r\n        create: false\r\n\r\n  roles:\r\n    - role: node-exporters\r\n    - role: Vmagent\r\n<\/pre>\n<h5>\u00a0What This Playbook Does<\/h5>\n<ul>\n<li>Runs on all target hosts<\/li>\n<li>Uses privilege escalation (become: true)<\/li>\n<li>Installs Node Exporter and VMagent<\/li>\n<li>Configures metric scraping and remote write automatically<\/li>\n<\/ul>\n<h3>requirements.yml \u2013 Role Dependencies<\/h3>\n<p>The requirements.yml file defines where the roles are downloaded from<\/p>\n<pre style=\"background: #0f172a; color: #e5e7eb; padding: 16px; border-radius: 8px; font-size: 13px; line-height: 1.6; overflow-x: auto; max-width: 100%;\">roles:\r\n\r\n  - name: node_exporter\r\n    src: https:\/\/github.com\/geerlingguy\/ansible-role-node_exporter.git\r\n    scm: git\r\n    version: master\r\n\r\ncollections:\r\n  - name: https:\/\/github.com\/VictoriaMetrics\/ansible-playbooks.git\r\n<\/pre>\n<pre style=\"background: #0f172a; color: #e5e7eb; padding: 16px; border-radius: 8px; font-size: 13px; line-height: 1.6; overflow-x: auto; max-width: 100%;\">type: git\r\nversion: master\r\n<\/pre>\n<h5>\u00a0Why This File Is Important<\/h5>\n<ul>\n<li>Roles are fetched directly from GitHub<\/li>\n<li>No manual role installation required<\/li>\n<li>Ensures the same role versions across all environments<\/li>\n<\/ul>\n<div style=\"border: 1px solid #d1d5db; padding: 16px; margin: 20px 0; background-color: #f0f4f8;\">\n<p style=\"margin: 0; font-weight: 600; font-size: 16px;\">Also Read &#8211; <a href=\"https:\/\/opstree.com\/blog\/2020\/03\/24\/ansible-directory-structure-default-vs-vars\/\">Ansible Directory Structure Explained: Defaults vs Vars (Best Practices &amp; Examples)<\/a><\/p>\n<\/div>\n<h2 id=\"how-to-use-setup\">How to Use This Setup<\/h2>\n<h3>Step 1: Install Role Dependencies<\/h3>\n<pre style=\"background: #0f172a; color: #e5e7eb; padding: 16px; border-radius: 8px; font-size: 13px; line-height: 1.6; overflow-x: auto; max-width: 100%;\">ansible-galaxy install -r requirements.yml\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-30969\" src=\"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144108.png\" alt=\"\" width=\"609\" height=\"213\" srcset=\"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144108.png 609w, https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144108-300x105.png 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/p>\n<p>By default, roles are downloaded into<\/p>\n<pre style=\"background: #0f172a; color: #e5e7eb; padding: 16px; border-radius: 8px; font-size: 13px; line-height: 1.6; overflow-x: auto; max-width: 100%;\">~\/. ansible\/roles\/\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-30970\" src=\"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144119.png\" alt=\"\" width=\"601\" height=\"72\" srcset=\"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144119.png 601w, https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144119-300x36.png 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/p>\n<h3>Step 2: Run the Playbook<\/h3>\n<pre style=\"background: #0f172a; color: #e5e7eb; padding: 16px; border-radius: 8px; font-size: 13px; line-height: 1.6; overflow-x: auto; max-width: 100%;\">ANSIBLE_ROLES_PATH= ~\/. ansible\/roles ansible-playbook playbook.yml \r\n-e remote_write_url =\"https:\/\/vminsert.k8s.opstree.dev\/insert\/0\/prometheus\/api\/v1\/write\" \\ \r\n- e env=testing \\ \r\n-e dc= hanuman \\\r\n--ask-become-pass\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-30972\" src=\"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144142.png\" alt=\"\" width=\"608\" height=\"173\" srcset=\"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144142.png 608w, https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-17-144142-300x85.png 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/p>\n<ul>\n<li>This command sets the ANSIBLE_ROLES_PATH to locate the downloaded roles and runs the playbook.yml.<\/li>\n<li>Runtime variables like remote_write_url, env, and dc are passed using -e, while &#8211;ask-become-pass enables sudo access during execution<\/li>\n<\/ul>\n<h2 id=\"why-approach-works\">Why This Approach Works Well<\/h2>\n<ul>\n<li>Minimalistic \u2013 only two files<\/li>\n<li>Reusable \u2013 roles can be reused across projects<\/li>\n<li>Clean \u2013 no unnecessary files on the system<\/li>\n<li>Production-ready \u2013 follows Ansible best practices<\/li>\n<\/ul>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>By using Ansible in this structured way, you can build a clean, scalable, and maintainable monitoring setup. Separating playbook logic from role dependencies keeps the system simple and easy to manage while remaining fully production ready.<\/p>\n<h2>Related Solutions<\/h2>\n<ul>\n<li><a href=\"https:\/\/buildpiper.io\/kubeops-kubernetes-management\/\" target=\"_blank\" rel=\"noopener\">kubernetes cluster management tools<\/a><\/li>\n<li><a href=\"https:\/\/opstree.com\/services\/cloud-engineering-modernisation-migrations\/\" target=\"_blank\" rel=\"noopener\">Cloud Engineering Services<\/a><\/li>\n<li><a href=\"https:\/\/opstree.com\/aws-consulting-services\/\" target=\"_blank\" rel=\"noopener\">AWS Consulting Services<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Table of Contents Introduction Why Use Ansible for Monitoring Setup Core Idea of This Setup Components Installed Project Structure How to Use This Setup Why This Approach Works Well Conclusion Introduction Keeping your infrastructure healthy means keeping a close eye on it\u2014and that is where monitoring tools like Node Exporter and VictoriaMetrics VMagent come in. &hellip; <a href=\"https:\/\/opstree.com\/blog\/2026\/03\/17\/automate-node-exporter-ansible\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Automating Node Exporter and VMagent Deployment with Ansible&#8221;<\/span><\/a><\/p>\n","protected":false},"author":244582724,"featured_media":30974,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[610],"tags":[768739304,28644656,768739285,768739625,343865,768739624],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2026\/03\/Untitled-design-7.png","jetpack_likes_enabled":false,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-83t","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/30967"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/244582724"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=30967"}],"version-history":[{"count":5,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/30967\/revisions"}],"predecessor-version":[{"id":30978,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/30967\/revisions\/30978"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/30974"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=30967"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=30967"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=30967"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}