<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ABIGAIL MOJUME</title>
    <description>The latest articles on Forem by ABIGAIL MOJUME (@abigailmojume).</description>
    <link>https://forem.com/abigailmojume</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1366253%2Fb27be74a-3af3-41d3-9c75-153f86d6ac3c.jpeg</url>
      <title>Forem: ABIGAIL MOJUME</title>
      <link>https://forem.com/abigailmojume</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/abigailmojume"/>
    <language>en</language>
    <item>
      <title>Building an Automated Monitoring Pipeline with Prometheus, Grafana, and cAdvisor</title>
      <dc:creator>ABIGAIL MOJUME</dc:creator>
      <pubDate>Mon, 24 Nov 2025 16:37:20 +0000</pubDate>
      <link>https://forem.com/abigailmojume/building-an-automated-monitoring-pipeline-with-prometheus-grafana-and-cadvisor-32hi</link>
      <guid>https://forem.com/abigailmojume/building-an-automated-monitoring-pipeline-with-prometheus-grafana-and-cadvisor-32hi</guid>
      <description>&lt;p&gt;&lt;em&gt;How I automated infrastructure monitoring deployment using GitHub Actions, Docker Compose, and container metrics&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;In today's world, monitoring is essential. We need to track CPU, memory, disk, network and  metrics to understand system performance. Additionally, monitoring request volumes, response times, and error rates helps identify issues before they impact users.&lt;/p&gt;

&lt;p&gt;But here's the challenge: manually setting up monitoring infrastructure every time your code is successfully deployed is time-consuming and error-prone. What if you could automatically deploy your entire monitoring stack whenever new code gets deployed?&lt;/p&gt;

&lt;p&gt;That's exactly what I built—an automated monitoring pipeline that deploys Prometheus, Grafana, and cAdvisor as the final step in our deployment process.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: A Three-Part Pipeline
&lt;/h2&gt;

&lt;p&gt;Our complete CI/CD pipeline consists of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code Quality Check&lt;/strong&gt; (SonarQube) - Ensures code meets quality standards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Deployment&lt;/strong&gt; - Deploys the application to production servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring Setup&lt;/strong&gt; (this article) - Automatically deploys monitoring infrastructure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When code passes quality checks and deploys successfully, the monitoring pipeline triggers automatically, ensuring our newly deployed application is immediately observable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;Here's what we're building:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dev-prometheus-monitoring
    ├── prometheus.yml          # Monitoring configuration
    ├── docker-compose.yml      # Container orchestration
    ├── monitor.env            # Environment variables
    └── .github/workflows/
        └── deploy-monitoring.yml   # Automation workflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus&lt;/strong&gt;: Collects and stores metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafana&lt;/strong&gt;: Visualizes metrics in dashboards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cAdvisor&lt;/strong&gt;: Exposes metrics about container&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis&lt;/strong&gt;: Stores historical data for cAdvisor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt;: Automates deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt;: Orchestrates all containers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why cAdvisor for Container Monitoring?
&lt;/h2&gt;

&lt;p&gt;For containerized environments, cAdvisor provides critical insights that traditional system monitors can't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-container resource usage&lt;/strong&gt;: See exactly which container is consuming resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container-specific metrics&lt;/strong&gt;: CPU, memory, network, and filesystem usage for each container&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time visibility&lt;/strong&gt;: Track container performance as workloads scale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker integration&lt;/strong&gt;: Native understanding of Docker containers and their lifecycles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it ideal for microservices architectures where multiple containers run on the same host.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Setting Up Your Workspace
&lt;/h2&gt;

&lt;p&gt;I created a dedicated directory for this project on the VM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;dev-prometheus-monitoring
&lt;span class="nb"&gt;cd &lt;/span&gt;dev-prometheus-monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Configuring Prometheus
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;prometheus.yml&lt;/code&gt; - this tells Prometheus what to monitor and how often:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scrape_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;      &lt;span class="c1"&gt;# Collect metrics every 15 seconds&lt;/span&gt;
  &lt;span class="na"&gt;evaluation_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;   &lt;span class="c1"&gt;# Evaluate alerting rules every 15 seconds&lt;/span&gt;

&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Monitor Prometheus itself&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nvs-prometheus'&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;localhost:9090'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# Monitor Docker containers via cAdvisor&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nvs-vm'&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cadvisor:8080'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Understanding the config:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;scrape_interval&lt;/strong&gt;: How frequently Prometheus pulls metrics. 15 seconds balances real-time visibility with resource usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;job_name&lt;/strong&gt;: Logical grouping of similar targets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;targets&lt;/strong&gt;: Specific endpoints exposing metrics in the format &lt;code&gt;host:port&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;nvs-vm&lt;/code&gt; job scrapes cAdvisor, which exposes metrics for all Docker containers running on the host.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Creating the Docker Compose File
&lt;/h2&gt;

&lt;p&gt;Docker Compose allows us to define and run multiple containers with a single command. Create &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prom/prometheus:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9090:9090"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./prometheus.yml:/etc/prometheus/prometheus.yml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;prometheus-data:/prometheus&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--config.file=/etc/prometheus/prometheus.yml'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--storage.tsdb.path=/prometheus'&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cadvisor&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;grafana&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana/grafana:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;grafana-data:/var/lib/grafana&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/home/administrator/Desktop/workspace/dev-prometheus-monitoring/monitor.env&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;cadvisor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcr.io/cadvisor/cadvisor:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cadvisor&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/:/rootfs:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run:/var/run:rw&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/sys:/sys:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/lib/docker/:/var/lib/docker:ro&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6379:6379"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;prometheus-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;grafana-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;monitoring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Environment Configuration
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;monitor.env&lt;/code&gt; to store Grafana configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;GF_SECURITY_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_secure_password
&lt;span class="nv"&gt;GF_SERVER_ROOT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://your-server-ip:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps sensitive configuration separate from the docker-compose file and makes it easy to change settings without modifying the main configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Version Control Setup
&lt;/h2&gt;

&lt;p&gt;Initialize Git and push to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add prometheus.yml docker-compose.yml monitor.env
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial monitoring setup"&lt;/span&gt;
git remote add origin https://github.com/yourusername/dev-prometheus-monitoring.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;.gitignore&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_actions/
*.log
.DS_Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why ignore &lt;code&gt;_actions/&lt;/code&gt;?&lt;/strong&gt; This directory contains the self-hosted runner files (explained next), which are large and system-specific.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Setting Up Self-Hosted GitHub Actions Runner
&lt;/h2&gt;

&lt;p&gt;Since we're working with on-premise servers, we need a self-hosted runner that can access our internal network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your GitHub repository&lt;/li&gt;
&lt;li&gt;Navigate to Settings → Actions → Runners&lt;/li&gt;
&lt;li&gt;Click "New self-hosted runner"&lt;/li&gt;
&lt;li&gt;Follow the provided commands on your Linux VM:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Download the runner&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;actions-runner &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;actions-runner
curl &lt;span class="nt"&gt;-o&lt;/span&gt; actions-runner-linux-x64-2.311.0.tar.gz &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
&lt;span class="nb"&gt;tar &lt;/span&gt;xzf ./actions-runner-linux-x64-2.311.0.tar.gz

&lt;span class="c"&gt;# Configure the runner&lt;/span&gt;
./config.sh &lt;span class="nt"&gt;--url&lt;/span&gt; https://github.com/yourusername/dev-prometheus-monitoring &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--token&lt;/span&gt; YOUR_TOKEN

&lt;span class="c"&gt;# Start the runner&lt;/span&gt;
./run.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production, install it as a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./svc.sh &lt;span class="nb"&gt;install
sudo&lt;/span&gt; ./svc.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why self-hosted?&lt;/strong&gt; GitHub-hosted runners can't access on-premise servers. Our self-hosted runner bridges the gap between GitHub (cloud) and our infrastructure (on-premise).&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Adding GitHub Secrets
&lt;/h2&gt;

&lt;p&gt;Store sensitive credentials securely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to repository Settings → Secrets and variables → Actions&lt;/li&gt;
&lt;li&gt;Add these secrets:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GH_USERNAME&lt;/code&gt;: Your GitHub username&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GH_TOKEN&lt;/code&gt;: Personal access token for GitHub authentication&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These will be used to authenticate when cloning the repository during deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 8: Creating the Automation Workflow
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/deploy-monitoring.yml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-monitoring-solution&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;deploy-monitoring&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy-prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Prometheus Stack&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self-hosted&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;server-76"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout orchestrator repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Prometheus repo&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/administrator/Desktop/DevOps/dev-prometheus-monitoring&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;rm -rf dev-prometheus-monitoring&lt;/span&gt;
          &lt;span class="s"&gt;git clone https://${{ secrets.GH_USERNAME }}:${{ secrets.GH_TOKEN }}@github.com/technotrending/dev-prometheus-monitoring.git -b main&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker images&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/administrator/Desktop/workspace/dev-prometheus-monitoring&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;docker compose up -d&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cleanup old images&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;docker image prune -af&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro tip I learned:&lt;/strong&gt; Use &lt;code&gt;mkdir -p .github/workflows&lt;/code&gt; to create nested directories in one command. The &lt;code&gt;-p&lt;/code&gt; flag creates parent directories automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Understanding the workflow:&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Trigger
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;deploy-monitoring&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow is triggered by the deployment pipeline. After your application successfully deploys, the deployment workflow sends a &lt;code&gt;repository_dispatch&lt;/code&gt; event to trigger this monitoring setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Checkout orchestrator repo&lt;/strong&gt;: Downloads the workflow repository&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clone Prometheus repo&lt;/strong&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Navigates to the DevOps directory
- Removes old copy if it exists
- Clones fresh configuration from GitHub
- Uses secrets for authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build Docker images&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Changes to the workspace directory
- Runs `docker compose up -d` to start all containers
- The `-d` flag runs them in detached mode (background)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cleanup old images&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Removes unused Docker images to save disk space
- Keeps the system clean after updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  Step 9: Integrating with the Deployment Pipeline
&lt;/h2&gt;

&lt;p&gt;In your application deployment workflow, add this step at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Trigger monitoring deployment&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success()&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;curl -X POST \&lt;/span&gt;
      &lt;span class="s"&gt;-H "Accept: application/vnd.github.v3+json" \&lt;/span&gt;
      &lt;span class="s"&gt;-H "Authorization: token ${{ secrets.GH_PAT }}" \&lt;/span&gt;
      &lt;span class="s"&gt;https://api.github.com/repos/yourusername/dev-prometheus-monitoring/dispatches \&lt;/span&gt;
      &lt;span class="s"&gt;-d '{"event_type":"deploy-monitoring"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SonarQube checks pass ✓&lt;/li&gt;
&lt;li&gt;Application deploys successfully ✓&lt;/li&gt;
&lt;li&gt;Deployment workflow sends &lt;code&gt;repository_dispatch&lt;/code&gt; event&lt;/li&gt;
&lt;li&gt;Monitoring workflow triggers automatically&lt;/li&gt;
&lt;li&gt;Prometheus, Grafana, cAdvisor, and Redis deploy&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 10: Verifying the Setup
&lt;/h2&gt;

&lt;p&gt;Once deployed, access your monitoring stack:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prometheus UI: &lt;code&gt;http://your-server-ip:9090&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to Status → Targets&lt;/li&gt;
&lt;li&gt;Both targets should show "UP" status:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nvs-prometheus&lt;/code&gt; (localhost:9090)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nvs-vm&lt;/code&gt; (cadvisor:8080)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Grafana UI: &lt;code&gt;http://your-server-ip:3000&lt;/code&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Login with credentials from &lt;code&gt;monitor.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add Prometheus as a data source:

&lt;ul&gt;
&lt;li&gt;Go to Configuration → Data Sources&lt;/li&gt;
&lt;li&gt;Add Prometheus&lt;/li&gt;
&lt;li&gt;URL: &lt;code&gt;http://prometheus:9090&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click "Save &amp;amp; Test"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  cAdvisor UI: &lt;code&gt;http://your-server-ip:8080&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Browse container metrics directly&lt;/li&gt;
&lt;li&gt;View real-time CPU, memory, and network usage per container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjp7c1vwj361pyb32ezh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjp7c1vwj361pyb32ezh.jpg" alt="An image depicting healthy targets for cAdvisor and Prometheus on the Prometheus dashboard" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: Prometheus dashboard showing targets metrics and health status&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Import Dashboards
&lt;/h3&gt;

&lt;p&gt;For quick visualization, import pre-built Grafana dashboards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Create → Import&lt;/li&gt;
&lt;li&gt;For Docker monitoring, use dashboard ID: &lt;strong&gt;193&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;This shows container metrics collected by cAdvisor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3c7z29s02xdol2xuq6l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3c7z29s02xdol2xuq6l.jpg" alt="Grafana dashboard" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: Grafana dashboard displaying real-time CPU usage metrics for Docker containers over a 3-hour period&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Complete Flow
&lt;/h2&gt;

&lt;p&gt;Here's what happens end-to-end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Developer commits code
   ↓
2. SonarQube validates code quality
   ↓
3. Application deploys to production
   ↓
4. Deployment workflow sends repository_dispatch
   ↓
5. Monitoring workflow triggers on self-hosted runner
   ↓
6. Runner clones latest monitoring configuration
   ↓
7. Docker Compose starts containers:
   - Redis (for data persistence)
   - cAdvisor (collects container metrics)
   - Prometheus (scrapes and stores metrics)
   - Grafana (visualizes data)
   ↓
8. Prometheus begins scraping cAdvisor every 15s
   ↓
9. Container metrics now visible in Grafana dashboards
   ↓
10. Old Docker images cleaned up automatically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This automated monitoring setup provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Immediate Visibility&lt;/strong&gt;: New deployments are monitored from the moment they start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Optimization&lt;/strong&gt;: Identify containers consuming excessive resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Tracking&lt;/strong&gt;: Historical data shows performance trends over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident Response&lt;/strong&gt;: Quickly diagnose issues by examining container metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Manual Work&lt;/strong&gt;: Monitoring deploys automatically with each application deployment&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The complete pipeline ensures that every time code is deployed, monitoring infrastructure is automatically configured to track it. This eliminates manual setup, reduces errors, and guarantees observability from the moment containers start running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://prometheus.io/docs/" rel="noopener noreferrer"&gt;Prometheus Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google/cadvisor" rel="noopener noreferrer"&gt;cAdvisor GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://grafana.com/docs/grafana/latest/getting-started/" rel="noopener noreferrer"&gt;Grafana Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions" rel="noopener noreferrer"&gt;GitHub Actions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Questions?&lt;/strong&gt; Drop them in the comments below. I'm happy to help troubleshoot or explain any part of this setup in more detail.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this helpful, please consider following me for more DevOps automation guides and infrastructure tutorials.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cicd</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
