{"id":56,"date":"2025-11-04T12:00:00","date_gmt":"2025-11-04T12:00:00","guid":{"rendered":"https:\/\/rezachegini.com\/?p=56"},"modified":"2026-10-30T06:41:57","modified_gmt":"2026-10-30T06:41:57","slug":"getting-started-with-prometheus-pushgateway","status":"publish","type":"post","link":"https:\/\/rezachegini.com\/?p=56","title":{"rendered":"Getting Started with Prometheus Pushgateway"},"content":{"rendered":"<p class=\"wp-block-paragraph\">This post explains what Prometheus Pushgateway is, when to use it, how to install it, and how to push metrics from Python. It&#8217;s a simple guide for beginners in DevOps and monitoring.<\/p>\n<h3 class=\"wp-block-heading\">1) What is Pushgateway and Why Use It<\/h3>\n<p class=\"wp-block-paragraph\">Prometheus normally pulls metrics from applications and exporters. But sometimes, scraping directly is not possible. Pushgateway is a small service that lets applications push their metrics to it. Prometheus then scrapes those metrics from Pushgateway.<\/p>\n<p class=\"wp-block-paragraph\">You need Pushgateway when:<\/p>\n<ul class=\"wp-block-list\"><li>Your jobs are short-lived (cron jobs, backup scripts) and finish before Prometheus can scrape them.<\/li><li>Your application is not reachable (behind a load balancer or firewall).<\/li><li>You want to report results after a job finishes.<\/li><\/ul>\n<p class=\"wp-block-paragraph\">It works as a bridge between your short jobs and Prometheus.<\/p>\n<h3 class=\"wp-block-heading\">2) When to Use Pushgateway<\/h3>\n<p class=\"wp-block-paragraph\">Use Pushgateway for:<\/p>\n<ul class=\"wp-block-list\"><li>Batch or cron jobs that run briefly and then exit.<\/li><li>Jobs behind restricted networks or private servers.<\/li><li>Scripts that finish quickly and cannot expose \/metrics while running.<\/li><\/ul>\n<p class=\"wp-block-paragraph\">Avoid using it for:<\/p>\n<ul class=\"wp-block-list\"><li>Long-running applications that can be scraped directly. Direct scraping is always better for performance and reliability.<\/li><\/ul>\n<h3 class=\"wp-block-heading\">3) Installing Pushgateway<\/h3>\n<h3 class=\"wp-block-heading\">Linux (Ubuntu) \u2013 systemd setup<\/h3>\n<pre class=\"wp-block-code\"><code># Download latest version (replace &lt;version&gt;)\nwget https:\/\/github.com\/prometheus\/pushgateway\/releases\/download\/v&lt;version&gt;\/pushgateway-&lt;version&gt;.linux-amd64.tar.gz\ntar xvf pushgateway-&lt;version&gt;.linux-amd64.tar.gz\ncd pushgateway-&lt;version&gt;.linux-amd64\n\n# Install\nsudo cp pushgateway \/usr\/local\/bin\/\nsudo chown prometheus:prometheus \/usr\/local\/bin\/pushgateway\n\n# Create service\nsudo tee \/etc\/systemd\/system\/pushgateway.service &gt;\/dev\/null &lt;&lt;'EOF'\n[Unit]\nDescription=Prometheus Pushgateway\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nUser=prometheus\nGroup=prometheus\nType=simple\nExecStart=\/usr\/local\/bin\/pushgateway --web.listen-address=\":9091\"\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl enable pushgateway\nsudo systemctl start pushgateway\nsudo systemctl status pushgateway<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Open your browser at:<\/p>\n<pre class=\"wp-block-code\"><code>http:\/\/localhost:9091\/metrics<\/code><\/pre>\n<p class=\"wp-block-paragraph\">You should see default metrics.<\/p>\n<h3 class=\"wp-block-heading\">4) Basic Configuration<\/h3>\n<p class=\"wp-block-paragraph\">Default settings:<\/p>\n<ul class=\"wp-block-list\"><li>Port: 9091<\/li><li>Metrics path: \/metrics<\/li><li>Same port handles both metric pushes and Prometheus scraping.<\/li><\/ul>\n<p class=\"wp-block-paragraph\">Change port example:<\/p>\n<pre class=\"wp-block-code\"><code>.\/pushgateway --web.listen-address=\":9092\"<\/code><\/pre>\n<p class=\"wp-block-paragraph\">For systemd, change the ExecStart line and restart the service:<\/p>\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl restart pushgateway<\/code><\/pre>\n<h3 class=\"wp-block-heading\">5) Connect Pushgateway to Prometheus<\/h3>\n<p class=\"wp-block-paragraph\">Edit your Prometheus configuration (prometheus.yml):<\/p>\n<pre class=\"wp-block-code\"><code>scrape_configs:\n  - job_name: 'pushgateway'\n    static_configs:\n      - targets: ['localhost:9091']<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Restart Prometheus, then open Status \u2192 Targets. If you see pushgateway as UP (green), it&#8217;s working.<\/p>\n<h3 class=\"wp-block-heading\">6) Sending Metrics from Python<\/h3>\n<h3 class=\"wp-block-heading\">Install client<\/h3>\n<pre class=\"wp-block-code\"><code>python3 -m venv pgw-demo\nsource pgw-demo\/bin\/activate\npip install prometheus_client<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Simple example<\/h3>\n<pre class=\"wp-block-code\"><code>from prometheus_client import CollectorRegistry, Gauge, push_to_gateway\nimport time\n\n# 1) Create a clean registry for this push\nregistry = CollectorRegistry()\n\n# 2) Create a gauge (can go up or down)\ng = Gauge(\n    'python_pushgateway_sample_metric',\n    'Sample metric pushed from Python to Pushgateway',\n    registry=registry\n)\n\n# 3) Set a value (here: UNIX timestamp)\ng.set(time.time())\n\n# 4) Push to Pushgateway\npush_to_gateway(\n    'localhost:9091',\n    job='python_example_job',\n    grouping_key={'instance': 'server-1'},\n    registry=registry\n)\n\nprint(\"Metric pushed successfully!\")<\/code><\/pre>\n<h3 class=\"wp-block-heading\">What each part does<\/h3>\n<p class=\"wp-block-paragraph\"><strong>CollectorRegistry()<\/strong> Makes a clean container for the metrics you want to push. This avoids sending other metrics by mistake.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Gauge(&#8230;)<\/strong> Creates a metric that represents a current value (can go up or down). We pass registry=registry so it belongs to our private registry.<\/p>\n<p class=\"wp-block-paragraph\"><strong>g.set(time.time())<\/strong> Sets the gauge to any numeric value. Here we use the UNIX timestamp just to have a real number.<\/p>\n<p class=\"wp-block-paragraph\"><strong>push_to_gateway(&#8216;localhost:9091&#8242;, job=&#8217;python_example_job&#8217;, grouping_key=&#8230;, registry=&#8230;)<\/strong> Sends your registry to Pushgateway.<\/p>\n<ul class=\"wp-block-list\"><li>job becomes a label in Prometheus (use a meaningful name like nightly_backup or disk_scan).<\/li><li>grouping_key becomes extra labels (like instance=&#8217;server-1&#8242;, env=&#8217;prod&#8217;).<\/li><li>Each push overwrites the previous metrics for the same job + grouping_key. (If you want to add instead of overwrite, Python also has pushadd_to_gateway.)<\/li><\/ul>\n<h3 class=\"wp-block-heading\">7) Understanding CollectorRegistry<\/h3>\n<ul class=\"wp-block-list\"><li>The CollectorRegistry is a container that holds your metrics.<\/li><li>The default registry collects every metric your app creates.<\/li><li>For Pushgateway, always use a custom registry to avoid conflicts and only send what you want.<\/li><\/ul>\n<pre class=\"wp-block-code\"><code>registry = CollectorRegistry()\nmy_gauge = Gauge('my_metric', 'Description', registry=registry)\npush_to_gateway('localhost:9091', job='my_job', registry=registry)<\/code><\/pre>\n<h3 class=\"wp-block-heading\">8) Best Practices<\/h3>\n<ul class=\"wp-block-list\"><li>Use Pushgateway only when needed (batch jobs, restricted apps).<\/li><li>Always create a custom registry for pushes.<\/li><li>Use clear job names like db_backup_job or file_cleaner.<\/li><li>Add stable labels (environment, instance).<\/li><li>Avoid secrets in labels or metric names.<\/li><li>Disable admin API in production for security:<\/li><li>Avoid too many unique label combinations (high cardinality).<\/li><\/ul>\n<h3 class=\"wp-block-heading\">9) Common Issues and Fixes<\/h3>\n<p class=\"wp-block-paragraph\"><strong>Metrics not visible:<\/strong> Check http:\/\/localhost:9091\/metrics. Ensure Prometheus target is UP and using the correct port.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Connection refused:<\/strong> Pushgateway may not be running or port is blocked. Restart the service or allow port 9091.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Duplicate metrics:<\/strong> You used the default registry. Switch to a custom one (CollectorRegistry()).<\/p>\n<p class=\"wp-block-paragraph\"><strong>Old metrics stay visible:<\/strong> Pushgateway keeps data until deleted. Delete with:<\/p>\n<pre class=\"wp-block-code\"><code>curl -X DELETE http:\/\/localhost:9091\/metrics\/job\/&lt;job-name&gt;<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>Access from another machine:<\/strong> Run with:<\/p>\n<pre class=\"wp-block-code\"><code>.\/pushgateway --web.listen-address=\":9091\"<\/code><\/pre>\n<p class=\"wp-block-paragraph\">and open the port:<\/p>\n<pre class=\"wp-block-code\"><code>sudo ufw allow 9091<\/code><\/pre>\n<h3 class=\"wp-block-heading\">10) Summary<\/h3>\n<ul class=\"wp-block-list\"><li>Pushgateway is used when Prometheus cannot scrape your app directly.<\/li><li>Perfect for batch jobs, cron tasks, and private apps.<\/li><li>Default port is 9091.<\/li><li>Prometheus scrapes Pushgateway just like any exporter.<\/li><li>Use Python client to push metrics easily.<\/li><li>Always use a custom registry.<\/li><li>Add job name and labels for better organization.<\/li><li>Push once at job completion to avoid missing data.<\/li><\/ul>","protected":false},"excerpt":{"rendered":"<p>This post explains what Prometheus Pushgateway is, when to use it, how to install it, and how to push metrics from Python.&hellip;<\/p>\n","protected":false},"author":2,"featured_media":58,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_rezaops_part":"6","_rezaops_linkedin_url":"https:\/\/www.linkedin.com\/pulse\/getting-started-prometheus-pushgateway-reza-chegini-j5pyc\/","footnotes":""},"categories":[10,14],"tags":[8,19,16,26],"series":[15],"class_list":["post-56","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-observability","tag-devops","tag-monitoring","tag-prometheus","tag-pushgateway","series-prometheus"],"jetpack_featured_media_url":"https:\/\/rezachegini.com\/wp-content\/uploads\/2026\/10\/getting-started-prometheus-pushgateway-cover.png","_links":{"self":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts\/56","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=56"}],"version-history":[{"count":1,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts\/56\/revisions"}],"predecessor-version":[{"id":57,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts\/56\/revisions\/57"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/media\/58"}],"wp:attachment":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=56"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fseries&post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}