Previously, we've seen what the running version of Prometheus Software looks like, but it was a bit finicky to get set up, and it wasn't fully configured yet.
This chapter is going to be about making this easier to use, and getting it fully configured.
So, what do we need?
We, as our computer users, need to be able to access the Prometheus Server, and we're going to do that by running a Docker container, which we've already done successfully.
We also need to be able to access the Pushgateway, which is also going to be in a Docker container and has been proven to work.
What we need to add is the ability for the Prometheus Server to have a configuration file that allows it to speak to the Pushgateway.
In order to have all of these things working, in the easiest way possible, we're going to introduce Docker Compose.
Docker Compose allows us to move away from the Docker Desktop UI, where we need to configure things one by one, and allow us to instead have a single configuration file to hold all of the necessary bits.
Let's get started with a Docker Compose file by going to our codebase.
Here I am in my codebase, and what we're going to do is actually introduce a brand new file.
For that file, I'm going to add it just at the root of the directory - so under
selenium-webdriver-java-course, I'm going to right-click and select "New" > "File", and this needs to be named
With this new file, we can close that tab and we can get started by pseudo-coding the things that we need to introduce.
For example, I know that I need to have a "prometheus server".
I also know that I need to be able to "access that on port 9090", and finally, I need it to have a "configuration file to scrape Prometheus Pushgateway".
In addition to the Prometheus server, I need that "Pushgateway server" as well, and I need to be able to "access that on port 9091".
# prometheus server # access port 9090 # configuration file to scrape prometheus pushgateway # pushgateway server # access port 9091
I can now start to actually write the
docker-compose file for this.
This is going to be in the YAML format, just like our GitHub Actions.
We're going to see some similarities, but this is configuring a different piece of software, so you'll also see a lot of differences.
To start with, with
docker-compose, we need to tell it what version we're using, so I'm going to use version
This is the most up to date version at the time of this video.
From here, I need to start this list of servers I want.
To do that, I say
services, and underneath, I now am indented by two spaces and I can make my list of services.
The first service I want to create is the
Now, I re-indent to be able to configure underneath the Prometheus service.
Within here, I need to tell it what Docker image it's going to be using for running Prometheus.
That is just like we downloaded the
I also need to be able to access this on port
To do that I need to expose the port
9090 - this is what's going to tell the container that
9090 should be accessible from outside of the container.
Then, I need to map these ports from inside the container at
9090 to outside the container at
This is what's going to allow my computer to speak to the container on port
9090, and allow me to view the website.
I'm going to remove these two comments, as we've completed those two tasks, but I'm going to leave the configuration file for a moment later, after we've completed adding the Pushgateway service.
version: '3' services: prometheus: image: prom/prometheus expose: - 9090 ports: - 9090:9090 # configuration file to scrape prometheus pushgateway # pushgateway server # access port 9091
Under here, I'm going to indent by two spaces and create a
I'm going to follow the same pattern as above, so I need to tell it what
image to use, and this time it's going to be
prom/pushgateway, just like we downloaded previously.
I'm also going to need to expose this port, but we know that the Pushgateway is on
9091, and once again, I need to be able to reach this from my computer so I need to map these ports - so
I can remove these comments as I've completed that task now.
version: '3' services: prometheus: image: prom/prometheus expose: - 9090 ports: - 9090:9090 # configuration file to scrape prometheus pushgateway pushgateway: image: prom/pushgateway expose: - 9091 ports:
- 9091:9091 \
At this point, I should be able to run this file and end up in the same position I was in previously.
The one thing we need to make sure is that we've cleaned up after ourselves from previously running the Prometheus Docker images, because ports have to be unique.
If we were running this elsewhere, we wouldn't be able to start running it on
So, I'm going to go back to Docker Desktop and check if I've cleaned up after myself, and I haven't.
That's fine, all I need to do is click "Delete", and delete the other one.
It's good practice to clean this up, if you can, as you go, because these are like running mini computers on your computer and they can take energy from the laptop.
Returning back to my codebase in IntelliJ, I actually get given the opportunity to run this directly from IntelliJ.
I can run a single container using these single green play buttons, or I can run all the services together using the command
docker-compose up, but letting IntelliJ run it.
So I'm going to click "Play".
It's going to open up this bottom window where it's going to talk about opening the containers, and it says that it's been deployed successfully.
I can even see that in Docker Desktop.
I can now see that the
selenium-webdriver-java-course is running two different containers, and this container is on port
9091, which is a Pushgateway, and
9090 for the server.
I can also still open this directly from here in the browser.
So, here I am at the Pushgateway browser, and if I open up the server, here I am with the server.
See how much easier it is when we have a single configuration file?
We can do that with a single push of a button, rather than needing to manually click and open things, but we're not done yet.
We still need to configure the Prometheus server to know where the Pushgateway is.
Back in my codebase, the last thing I need to do is solve this configuration file for how to scrape Prometheus Pushgateway.
To do that, I'm going to introduce a new file inside of a new directory.
I'm going to create a directory and I'm going to call that
prometheus and inside of this
prometheus directory, I'm going to introduce a new file called
The reason this is
yml, is that this is a shortened version of the ending
yaml that we've been using previously.
You can think of this a little bit like "jpeg" - you can have j-p-e-g or you can have j-p-g, but they actually are the same type of file.
We're going to be particular here and use the
yml because the Prometheus server is configured to look for this specific file name, and we don't want to do any more complex configurations for it to look for a different file name, even if it's just to use a different ending.
With this file created, we now can create any custom configuration we want, but it makes sense to start with the default.
I'm going to return to my running Prometheus server, and I'm going to go check out the configuration.
Here, I'm able to copy this to my clipboard, and that will be my starting point.
With that configuration pasted in, I can see it's a fairly trivial thing to add a new scrape target.
I can just copy this entire job and I can paste it down below.
With that, I now have two jobs by the same name, scraping the same target, and that's not exactly what we want to do.
Instead, what we want is this to be named after the type of metric it's pulling - so the
We also need to change how it finds that service.
The way that we do that is we use a docker-compose aspect, which is the name of the service and its port.
So, it's not going to be
localhost, because it's not on the same container as prometheus, but it's going to be
pushgateway, which is the name of the service, and
9091, which is the port.
We now have a configuration file for prometheus, which contains a scrape configuration for itself and a scrape configuration for the pushgateway running next to it.
When I go back to the docker-compose, I need to tell the Prometheus service about this new configuration file.
I do that by introducing a
Volumes are ways for us to map files on our local computers into the Docker containers, and more specifically, we need to map the directory, which is
I'm going to map this to the directory on the container called
This is where the Prometheus service is by default looking for its configuration file.
version: '3' services: prometheus: image: prom/prometheus expose: - 9090 ports: - 9090:9090 volumes: - ./prometheus:/etc/prometheus pushgateway: image: prom/pushgateway expose: - 9091 ports: - 9091:9091
I'm going to remove this comment now that I have completed that task, and I can rerun this
docker-compose is actually quite smart - it's able to tell that the Prometheus Pushgateway is up-to-date and doesn't require any changes, but it does need to recreate the
selenium-webdriver-java-course_prometheus, which is the Prometheus server.
It's now done recreating that so I can return to the browser and check it out.
Here I am in the browser, and when I refresh this, I can see the longer configuration file.
I can see that it is now configured to push to the
pushgateway and check the metrics endpoint at
What really matters is that it can do that.
I can check on the status of this by going to "Status" > "Targets" and seeing that I now have a second endpoint.
I have a
localhost:9090 that is able to scrape metrics, and I also have a
pushgateway that is able to scrape metrics.
I can also confirm this by looking and seeing that I'm getting pushgateway specific metrics, which I wasn't previously.
One thing you'll notice is that the metrics that we created in the last chapter won't exist anymore.
If I look for chapter-9, it doesn't exist.
That's because we have recreated these Docker containers, and so all of the storage has disappeared.
These are what we call ephemeral, meaning that they don't retain storage over time.
In order to fully test that we can get this metric in Pushgateway into Prometheus and map it, I'm going to need to push a new metric.
Right now this metrics page is empty, but I'm going to go to the Terminal and send a new
To do that, I need a string, which is the metric name - I'm going to call that
I also need a metric value - this time instead of using date, I'm just going to use a manually entered number
Then I need to send that into a
curl request as the data and that
curl request needs to hit our
localhost:9091 metrics endpoint, and I need to send it in what job this is - so I'm going to call this
echo "chapter_10 123" | curl --data-binary @- http://localhost:9091/metrics/job/chapter10
With that, I've sent the
curl request to the server and I can return and see it in the browser.
I'm now going to refresh the Pushgateway and see that job "chapter10" has appeared.
Inside of there, I can see that the "chapter10" metric exists with a value of "123".
In addition, when I go into Prometheus, I can look up "chapter_10", and I can see that that has a value of "123".
Now is when we can actually explore and understand this scrape config.
What I can do is I can send a number of curl requests in quick succession, and see what metrics show up.
I'm going to arrow up to return back to my old request.
I'm going to change this to "324",. I'm going to change it to just the number "4",. I'm going to change it to "87"... I'm just changing these to random numbers as fast as I can.
What do you expect to have happen in the user interface?
Do you expect to see all of these values?
Let's go find out.
If I return back to the Pushgateway and I refresh the page, I can still only see a single value - the most recent one that I've given.
This is because this is a point in time collection - it will only ever hold the most recent value of that metric.
Prometheus then scrapes this every 15 seconds.
So, if I run this command again, I again see the most recent, but let's go to the graph and see if I can see it over time.
Notice it's picked up a few of my changes.
Let's zoom in here, to be able to see this a little bit clearer.
It started as 123, and then it dropped to 87, but then it rose to 3345.
If I return back to all of my curl requests, I can see that I did a whole bunch of requests and it wasn't just to 87. So 123, 324, 4, and then 87, so we lost these two measurements.
In addition, we did a whole bunch of requests after 87, this 89324, and then 3345.
Because we can only store the most recent value in time in the Pushgateway and Prometheus only scrapes every 15 seconds, you end up with a point in time history, in every 15 second snapshot.
This is an important understanding about how metrics work.
Fantastic, at this point, we have a fully running Prometheus server and Prometheus Pushgateway that it will be easy for us to use throughout the next few chapters.
Next up is trying to get this ready to be used by GitHub Actions and our pipeline specific metrics.