├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── alertmanager ├── .env ├── Makefile ├── README.md ├── alert.png ├── alertmanager │ └── alertmanager.yml ├── amtool │ ├── Dockerfile │ └── config.yml ├── docker-compose.yml ├── hello │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go ├── prometheus │ ├── alert.rules │ └── prometheus.yml └── webhook │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go ├── blackbox-exporter ├── .env ├── Makefile ├── README.md ├── blackbox │ └── blackbox.yml ├── docker-compose.yml ├── prometheus │ └── prometheus.yml └── web │ ├── Dockerfile │ ├── go.mod │ └── main.go ├── cadvisor ├── .env ├── Makefile ├── README.md ├── docker-compose.yml └── prometheus │ └── prometheus.yml ├── federation ├── .env ├── Makefile ├── README.md ├── docker-compose.yml └── prometheus │ └── prometheus.yml ├── file-sd ├── .env ├── Makefile ├── README.md ├── docker-compose.yml ├── myservice │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go └── prometheus │ ├── prometheus.yml │ └── targets.json ├── go-app ├── .env ├── .gitignore ├── Makefile ├── README.md ├── docker-compose.yml ├── myapp │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go └── prometheus │ └── prometheus.yml ├── haproxy ├── .env ├── Makefile ├── README.md ├── certs │ └── cert.pem ├── docker-compose.yml ├── haproxy │ └── haproxy.cfg └── prometheus │ └── prometheus.yml ├── nginx ├── .env ├── Makefile ├── README.md ├── certs │ ├── example.com.crt │ └── example.com.key ├── docker-compose.yml ├── nginx │ ├── .htpasswd │ └── nginx.conf └── prometheus │ └── prometheus.yml ├── node-exporter ├── .env ├── Makefile ├── README.md ├── docker-compose.yml └── prometheus │ └── prometheus.yml └── python-flask-app ├── .env ├── Makefile ├── README.md ├── docker-compose.yml ├── myapp ├── Dockerfile ├── requirements.txt └── server.py └── prometheus └── prometheus.yml /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Prometheus Community Code of Conduct 2 | 3 | Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Prometheus Playground 2 | 3 | This repo houses a variety of [Docker-Compose](https://docs.docker.com/compose)-based "sandbox" projects showcasing the [Prometheus](https://prometheus.io) monitoring system. All projects are "turnkey" and require just a single `docker-compose up` command to run. 4 | 5 | Each sandbox project has a `README` with an explanation of the project, a `docker-compose.yml` configuration file for Docker Compose, and other necessary resources (config files, `Dockerfile`s, etc.). To run a project, navigate to the appropriate directory and run `make run` (which is just an alias for `docker-compose up --build`). This will run the project in the *foreground*. To run the project in detached mode, use `make run-detached`. 6 | 7 | ## Prerequisites 8 | 9 | In order to run the sandbox projects you'll need to install [Docker](https://docker.com) and [Docker Compose](https://docs.docker.com/compose) and have a Docker daemon running locally. 10 | 11 | ## Projects 12 | 13 | Directory | Scenario 14 | :---------|:-------- 15 | [`alertmanager`](./alertmanager) | Prometheus monitors a basic web service and notifies [Alertmanager](https://prometheus.io/docs/alerting/alertmanager/) if the service is down; Alertmanager, in turns, notifies a web service via webhook 16 | [`blackbox-exporter`](./blackbox-exporter) | A [BlackBox prober exporter](https://github.com/prometheus/blackbox_exporter) probes a simple web service and provides probe-based metrics to Prometheus 17 | [`cadvisor`](./cadvisor) | Prometheus scrapes [cAdvisor](https://github.com/google/cadvisor)-gathered metrics for several containers 18 | [`federation`](./federation) | Three Prometheus instances run together as a single federation 19 | [`file-sd`](./file-sd) | A Prometheus instance discovers a simple instrumented web service via file-based service discovery 20 | [`go-app`](./go-app) | An instrumented Go application using the Prometheus [Go client](https://github.com/prometheus/client_golang) 21 | [`haproxy`](./haproxy) | Prometheus runs behind [HAProxy](https://haproxy.org/), which acts as a reverse proxy and provides basic auth and TLS encryption 22 | [`nginx`](./nginx) | Prometheus runs behind [nginx](https://nginx.org), which acts as a reverse proxy and provides basic auth and TLS encryption 23 | [`node-exporter`](./node-exporter) | Prometheus scrapes Linux host metrics from a [Node Exporter](https://prometheus.io/docs/guides/node-exporter/) 24 | [`python-flask-app`](./python-flask-app) | An instrumented [Flask](https://flask.pocoo.org) application demonstrating the Prometheus [Python client](https://github.com/prometheus/client_python) 25 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting a security issue 2 | 3 | The Prometheus security policy, including how to report vulnerabilities, can be 4 | found here: 5 | 6 | 7 | -------------------------------------------------------------------------------- /alertmanager/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | ALERTMANAGER_TAG=v0.15.3 3 | -------------------------------------------------------------------------------- /alertmanager/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /alertmanager/README.md: -------------------------------------------------------------------------------- 1 | # Alertmanager sandbox 2 | 3 | In this sandbox, a Prometheus [Alertmanager](https://github.com/prometheus/alertmanager) handles alerts thrown by a running Prometheus instance. The Alertmanager in this example is configured with one alert (specified in an [`alert.rules`](./prometheus/alert.rules) file) that Prometheus fires whenever the [`hello`](./hello/main.go) service—a simple web service—is down for more than 10 seconds. If Prometheus alerts the Alertmanager that the `hello` service is down, it will `POST` a webhook to the [`webhook`](./webhook/main.go) service, which will then log the alert sent by the Alertmanager to stdout. 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up five services: 18 | 19 | Service | Description 20 | :-------|:----------- 21 | `prometheus` | A Prometheus instance that's [configured](./prometheus/alert.rules) to alert the Alertmanager whenever the `hello` web service has been down for more than 10 seconds 22 | `alertmanager` | An Alertmanager instance that's configured to `POST` an alert message to the `webhook` service whenever Prometheus alerts Alertmanager that the `hello` service is down 23 | `amtool` | [amtool](https://github.com/prometheus/alertmanager#amtool) is a CLI utility for interacting with the Alertmanager. This service is a utility container that enables you to run amtool against the Alertmanager instance included in the sandbox. 24 | `hello` | A simple [web service](./hello/main.go) written in Go. The `hello` web service has just two endpoints: a `/hello` endpoint that returns a `{"hello":"world"}` JSON object and a `/metrics` endpoint for Prometheus instrumentation 25 | `webhook` | A simple [web service](./webhook/main.go) written in Go. The `webhook` web service has just one `/alert` endpoint to which Alertmanager alerts are `POST`ed 26 | 27 | ## Creating an alert 28 | 29 | When you first start up the containers, there's no alert-worthy behavior because the `hello` service is running as expected. You can verify this in the [Prometheus expression browser](http://localhost:9090/graph) using the [`up{job="hello"}`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=up%7Bjob%3D%22hello%22%7D&g0.tab=1) expression, which should have a value of 1. 30 | 31 | To create an alert, stop the service: 32 | 33 | ```bash 34 | docker-compose stop hello 35 | ``` 36 | 37 | Wait about 10 seconds and you should see something like this in the Docker Compose logs: 38 | 39 | ``` 40 | webhook_1 | 2018/07/23 19:31:28 Webhook received: {"receiver":"webhook","status":"firing","alerts":[{"status":"firing","labels":{"alertname":"InstanceDown","instance":"hello:2112","job":"hello","severity":"page"},"annotations":{"description":"Instance hello:2112 of job hello has been down for more than 30 seconds","summary":"Instance hello:2112 down"},"startsAt":"2018-07-23T19:31:18.893055177Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://e192da4eb26f:9090/graph?g0.expr=up%7Bjob%3D%22hello%22%7D+%3D%3D+0\u0026g0.tab=1"}],"groupLabels":{"alertname":"InstanceDown"},"commonLabels":{"alertname":"InstanceDown","instance":"hello:2112","job":"hello","severity":"page"},"commonAnnotations":{"description":"Instance hello:2112 of job hello has been down for more than 30 seconds","summary":"Instance hello:2112 down"},"externalURL":"http://98c322df76cb:9093","version":"4","groupKey":"{}:{alertname=\"InstanceDown\"}"} 41 | ``` 42 | 43 | This indicates that Alertmanager has `POST`ed a webhook to the running [`webhook`](./webhook/main.go) service. You can also read the webhook service logs directly: 44 | 45 | ```bash 46 | docker-compose logs webhook 47 | ``` 48 | 49 | You can also see the alert in the [Alertmanager UI](http://localhost:9093/#/alerts). It should look like this: 50 | 51 | ![Alertmanager alert](./alert.png) 52 | 53 | In the Prometheus expression browser, [`up{job="hello"}`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=up%7Bjob%3D%22hello%22%7D&g0.tab=1) should now have a value of 0. 54 | 55 | ## amtool 56 | 57 | The `amtool` service can be used as a proxy for the [amtool](https://github.com/prometheus/alertmanager#amtool) CLI utility. For ease of use, you can alias `amtool` to the container: 58 | 59 | ```bash 60 | alias amtool='docker-compose run amtool amtool' 61 | ``` 62 | 63 | Now you can use amtool commands like this: 64 | 65 | ```bash 66 | amtool alert 67 | ``` -------------------------------------------------------------------------------- /alertmanager/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prometheus-community/prometheus-playground/HEAD/alertmanager/alert.png -------------------------------------------------------------------------------- /alertmanager/alertmanager/alertmanager.yml: -------------------------------------------------------------------------------- 1 | global: 2 | resolve_timeout: 5m 3 | 4 | route: 5 | group_by: ['alertname'] 6 | group_wait: 10s 7 | group_interval: 10s 8 | repeat_interval: 1h 9 | receiver: webhook 10 | receivers: 11 | - name: webhook 12 | webhook_configs: 13 | - url: http://webhook:5001/alert -------------------------------------------------------------------------------- /alertmanager/amtool/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.11beta1-alpine3.7 2 | 3 | RUN apk update \ 4 | && apk upgrade \ 5 | && apk add --no-cache git \ 6 | && go get github.com/prometheus/alertmanager/cmd/amtool \ 7 | && apk del git -------------------------------------------------------------------------------- /alertmanager/amtool/config.yml: -------------------------------------------------------------------------------- 1 | alertmanager.url: http://alertmanager:9093 -------------------------------------------------------------------------------- /alertmanager/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | alertmanager: 4 | image: prom/alertmanager:${ALERTMANAGER_TAG} 5 | ports: 6 | - 9093:9093 7 | command: 8 | - --config.file=/etc/alertmanager/alertmanager.yml 9 | volumes: 10 | - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro 11 | prometheus: 12 | image: prom/prometheus:${PROMETHEUS_TAG} 13 | ports: 14 | - 9090:9090 15 | command: 16 | - --config.file=/etc/prometheus/prometheus.yml 17 | volumes: 18 | - ./prometheus:/etc/prometheus:ro 19 | amtool: 20 | build: 21 | context: amtool 22 | volumes: 23 | - ./amtool/config.yml:/etc/amtool/config.yml:ro 24 | hello: 25 | build: 26 | context: hello 27 | args: 28 | goPackage: github.com/prometheus-community/prometheus-playground/alertmanager/hello 29 | goVersion: 1.11 30 | cache_from: 31 | - golang:1.11 32 | - scratch 33 | ports: 34 | - 2112:2112 35 | webhook: 36 | build: 37 | context: webhook 38 | args: 39 | goPackage: github.com/prometheus-community/prometheus-playground/alertmanager/webhook 40 | goVersion: 1.11 41 | cache_from: 42 | - golang:1.11 43 | - scratch 44 | ports: 45 | - 5001:5001 -------------------------------------------------------------------------------- /alertmanager/hello/Dockerfile: -------------------------------------------------------------------------------- 1 | # Args 2 | ARG goVersion 3 | ARG goPackage 4 | 5 | FROM golang:${goVersion} AS builder 6 | 7 | # Copy the code from the host and compile it 8 | WORKDIR /home 9 | COPY . ./ 10 | RUN go mod vendor 11 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /app . 12 | 13 | FROM scratch 14 | COPY --from=builder /app ./ 15 | ENTRYPOINT ["./app"] -------------------------------------------------------------------------------- /alertmanager/hello/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prometheus-community/prometheus-playground/alertmanager/hello 2 | 3 | require ( 4 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect 5 | github.com/go-chi/chi v3.3.2+incompatible 6 | github.com/golang/protobuf v1.1.0 // indirect 7 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 8 | github.com/prometheus/client_golang v0.8.0 9 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect 10 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 // indirect 11 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 // indirect 12 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3 13 | ) 14 | -------------------------------------------------------------------------------- /alertmanager/hello/go.sum: -------------------------------------------------------------------------------- 1 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 2 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 3 | github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ= 4 | github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= 5 | github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc= 6 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 7 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 8 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 9 | github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= 10 | github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 11 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 12 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 13 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc= 14 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 15 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0= 16 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 17 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3 h1:ZsIlNwu/G0zbChIZaWOeZ2TPGNmKMt46jZLXi3e8LFc= 18 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= 19 | -------------------------------------------------------------------------------- /alertmanager/hello/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | 8 | "github.com/go-chi/chi" 9 | "github.com/prometheus/client_golang/prometheus/promhttp" 10 | "github.com/unrolled/render" 11 | ) 12 | 13 | const ( 14 | port = 2112 15 | ) 16 | 17 | var ( 18 | renderer = render.New() 19 | address = fmt.Sprintf(":%d", port) 20 | ) 21 | 22 | func hello(w http.ResponseWriter, r *http.Request) { 23 | renderer.JSON(w, http.StatusOK, map[string]string{"hello": "world"}) 24 | } 25 | 26 | func main() { 27 | router := chi.NewRouter() 28 | 29 | router.Get("/hello", hello) 30 | 31 | router.Handle("/metrics", promhttp.Handler()) 32 | 33 | log.Fatal(http.ListenAndServe(address, router)) 34 | } 35 | -------------------------------------------------------------------------------- /alertmanager/prometheus/alert.rules: -------------------------------------------------------------------------------- 1 | groups: 2 | - name: node.rules 3 | rules: 4 | - alert: InstanceDown 5 | expr: up{job="hello"} == 0 6 | for: 10s 7 | labels: 8 | severity: page 9 | annotations: 10 | summary: "Instance {{ $labels.instance }} down" 11 | description: "Instance {{ $labels.instance }} of job {{ $labels.job }} has been down for more than 30 seconds" 12 | -------------------------------------------------------------------------------- /alertmanager/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | rule_files: 6 | - /etc/prometheus/alert.rules 7 | 8 | alerting: 9 | alertmanagers: 10 | - scheme: http 11 | static_configs: 12 | - targets: 13 | - alertmanager:9093 14 | 15 | scrape_configs: 16 | - job_name: prometheus 17 | scrape_interval: 5s 18 | static_configs: 19 | - targets: 20 | - localhost:9090 21 | - job_name: hello 22 | scrape_interval: 5s 23 | static_configs: 24 | - targets: 25 | - hello:2112 -------------------------------------------------------------------------------- /alertmanager/webhook/Dockerfile: -------------------------------------------------------------------------------- 1 | # Args 2 | ARG goVersion 3 | ARG goPackage 4 | 5 | FROM golang:${goVersion} AS builder 6 | 7 | # Copy the code from the host and compile it 8 | WORKDIR /home 9 | COPY . ./ 10 | RUN go mod vendor 11 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /app . 12 | 13 | FROM scratch 14 | COPY --from=builder /app ./ 15 | ENTRYPOINT ["./app"] -------------------------------------------------------------------------------- /alertmanager/webhook/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prometheus-community/prometheus-playground/alertmanager/webhook 2 | 3 | require ( 4 | github.com/go-chi/chi v3.3.2+incompatible 5 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3 6 | ) 7 | -------------------------------------------------------------------------------- /alertmanager/webhook/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ= 2 | github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= 3 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3 h1:ZsIlNwu/G0zbChIZaWOeZ2TPGNmKMt46jZLXi3e8LFc= 4 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= 5 | -------------------------------------------------------------------------------- /alertmanager/webhook/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | 9 | "github.com/go-chi/chi" 10 | "github.com/unrolled/render" 11 | ) 12 | 13 | const ( 14 | port = 5001 15 | ) 16 | 17 | var ( 18 | renderer = render.New() 19 | 20 | address = fmt.Sprintf(":%d", port) 21 | ) 22 | 23 | func getRequestBody(r *http.Request) string { 24 | body, err := ioutil.ReadAll(r.Body) 25 | if err != nil { 26 | log.Fatalf("Could not read webhook body: %v", err) 27 | } 28 | defer r.Body.Close() 29 | 30 | return string(body) 31 | } 32 | 33 | func webhookHandler(w http.ResponseWriter, r *http.Request) { 34 | requestBody := getRequestBody(r) 35 | 36 | msg := fmt.Sprintf("Webhook received: %s", requestBody) 37 | 38 | log.Print(msg) 39 | 40 | renderer.Text(w, http.StatusAccepted, "") 41 | } 42 | 43 | func main() { 44 | router := chi.NewRouter() 45 | 46 | router.Post("/alert", webhookHandler) 47 | 48 | log.Fatal(http.ListenAndServe(address, router)) 49 | } 50 | -------------------------------------------------------------------------------- /blackbox-exporter/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | BLACKBOX_EXPORTER_TAG=v0.12.0 3 | -------------------------------------------------------------------------------- /blackbox-exporter/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /blackbox-exporter/README.md: -------------------------------------------------------------------------------- 1 | # Blackbox prober exporter sandbox 2 | 3 | In this sandbox, the [Blackbox prober exporter](https://github.com/prometheus/blackbox_exporter) probes a [simple web service](./web/main.go), while Prometheus scrapes `probe_*` metrics from the Blackbox exporter. 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up three services: 18 | 19 | Service | Description 20 | :-------|:----------- 21 | `blackbox` | A Prometheus Blackbox exporter running on port 9115, which runs probes against the `web` service using the [`http_2xx` module](./blackbox/blackbox.yml). 22 | `prometheus` | A Prometheus instance configured to scrape the Blackbox exporter and collect a wide variety of metrics (prefaced by `probe_`). 23 | `web` | A simple web service with two endpoints: `/hello` returns a `{"hello": "world"}` JSON object and `/health` returns an HTTP `200 OK` indicating that the service is running. The `web` service 24 | 25 | Things to check out: 26 | 27 | * The Blackbox exporter dashboard at http://localhost:9115. You'll see a **Recent Probes** table listing all probes, including the following information for each probe: module, target, result, and a link to debugging logs. 28 | * The results of the most recent probe of the `web` service at http://localhost:9115/probe?target=web:2112/health&module=http_2xx. If the value of `probe_success` metric is 1, then the service is running properly (otherwise the value will be 0). 29 | * The `probe_success` metric on Prometheus at http://localhost:9090/graph?g0.range_input=1h&g0.expr=probe_success%7Binstance%3D%22web%3A2112%2Fhealth%22%7D&g0.tab=1. 30 | 31 | At first, the `web` service will be running normally, which means that the Blackbox probes of that service's `/health` will succeed. This will change if you shut down the service: 32 | 33 | ```bash 34 | docker-compose stop web 35 | ``` 36 | 37 | Now you can navigate back to the most recent [probe result](http://localhost:9115/probe?target=web:2112/health&module=http_2xx) and see that `probe_success` now has a value of 0. If you navigate back to the Prometheus [expression browser](http://localhost:9090/graph?g0.range_input=1h&g0.expr=probe_success%7Binstance%3D%22web%3A2112%2Fhealth%22%7D&g0.tab=1) you can see that `probe_success` for the `web` service now returns 0 as well (the scrape interval is 5 seconds, so you may need to wait a bit and hit refresh). 38 | 39 | If you restart the `web` service, the probes will once again be successful: 40 | 41 | ```bash 42 | docker-compose start web 43 | ``` 44 | 45 | ## Assets 46 | 47 | Folder | Assets 48 | :------|:------ 49 | [`prometheus`](./prometheus) | A [`prometheus.yml`](./prometheus/prometheus.yml) configuration file for Prometheus 50 | [`blackbox`](./blackbox) | A [`blackbox.yml`](./blackbox/blackbox.yml) configuration file for the Blackbox exporter 51 | [`web`](./web) | Source files for the simple web server (written in Go) -------------------------------------------------------------------------------- /blackbox-exporter/blackbox/blackbox.yml: -------------------------------------------------------------------------------- 1 | modules: 2 | http_2xx: 3 | prober: http 4 | timeout: 5s 5 | http: 6 | method: GET -------------------------------------------------------------------------------- /blackbox-exporter/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | blackbox: 4 | image: prom/blackbox-exporter:${BLACKBOX_EXPORTER_TAG} 5 | ports: 6 | - 9115:9115 7 | command: 8 | - --config.file=/etc/blackbox/blackbox.yml 9 | volumes: 10 | - ./blackbox/blackbox.yml:/etc/blackbox/blackbox.yml 11 | depends_on: 12 | - web 13 | prometheus: 14 | image: prom/prometheus:${PROMETHEUS_TAG} 15 | ports: 16 | - 9090:9090 17 | command: 18 | - --config.file=/etc/prometheus/prometheus.yml 19 | volumes: 20 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml 21 | depends_on: 22 | - blackbox 23 | web: 24 | build: 25 | context: web 26 | args: 27 | goPackage: github.com/prometheus-community/prometheus-playground/blackbox-exporter/web 28 | goVersion: 1.11 29 | cache_from: 30 | - golang:1.11 31 | - scratch 32 | ports: 33 | - 2112:2112 34 | -------------------------------------------------------------------------------- /blackbox-exporter/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: prometheus 3 | scrape_interval: 5s 4 | static_configs: 5 | - targets: 6 | - prometheus:9090 7 | - job_name: blackbox 8 | metrics_path: /probe 9 | scrape_interval: 5s 10 | params: 11 | module: [http_2xx] 12 | static_configs: 13 | - targets: 14 | - prometheus:9090 15 | - web:2112/health 16 | relabel_configs: 17 | - source_labels: [__address__] 18 | target_label: __param_target 19 | - source_labels: [__param_target] 20 | target_label: instance 21 | - target_label: __address__ 22 | replacement: blackbox:9115 23 | -------------------------------------------------------------------------------- /blackbox-exporter/web/Dockerfile: -------------------------------------------------------------------------------- 1 | # Args 2 | ARG goVersion 3 | ARG goPackage 4 | 5 | FROM golang:${goVersion} AS builder 6 | 7 | # Copy the code from the host and compile it 8 | WORKDIR /home 9 | COPY . ./ 10 | RUN go mod vendor 11 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /app . 12 | 13 | FROM scratch 14 | COPY --from=builder /app ./ 15 | ENTRYPOINT ["./app"] -------------------------------------------------------------------------------- /blackbox-exporter/web/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prometheus-community/prometheus-playground/blackbox-exporter/web 2 | 3 | require ( 4 | github.com/go-chi/chi v3.3.2+incompatible 5 | github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3 6 | ) 7 | -------------------------------------------------------------------------------- /blackbox-exporter/web/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/go-chi/chi" 8 | "github.com/unrolled/render" 9 | ) 10 | 11 | var ( 12 | renderer = render.New() 13 | ) 14 | 15 | func health(w http.ResponseWriter, r *http.Request) { 16 | renderer.Text(w, http.StatusOK, "") 17 | } 18 | 19 | func hello(w http.ResponseWriter, r *http.Request) { 20 | renderer.JSON(w, http.StatusOK, map[string]string{"hello": "world"}) 21 | } 22 | 23 | func main() { 24 | router := chi.NewRouter() 25 | 26 | router.Get("/health", health) 27 | 28 | router.Get("/hello", hello) 29 | 30 | log.Fatal(http.ListenAndServe(":2112", router)) 31 | } 32 | -------------------------------------------------------------------------------- /cadvisor/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | CADVISOR_TAG=v0.32.0 3 | REDIS_TAG=5-alpine3.8 4 | -------------------------------------------------------------------------------- /cadvisor/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /cadvisor/README.md: -------------------------------------------------------------------------------- 1 | # cAdvisor sandbox 2 | 3 | In this sandbox, [cAdvisor](https://github.com/google/cadvisor) gathers metrics for three running containers: 4 | 5 | * Its own container 6 | * A container running [Redis](https://redis.io) 7 | * A container running [Prometheus](https://prometheus.io) 8 | 9 | The Prometheus instance scrapes metrics from cAdvisor and makes them accessible via the Prometheus [expression browser](https://prometheus.io/docs/visualization/browser). 10 | 11 | ## Usage 12 | 13 | To start the sandbox: 14 | 15 | ```bash 16 | # In the foreground 17 | make run # docker-compose up --build 18 | 19 | # In detached mode 20 | make run-detached # docker-compose up --build --detach 21 | ``` 22 | 23 | This will start up the three containers mentioned above. 24 | 25 | > To kill the sandbox, run `make kill` (alias for `docker-compose kill`). 26 | 27 | Open up `http://localhost:9090/graph` to access the Prometheus expression browser. Some example metrics to explore: 28 | 29 | * [`rate(container_cpu_usage_seconds_total{name="redis"}[1m])`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=rate(container_cpu_usage_seconds_total%7Bname%3D%22redis%22%7D%5B1m%5D)&g0.tab=1) 30 | * [`container_memory_usage_bytes{name="redis"}`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=container_memory_usage_bytes%7Bname%3D%22redis%22%7D&g0.tab=1) 31 | * [`rate(container_network_transmit_bytes_total[1m])`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=rate(container_network_transmit_bytes_total%5B1m%5D)&g0.tab=1) 32 | * [`rate(container_network_receive_bytes_total[1m])`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=rate(container_network_receive_bytes_total%5B1m%5D)&g0.tab=1) 33 | 34 | ## Assets 35 | 36 | Folder | Assets 37 | :------|:------ 38 | [`prometheus`](./prometheus) | A [`prometheus.yml`](./prometheus/prometheus.yml) configuration file for Prometheus -------------------------------------------------------------------------------- /cadvisor/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | prometheus: 4 | image: prom/prometheus:${PROMETHEUS_TAG} 5 | ports: 6 | - 9090:9090 7 | command: 8 | - --config.file=/etc/prometheus/prometheus.yml 9 | volumes: 10 | - ./prometheus:/etc/prometheus 11 | links: 12 | - cadvisor:cadvisor 13 | depends_on: 14 | - cadvisor 15 | cadvisor: 16 | image: google/cadvisor:${CADVISOR_TAG} 17 | ports: 18 | - 8080:8080 19 | volumes: 20 | - /:/rootfs:ro 21 | - /var/run:/var/run:rw 22 | - /sys:/sys:ro 23 | - /var/lib/docker/:/var/lib/docker:ro 24 | depends_on: 25 | - redis 26 | redis: 27 | image: redis:${REDIS_TAG} 28 | ports: 29 | - 6379:6379 30 | -------------------------------------------------------------------------------- /cadvisor/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | scrape_timeout: 10s 5 | 6 | scrape_configs: 7 | - job_name: cadvisor 8 | scrape_interval: 5s 9 | static_configs: 10 | - targets: 11 | - cadvisor:8080 -------------------------------------------------------------------------------- /federation/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | NODE_EXPORTER_TAG=v0.16.0 3 | -------------------------------------------------------------------------------- /federation/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /federation/README.md: -------------------------------------------------------------------------------- 1 | # Federation sandbox 2 | 3 | In this sandbox, three Prometheus instances are run as a single Prometheus [federation](https://prometheus.io/docs/prometheus/latest/federation). All three instances scrape metrics from a single [Node Exporter](../node-exporter). 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up three Prometheus services (`prometheus1`, `prometheus2`, and `prometheus3`) and a `node_exporter` service. 18 | 19 | Service | Description 20 | :-------|:----------- 21 | `prometheus1`, `prometheus2`, `prometheus3` | Standard Prometheus instances [configured](./prometheus/prometheus.yml#L10-L14) to run as a single federation 22 | `node_exporter` | A Node Exporter instance that gathers and exposes Linux host metrics to be scraped by the Prometheus federation 23 | 24 | > To kill the sandbox, run `make kill` (alias for `docker-compose kill`). 25 | 26 | Open up `http://localhost:9090/graph` to access the Prometheus [expression browser](https://prometheus.io/docs/visualization/browser). The expression browser is actually available via all three Prometheus instances (ports 9090, 9091, and 9092). 27 | -------------------------------------------------------------------------------- /federation/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | prometheus1: 4 | image: prom/prometheus:${PROMETHEUS_TAG} 5 | ports: 6 | - 9090:9090 7 | command: 8 | - --config.file=/etc/prometheus/prometheus.yml 9 | volumes: 10 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro 11 | prometheus2: 12 | image: prom/prometheus:${PROMETHEUS_TAG} 13 | ports: 14 | - 9091:9091 15 | command: 16 | - --config.file=/etc/prometheus/prometheus.yml 17 | - --web.listen-address=0.0.0.0:9091 18 | volumes: 19 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro 20 | prometheus3: 21 | image: prom/prometheus:${PROMETHEUS_TAG} 22 | ports: 23 | - 9092:9092 24 | command: 25 | - --config.file=/etc/prometheus/prometheus.yml 26 | - --web.listen-address=0.0.0.0:9092 27 | volumes: 28 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro 29 | node_exporter: 30 | image: prom/node-exporter:${NODE_EXPORTER_TAG} 31 | ports: 32 | - 9100:9100 33 | -------------------------------------------------------------------------------- /federation/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: federate 3 | scrape_interval: 15s 4 | honor_labels: true 5 | metrics_path: '/federate' 6 | params: 7 | 'match[]': 8 | - '{job="prometheus"}' 9 | - '{__name__=~"job:.*"}' 10 | static_configs: 11 | - targets: 12 | - prometheus1:9090 13 | - prometheus2:9091 14 | - prometheus3:9092 15 | - job_name: node 16 | scrape_interval: 5s 17 | static_configs: 18 | - targets: 19 | - node_exporter:9100 20 | -------------------------------------------------------------------------------- /file-sd/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | -------------------------------------------------------------------------------- /file-sd/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /file-sd/README.md: -------------------------------------------------------------------------------- 1 | # File-based service discovery sandbox 2 | 3 | In this sandbox, a simple [web service](./myservice) running on the `myservice` host is scraped by a Prometheus instance. Prometheus discovers that host via [file-based service discovery](https://www.robustperception.io/using-json-file-service-discovery-with-prometheus). 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up two services: 18 | 19 | Service | Description 20 | :-------|:----------- 21 | `prometheus` | A Prometheus instance configured to use the [`targets.json`](./prometheus/targets.json) file for file-based service discovery (see the [`dummy`](./prometheus/prometheus.yml#L2-L5) job configuration) 22 | `myservice1` and `myservice2` | A basic web service that exposes a `/metrics` endpoint for Prometheus metrics and one custom metric: [`myservice_processed_ops_total`](./myservice/main.go#L20-L24). Two instances of this service are run. 23 | 24 | > To kill the sandbox, run `make kill` (alias for `docker-compose kill`). 25 | 26 | Once the sandbox is up and running, you can verify that the `myservice_processed_ops_total` metric is being scraped—and thus that the `myservice1` and `myservice2` services have been properly discovered by Prometheus—you can see the current value in the [expression browser](http://localhost:9090/graph?g0.range_input=1h&g0.expr=myservice_processed_ops_total&g0.tab=1). -------------------------------------------------------------------------------- /file-sd/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | prometheus: 4 | image: prom/prometheus:${PROMETHEUS_TAG} 5 | ports: 6 | - 9090:9090 7 | command: 8 | - --config.file=/etc/prometheus/prometheus.yml 9 | volumes: 10 | - ./prometheus:/etc/prometheus:ro 11 | myservice1: &myservice 12 | build: 13 | context: myservice 14 | args: 15 | goPackage: github.com/prometheus-community/prometheus-playground/file-sd/myservice 16 | goVersion: 1.11 17 | environment: 18 | - PORT=1234 19 | ports: 20 | - 1234:1234 21 | myservice2: 22 | << : *myservice 23 | environment: 24 | - PORT=4321 25 | ports: 26 | - 4321:4321 -------------------------------------------------------------------------------- /file-sd/myservice/Dockerfile: -------------------------------------------------------------------------------- 1 | # Args 2 | ARG goVersion 3 | ARG goPackage 4 | 5 | FROM golang:${goVersion} AS builder 6 | 7 | # Copy the code from the host and compile it 8 | WORKDIR /home 9 | COPY . ./ 10 | RUN go mod vendor 11 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /app . 12 | 13 | FROM scratch 14 | COPY --from=builder /app ./ 15 | ENTRYPOINT ["./app"] -------------------------------------------------------------------------------- /file-sd/myservice/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prometheus-community/prometheus-playground/file-sd/myservice 2 | 3 | require ( 4 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 5 | github.com/golang/protobuf v1.1.0 6 | github.com/matttproud/golang_protobuf_extensions v1.0.1 7 | github.com/prometheus/client_golang v0.0.0-20180713201052-bcbbc08eb2dd 8 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 9 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 10 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 11 | ) 12 | -------------------------------------------------------------------------------- /file-sd/myservice/go.sum: -------------------------------------------------------------------------------- 1 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 2 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 3 | github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc= 4 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 5 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 6 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 7 | github.com/prometheus/client_golang v0.0.0-20180713201052-bcbbc08eb2dd h1:T6Y9DkTZlfcCB1qlrwQFCiAcLhTjmkjxW8EP3ZhV7Ts= 8 | github.com/prometheus/client_golang v0.0.0-20180713201052-bcbbc08eb2dd/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 9 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 10 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 11 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc= 12 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 13 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0= 14 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 15 | -------------------------------------------------------------------------------- /file-sd/myservice/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | "time" 9 | 10 | "github.com/prometheus/client_golang/prometheus/promauto" 11 | 12 | "github.com/prometheus/client_golang/prometheus" 13 | "github.com/prometheus/client_golang/prometheus/promhttp" 14 | ) 15 | 16 | var ( 17 | port = os.Getenv("PORT") 18 | 19 | processedOps = promauto.NewCounter(prometheus.CounterOpts{ 20 | Name: "processed_ops_total", 21 | Help: "The total number of processed events", 22 | Namespace: "myservice", 23 | }) 24 | ) 25 | 26 | func recordMetrics() { 27 | go func() { 28 | for { 29 | processedOps.Inc() 30 | time.Sleep(2 * time.Second) 31 | } 32 | }() 33 | } 34 | 35 | func main() { 36 | address := fmt.Sprintf(":%s", port) 37 | 38 | recordMetrics() 39 | 40 | http.Handle("/metrics", promhttp.Handler()) 41 | log.Fatal(http.ListenAndServe(address, nil)) 42 | } 43 | -------------------------------------------------------------------------------- /file-sd/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 5s 3 | 4 | scrape_configs: 5 | - job_name: dummy 6 | file_sd_configs: 7 | - files: 8 | - targets.json 9 | -------------------------------------------------------------------------------- /file-sd/prometheus/targets.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "targets": [ 4 | "myservice1:1234", 5 | "myservice2:4321" 6 | ], 7 | "labels": { 8 | "env": "development", 9 | "job": "myservice" 10 | } 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /go-app/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | 3 | -------------------------------------------------------------------------------- /go-app/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go-app/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /go-app/README.md: -------------------------------------------------------------------------------- 1 | # Instrumented Go application 2 | 3 | In this sandbox, a Prometheus intance scrapes metrics from a simple [Go](https://golang.org) web application. 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up two services: 18 | 19 | Service | Description 20 | :-------|:----------- 21 | `prometheus` | A Prometheus instance that's [configured](./prometheus/prometheus.yml) to scrape metrics from the Go application running on port 2112 22 | `myapp` | A simple Go web application that pretty much only exports a simple metric (a [`myapp_processed_ops_total`](./myapp/main.go#L20-L24) counter that is [incremented](./myapp/main.go#L27-L34) every 2 seconds) 23 | 24 | Once the sandbox is up and running, navigate to http://localhost:9090/graph in your browser and enter `myapp_processed_ops_total` into the expression bar to see the most up-to-date value of the counter. 25 | 26 | You can also see this metrics by "scraping" the Go web server's `/metrics` endpoint: 27 | 28 | ```bash 29 | curl localhost:2112/metrics | grep myapp_processed_ops_total 30 | # HELP myapp_processed_ops_total The total number of processed events 31 | # TYPE myapp_processed_ops_total counter 32 | myapp_processed_ops_total 4 33 | ``` -------------------------------------------------------------------------------- /go-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | myapp: 4 | build: 5 | context: myapp 6 | args: 7 | goPackage: github.com/prometheus-community/prometheus-playground/go-app/myapp 8 | goVersion: 1.11 9 | cache_from: 10 | - golang:1.11 11 | - scratch 12 | ports: 13 | - 2112:2112 14 | prometheus: 15 | image: prom/prometheus:${PROMETHEUS_TAG} 16 | ports: 17 | - 9090:9090 18 | command: 19 | - --config.file=/etc/prometheus/prometheus.yml 20 | volumes: 21 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro 22 | -------------------------------------------------------------------------------- /go-app/myapp/Dockerfile: -------------------------------------------------------------------------------- 1 | # Args 2 | ARG goVersion 3 | ARG goPackage 4 | 5 | FROM golang:${goVersion} AS builder 6 | 7 | # Copy the code from the host and compile it 8 | WORKDIR /home 9 | COPY . ./ 10 | RUN go mod vendor 11 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /app . 12 | 13 | FROM scratch 14 | COPY --from=builder /app ./ 15 | ENTRYPOINT ["./app"] -------------------------------------------------------------------------------- /go-app/myapp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prometheus-community/prometheus-playground/go-app/myapp 2 | 3 | require ( 4 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect 5 | github.com/golang/protobuf v1.1.0 // indirect 6 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 7 | github.com/prometheus/client_golang v0.0.0-20180713201052-bcbbc08eb2dd 8 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect 9 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 // indirect 10 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 // indirect 11 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /go-app/myapp/go.sum: -------------------------------------------------------------------------------- 1 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 2 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 3 | github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc= 4 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 5 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 6 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 7 | github.com/prometheus/client_golang v0.0.0-20180713201052-bcbbc08eb2dd h1:T6Y9DkTZlfcCB1qlrwQFCiAcLhTjmkjxW8EP3ZhV7Ts= 8 | github.com/prometheus/client_golang v0.0.0-20180713201052-bcbbc08eb2dd/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 9 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 10 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 11 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc= 12 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 13 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0= 14 | github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 15 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= 16 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 17 | -------------------------------------------------------------------------------- /go-app/myapp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/prometheus/client_golang/prometheus/promauto" 10 | 11 | "github.com/prometheus/client_golang/prometheus" 12 | "github.com/prometheus/client_golang/prometheus/promhttp" 13 | ) 14 | 15 | const ( 16 | port = 2112 17 | ) 18 | 19 | var ( 20 | processedOps = promauto.NewCounter(prometheus.CounterOpts{ 21 | Name: "processed_ops_total", 22 | Help: "The total number of processed events", 23 | Namespace: "myapp", 24 | }) 25 | ) 26 | 27 | func recordMetrics() { 28 | go func() { 29 | for { 30 | processedOps.Inc() 31 | time.Sleep(2 * time.Second) 32 | } 33 | }() 34 | } 35 | 36 | func main() { 37 | address := fmt.Sprintf(":%d", port) 38 | 39 | recordMetrics() 40 | 41 | http.Handle("/metrics", promhttp.Handler()) 42 | log.Fatal(http.ListenAndServe(address, nil)) 43 | } 44 | -------------------------------------------------------------------------------- /go-app/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 10s 3 | 4 | scrape_configs: 5 | - job_name: myapp 6 | static_configs: 7 | - targets: 8 | - myapp:2112 -------------------------------------------------------------------------------- /haproxy/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | HAPROXY_TAG=1.8 3 | -------------------------------------------------------------------------------- /haproxy/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /haproxy/README.md: -------------------------------------------------------------------------------- 1 | # haproxy sandbox 2 | 3 | In this sandbox, [HAProxy](http://www.haproxy.org/) acts as a reverse proxy for Prometheus, enforcing both [TLS encryption](https://prometheus.io/docs/guides/tls-encryption) and [basic auth](https://prometheus.io/docs/guides/basic-auth). All Prometheus endpoints are available behind https://example.com/prometheus. The [expression browser](https://prometheus.io/docs/visualization/browser), for example, is available at https://example.com/prometheus/graph. 4 | 5 | > To access Prometheus in this sandbox, two username/password combos are possible: `admin1`/`password1` and `admin2`/`password2`. 6 | 7 | ## Usage 8 | 9 | To start the sandbox: 10 | 11 | ```bash 12 | # In the foreground 13 | make run # docker-compose up --build 14 | 15 | # In detached mode 16 | make run-detached # docker-compose up --build --detach 17 | ``` 18 | 19 | This will start up an `haproxy` container and a `prometheus` container. 20 | 21 | The `haproxy` container is available on `localhost` port 443 but the example will only work if you map `localhost` to `example.com`. You can do so by modifying your `/etc/hosts` file to include a line like this: 22 | 23 | ```conf 24 | 127.0.0.1 localhost example.com 25 | ``` 26 | 27 | As HAProxy enforces both TLS encryption and basic auth, this will result in a self-signed certificate error: 28 | 29 | ```bash 30 | curl https://example.com/prometheus/metrics 31 | ``` 32 | 33 | If you disable cert checking using `--insecure`/`-k` you'll get a `401 Unauthorized` error: 34 | 35 | ```bash 36 | curl -ik https://example.com/prometheus/graph 37 | ``` 38 | 39 | You'll need to supply an valid username and password to access Prometheus through the proxy: 40 | 41 | ```bash 42 | curl -ik -u admin1:password1 https://example.com/prometheus/metrics 43 | ``` 44 | 45 | Open up `https://admin1:password1@example.com/prometheus/graph` to access the Prometheus [expression browser](https://prometheus.io/docs/visualization/browser). 46 | 47 | ## Assets 48 | 49 | Folder | Assets 50 | :------|:------ 51 | [`certs`](./certs) | An SSL cert and key generated by [OpenSSL](https://www.openssl.org/) 52 | [`haproxy`](./haproxy) | An [`haproxy.cfg`](./haproxy/haproxy.cfg) configuration file 53 | [`prometheus`](./prometheus) | A [`prometheus.yml`](./prometheus/prometheus.yml) configuration file for Prometheus 54 | 55 | The haproxy cert was created using these commands: 56 | 57 | ```bash 58 | openssl req -newkey rsa:4096 -nodes -keyout certs/key.pem -x509 -out certs/certificate.pem \ 59 | -subj "/C=US/ST=OR/L=Portland/O=CNCF/OU=Developer advocacy/CN=example.com" 60 | cat certs/{certificate,key}.pem > certs/cert.pem 61 | rm certs/{certificate,key}.pem 62 | ``` 63 | 64 | The hashed passwords in [`haproxy.cfg`](./haproxy/haproxy.cfg) were created using these commands: 65 | 66 | ```bash 67 | mkpasswd -m sha-512 password1 68 | mkpasswd -m sha-512 password2 69 | ``` -------------------------------------------------------------------------------- /haproxy/certs/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFWjCCA0ICCQC0XYj4xhiLfzANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJV 3 | UzELMAkGA1UECAwCT1IxETAPBgNVBAcMCFBvcnRsYW5kMQ0wCwYDVQQKDARDTkNG 4 | MRswGQYDVQQLDBJEZXZlbG9wZXIgYWR2b2NhY3kxFDASBgNVBAMMC2V4YW1wbGUu 5 | Y29tMB4XDTE4MDcyMTE1NTM0MVoXDTE4MDgyMDE1NTM0MVowbzELMAkGA1UEBhMC 6 | VVMxCzAJBgNVBAgMAk9SMREwDwYDVQQHDAhQb3J0bGFuZDENMAsGA1UECgwEQ05D 7 | RjEbMBkGA1UECwwSRGV2ZWxvcGVyIGFkdm9jYWN5MRQwEgYDVQQDDAtleGFtcGxl 8 | LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDcXcV2PgqRVOhG 9 | z1ZgfupjyMhxnzIz7fjoTi1Uh+0TXTPtxLFEQ6ENBU338eCnL2sTShEue9o8O9lk 10 | p5fFYNWZRfvw3wDABbS/3yYnkJ37uo3XtRhDJPfgkbjj/XnwNVdbis4Uz9vBOIER 11 | oS2WfMzVK9aATNjUTNPX6yCqOZ2ZkSlGxQZgIT6PYCMcqgyaK0SnIDFqWZv9mUNi 12 | YsFbeUvE2EvohbqVhMZsgFIH/J6IWmcyXOjdquskmEVwTsU8sV2KVa2sd0T0Bni9 13 | vd1BReqreqQ8P6lQRmPvDL9gww3rOnNRWYnWlbLaYEjkAqa4pcxfeTzsw97D3y3C 14 | a7nVvaGbWrDrDLbi53h84+qH7pa1u4YPGXEDnRDtQvkRcuC8X14NLsZtRieUqjRw 15 | TYv+iPsfQ0FtZeim3w5A4DnriHRZopDRdAJ3BfCORWwWWCs16ofyckh2wRuIlaxt 16 | OWc+BWc/mxvDiZ89qGQLLAZ5xnVZqmcDAeljK/WW3nE1Yl+nknTjFe3mpwU5hGzE 17 | t8YAurjQyfzXjVaS4xgIR+adza01AzQUWg1ovBjQ5Bv9Ii5Yg/JycIiCKqVdB+fQ 18 | n1GOg1VjKmTmrOBIpRSvJKDNl1/DBRIKQJhToLTmbxVhrgjlqtijIHMXR0Sr5Z+t 19 | NcF88tcNlpIqO3HHd1NGqI5LLQFFAgMBAAEwDQYJKoZIhvcNAQELBQADggIBADWc 20 | GQwlxZVU4SVODJas2rtr8Tot4T7E3S16KjIwOepn8Iso6ApTr2MoVstjIxeF2zA0 21 | wYu0xWeiO5kKll2jZGFaEHXimBggJP3Zvg0PKo1VNDF93H28xuqbfI3PX6IUBGjK 22 | Bd0uRZ7/88r9cr7JzrnYN6CjLGqteDn+cl62dR7eRMzkk6ff6xOfsT21Y1DcEpra 23 | HBQOY4JP0p95z9UEQJz5iHhzJWL/leQXZ5iv5FLeY0AuXxN4u+wPaEAPQvVi6o8l 24 | WH8zvgt6fzjwYQWION37bPJC/UafwzWTSKktsGl9PvTHTq+wBKPjGfN98to+Y9mW 25 | NMAEHm76nEBc+ql2qvStz7N4Ip5tSdSfvmcmqPO1AjfEQzdHnOEG6VEQrz+b63I8 26 | VTktyGhn0gEWxzIHhwmBsGUm+w/h1PqvxShkxmMbK7nvGzeQ4hB0PlXi1zK4FNPv 27 | HJ3OqO2Q40nAVQczW2W7FGqlrT1vOV9pI/jTklBFXVHKQ5ecKgSmONdN/lXpobei 28 | w1IHld8G4nBuOWD8HNkzDLJTCQmxSSEEowFV6qf53mliYRM4TbD8I2aQVwufKpl/ 29 | qD+AZGf03wWJrGFCPDntsjzRbwbhLnmY07CHO9tjh+ULRkgl5QO1ljyWL45UTr8L 30 | QvmvA9pt43283OdzBLTp8ODPqNBxUbKjLt0zxpKQ 31 | -----END CERTIFICATE----- 32 | -----BEGIN PRIVATE KEY----- 33 | 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 82 | vHWj7+Gw/wjBwlQd2c7jKr9trEqPDw== 83 | -----END PRIVATE KEY----- 84 | -------------------------------------------------------------------------------- /haproxy/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | haproxy: 4 | image: haproxy:${HAPROXY_TAG} 5 | ports: 6 | - 443:443 7 | volumes: 8 | - ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro 9 | - ./certs:/etc/ssl/certs:ro 10 | depends_on: 11 | - prometheus 12 | prometheus: 13 | image: prom/prometheus:${PROMETHEUS_TAG} 14 | expose: 15 | - 9090 16 | command: 17 | - --config.file=/etc/prometheus/prometheus.yml 18 | - --web.route-prefix=/prometheus 19 | - --web.external-url=http://example.com 20 | volumes: 21 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro -------------------------------------------------------------------------------- /haproxy/haproxy/haproxy.cfg: -------------------------------------------------------------------------------- 1 | userlist admin_users 2 | group admins users admin1,admin2 3 | user admin1 password $6$Mz3hA8lfZL2A06kQ$IQEFAIVBVhlqZT01fasZh6PHrZ0YrzvDSpZ0hY91r3fSoCsE1/vPYULV6CPVeBN/9bku18y6tF4TKgFSMsE.w1 4 | user admin2 password $6$m4JR4Q28pz6M1NrX$DqNQYI3XdvVya3fZJlCmi7MapRMXq1e/FOeX3p9bqNvkygX8fg4BQc6A8OkKYTZxDwX/CHpwnXdAzetG4HO64. 5 | 6 | defaults 7 | mode http 8 | balance roundrobin 9 | timeout connect 5000 10 | timeout client 10000 11 | timeout server 10000 12 | 13 | frontend proxy 14 | bind 0.0.0.0:443 ssl crt /etc/ssl/certs/cert.pem 15 | acl url_prometheus path_beg /prometheus 16 | acl is_admin http_auth(admin_users) 17 | http-request allow if is_admin 18 | http-request deny 19 | use_backend prometheus if url_prometheus is_admin 20 | 21 | backend prometheus 22 | server prom1 prometheus:9090 check 23 | -------------------------------------------------------------------------------- /haproxy/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: prometheus 3 | scrape_interval: 5s 4 | static_configs: 5 | - targets: 6 | - localhost:9090 -------------------------------------------------------------------------------- /nginx/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | NGINX_TAG=1.15.7-alpine 3 | -------------------------------------------------------------------------------- /nginx/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /nginx/README.md: -------------------------------------------------------------------------------- 1 | # nginx sandbox 2 | 3 | In this sandbox, [nginx](https://nginx.org) acts as a reverse proxy for Prometheus, enforcing both [TLS encryption](https://prometheus.io/docs/guides/tls-encryption) and [basic auth](https://prometheus.io/docs/guides/basic-auth). All Prometheus endpoints are available behind https://example.com/prometheus. The [expression browser](https://prometheus.io/docs/visualization/browser), for example, is available at https://example.com/prometheus/graph. 4 | 5 | > To access Prometheus in this sandbox, the proper username/password combo is `admin`/`password`. 6 | 7 | ## Usage 8 | 9 | To start the sandbox: 10 | 11 | ```bash 12 | # In the foreground 13 | make run # docker-compose up --build 14 | 15 | # In detached mode 16 | make run-detached # docker-compose up --build --detach 17 | ``` 18 | 19 | This will start up an `nginx` container and a `prometheus` container. 20 | 21 | > To kill the sandbox, run `make kill` (alias for `docker-compose kill`). 22 | 23 | The `nginx` container is available on `localhost` port 443 but the example will only work if you map `localhost` to `example.com`. You can do so by modifying your `/etc/hosts` file to include a line like this: 24 | 25 | ```conf 26 | 127.0.0.1 localhost example.com 27 | ``` 28 | 29 | As nginx enforces both TLS encryption and basic auth, this will result in a self-signed certificate error: 30 | 31 | ```bash 32 | curl https://example.com/prometheus/metrics 33 | ``` 34 | 35 | If you disable cert checking using `--insecure`/`-k` you'll get a `401 Unauthorized` error: 36 | 37 | ```bash 38 | curl -ik https://example.com/prometheus/metrics 39 | ``` 40 | 41 | You'll need to supply the username and password to access Prometheus through the proxy: 42 | 43 | ```bash 44 | curl -ik -u admin:password https://example.com/prometheus/metrics 45 | ``` 46 | 47 | Open up `https://admin:password@example.com/prometheus/graph` to access the Prometheus [expression browser](https://prometheus.io/docs/visualization/browser). 48 | 49 | ## Assets 50 | 51 | Folder | Assets 52 | :------|:------ 53 | [`certs`](./certs) | An SSL cert and key generated by [OpenSSL](https://www.openssl.org/) 54 | [`haproxy`](./haproxy) | An [`haproxy.cfg`](./haproxy/haproxy.cfg) configuration file and [`.htpasswd`](./nginx/.htpasswd) password file 55 | [`prometheus`](./prometheus) | A [`prometheus.yml`](./prometheus/prometheus.yml) configuration file for Prometheus 56 | 57 | The nginx certs were created using this command: 58 | 59 | ```bash 60 | openssl req -newkey rsa:4096 -nodes -keyout certs/example.com.key -x509 -out certs/example.com.crt \ 61 | -subj "/C=US/ST=OR/L=Portland/O=CNCF/OU=Developer advocacy/CN=example.com" 62 | ``` -------------------------------------------------------------------------------- /nginx/certs/example.com.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /nginx/certs/example.com.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | 6azFFyoB+Fu9hArTbj1llPI+4zDujQY= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /nginx/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | nginx: 4 | image: nginx:${NGINX_TAG} 5 | volumes: 6 | - ./nginx:/etc/nginx:ro 7 | - ./certs:/root/certs/example.com 8 | ports: 9 | - 443:443 10 | links: 11 | - prometheus:prometheus 12 | depends_on: 13 | - prometheus 14 | prometheus: 15 | image: prom/prometheus:${PROMETHEUS_TAG} 16 | ports: 17 | - 9090:9090 18 | command: 19 | - --config.file=/etc/prometheus/prometheus.yml 20 | - --web.route-prefix=/ 21 | - --web.external-url=http://example.com/prometheus 22 | volumes: 23 | - ./prometheus:/etc/prometheus 24 | -------------------------------------------------------------------------------- /nginx/nginx/.htpasswd: -------------------------------------------------------------------------------- 1 | admin:$apr1$Ps6FCt9l$trPwM2uLDcu3Tedmz/3dp/ 2 | -------------------------------------------------------------------------------- /nginx/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | events {} 2 | 3 | http { 4 | server { 5 | listen 443 ssl; 6 | ssl_certificate /root/certs/example.com/example.com.crt; 7 | ssl_certificate_key /root/certs/example.com/example.com.key; 8 | 9 | location /prometheus/ { 10 | auth_basic "Prometheus"; 11 | auth_basic_user_file /etc/nginx/.htpasswd; 12 | proxy_pass http://prometheus:9090/; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /nginx/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: prometheus 3 | scrape_interval: 5s 4 | static_configs: 5 | - targets: 6 | - localhost:9090 -------------------------------------------------------------------------------- /node-exporter/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | NODE_EXPORTER_TAG=v0.16.0 3 | -------------------------------------------------------------------------------- /node-exporter/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /node-exporter/README.md: -------------------------------------------------------------------------------- 1 | # Node Exporter sandbox 2 | 3 | In this sandbox, [Prometheus](https://prometheus.io) scrapes Linux host metrics from a [Node Exporter](https://prometheus.io/docs/guides/node-exporter). 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up a `node_exporter` container and a `prometheus` container. 18 | 19 | > To kill the sandbox, run `make kill` (alias for `docker-compose kill`). 20 | 21 | Open up `http://localhost:9090/graph` to access the Prometheus [expression browser](https://prometheus.io/docs/visualization/browser). Here are some example metrics to explore: 22 | 23 | * [`rate(node_cpu_seconds_total{mode="system"}[1m])`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=rate(node_cpu_seconds_total%7Bmode%3D%22system%22%7D%5B1m%5D)&g0.tab=1) 24 | * [`node_filesystem_avail_bytes`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=node_filesystem_avail_bytes&g0.tab=1) 25 | * [`rate(node_network_receive_bytes_total[1m])`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=rate(node_network_receive_bytes_total%5B1m%5D)&g0.tab=1) 26 | 27 | ## Assets 28 | 29 | Folder | Assets 30 | :------|:------ 31 | [`prometheus`](./prometheus) | A [`prometheus.yml`](./prometheus/prometheus.yml) configuration file for Prometheus -------------------------------------------------------------------------------- /node-exporter/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | node_exporter: 4 | image: prom/node-exporter:${NODE_EXPORTER_TAG} 5 | ports: 6 | - 9100:9100 7 | prometheus: 8 | image: prom/prometheus:${PROMETHEUS_TAG} 9 | ports: 10 | - 9090:9090 11 | command: 12 | - --config.file=/etc/prometheus/prometheus.yml 13 | volumes: 14 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro 15 | depends_on: 16 | - node_exporter 17 | -------------------------------------------------------------------------------- /node-exporter/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | - job_name: prometheus 7 | static_configs: 8 | - targets: 9 | - localhost:9090 10 | - job_name: node 11 | static_configs: 12 | - targets: 13 | - node_exporter:9100 -------------------------------------------------------------------------------- /python-flask-app/.env: -------------------------------------------------------------------------------- 1 | PROMETHEUS_TAG=v2.5.0 2 | -------------------------------------------------------------------------------- /python-flask-app/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose up --build 3 | 4 | run-detached: 5 | docker-compose up --build --detach 6 | 7 | kill: 8 | docker-compose kill 9 | -------------------------------------------------------------------------------- /python-flask-app/README.md: -------------------------------------------------------------------------------- 1 | # Instrumented Python Flask application 2 | 3 | In this sandbox, a Prometheus instance scrapes metrics from a simple Python [Flask](http://flask.pocoo.org/) web application. 4 | 5 | ## Usage 6 | 7 | To start the sandbox: 8 | 9 | ```bash 10 | # In the foreground 11 | make run # docker-compose up --build 12 | 13 | # In detached mode 14 | make run-detached # docker-compose up --build --detach 15 | ``` 16 | 17 | This will start up two services: 18 | 19 | Service | Description 20 | :-------|:----------- 21 | `prometheus` | A Prometheus instance that's [configured](./prometheus/prometheus.yml) to scrape metrics from the Go application running on port 2112 22 | `myapp` | A simple Python Flask web application exports a [`LATENCY_HISTOGRAM`](./myapp/server.py#L6) and a [`REQUEST_COUNTER`](./myapp/server.py#L7) 23 | 24 | Create some example web traffic to the app: 25 | 26 | ```shell 27 | for n in {1..100}; do 28 | curl http://localhost:5000/test-endpoint 29 | done 30 | ``` 31 | 32 | Once the sandbox is up and running, navigate to http://localhost:9090/graph in your browser and enter `myapp_request_count_total` into the expression bar to see the most up-to-date value of the counter. 33 | 34 | You can also see this metrics by "scraping" the Flask web server's `/metrics` endpoint: 35 | 36 | ```bash 37 | curl localhost:5000/metrics | grep myapp_request_count_total 38 | # HELP myapp_request_count_total myapp HTTP request count 39 | # TYPE myapp_request_count_total counter 40 | myapp_request_count_total{endpoint="/metrics",method="GET",status="200"} 17.0 41 | ``` 42 | 43 | Here are some example metrics to explore in the Prometheus [expression browser](https://prometheus.io/docs/visualization/browser): 44 | 45 | * [`myapp_request_count_total{endpoint="/test-endpoint"}`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=myapp_request_count_total%7Bendpoint%3D%22%2Ftest-endpoint%22%7D&g0) 46 | * [`myapp_request_latency_seconds_bucket{endpoint="/test-endpoint",le="0.1"}`](http://localhost:9090/graph?g0.range_input=1h&g0.expr=myapp_request_latency_seconds_bucket%7Bendpoint%3D%22%2Ftest-endpoint%22%2Cle%3D%220.1%22%7D&g0) 47 | -------------------------------------------------------------------------------- /python-flask-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | prometheus: 4 | image: prom/prometheus:${PROMETHEUS_TAG} 5 | ports: 6 | - 9090:9090 7 | command: 8 | - --config.file=/etc/prometheus/prometheus.yml 9 | volumes: 10 | - ./prometheus:/etc/prometheus:ro 11 | myapp: 12 | build: 13 | context: myapp 14 | cache_from: 15 | - python:3.7.0-alpine3.8 16 | ports: 17 | - 5000:5000 -------------------------------------------------------------------------------- /python-flask-app/myapp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.0-alpine3.8 2 | 3 | WORKDIR /usr/src/myapp 4 | 5 | COPY server.py requirements.txt ./ 6 | 7 | RUN pip install -r requirements.txt 8 | 9 | EXPOSE 5000 10 | 11 | CMD ["python", "server.py"] -------------------------------------------------------------------------------- /python-flask-app/myapp/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==1.0.2 2 | prometheus_client==0.4.2 -------------------------------------------------------------------------------- /python-flask-app/myapp/server.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from flask import Flask, Response, jsonify, request 4 | from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST 5 | 6 | LATENCY_HISTOGRAM = Histogram('myapp_request_latency_seconds', 'myapp request latency', ['method', 'endpoint']) 7 | REQUEST_COUNTER = Counter('myapp_request_count', 'myapp HTTP request count', ['method', 'endpoint', 'status']) 8 | 9 | app = Flask(__name__) 10 | 11 | def before_request(): 12 | request.start_time = time.time() 13 | 14 | def after_request(response): 15 | request_latency = time.time() - request.start_time 16 | LATENCY_HISTOGRAM.labels(request.method, request.path).observe(request_latency) 17 | REQUEST_COUNTER.labels(request.method, request.path, response.status_code).inc() 18 | return response 19 | 20 | @app.route("/metrics") 21 | def metrics(): 22 | return generate_latest(), 200 23 | 24 | @app.route("/") 25 | def other_routes(path): 26 | return "Hello world", 200 27 | 28 | if __name__ == '__main__': 29 | app.before_request(before_request) 30 | app.after_request(after_request) 31 | app.run(host='0.0.0.0') -------------------------------------------------------------------------------- /python-flask-app/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 10s 3 | 4 | scrape_configs: 5 | - job_name: myapp 6 | static_configs: 7 | - targets: 8 | - myapp:5000 --------------------------------------------------------------------------------