=====================
Prometheus Monitoring
=====================

https://blueprints.launchpad.net/kolla-ansible/+spec/prometheus

One of the challenges faced by Kolla-Ansible operators, particularly of large
deployments, is monitoring the behavior and performance of the nodes.  To help
address this concern, it is proposed that Kolla-Ansible use Prometheus [1]_ as a
framework for introducing monitoring capabilities.

Prometheus is a widely adopted and supported tool for monitoring, capable of
monitoring both system and service level characteristics.  Many projects have
existing support for exporting data in Prometheus format either directly from
the product itself or via a separate exporter [2]_.  This includes several tools
used as part of the Kolla-Ansible software stack, meaning that with minimal work
we could provide visibility into the performance characteristics of some of the
underlying software frameworks.  There are also exporters to do system
performance monitoring which could provide further visibility into the health of
the cluster.  Prometheus can also use the OpenStack APIs to automatically
discover running OpenStack servers such that servers can also easily expose data
to Prometheus.

Problem description
===================
There are three aspects to any useful system monitoring solution using
Prometheus:

* Exposing the data
* Configuring and running Prometheus to collect and store data
* Analyzing the data and reporting problems

Prometheus and existing exporters can help address the first two items above.
Analysis and reporting is the most complex part of the problem and will require
additional tools on top of Prometheus.  For example, Grafana can be configured
to use Prometheus as a data source and can help provide visibility into the data
collected by Prometheus.

Use Cases
---------
1. Query performance characteristics of nodes or other components in
   Kolla-Ansible software stack (more details about what components can be
   monitored is given below)
2. Display dashboard illustrating overall system performance of Kolla-Ansible
   nodes
3. Determine high-level status of Kolla-Ansible containers and identify
   potential issues encountered during deployment

Proposed change
===============

Exposing the Data
-----------------
Prometheus generally works through a pull model where data is scraped at regular
intervals from data providers.  Therefore, the first step in any Prometheus
solution is to expose the data so that Prometheus can access it.

Some tools natively expose data in a useful format.  In these cases all that is
necessary is proper configuration of the tool to ensure the data is exported on
a known port and configuration of the Kolla-Ansible container to expose the
relevant port such that Prometheus can access the data.

Most tools, however, use exporters or collectors that run as separate processes
from the tool itself.  These collect data using exposed APIs and format the data
in a manner that can be collected by Prometheus.  In these cases, each exporter
would be run on a separate container from the main process.  This will require
building of the requisite containers as well as modifications to the
Kolla-Ansible deployment to run these containers during deployment. Furthermore,
each exporter requires configuration of the Prometheus server to configure it to
scrape the data.

Listed below are some of the exporters that already exist for Prometheus that
are related to components of a typical OpenStack Kolla-Ansible deployment.  This
is based largely on the list of Prometheus Exporters and Integrations [2]_, and
links to more information about each exporter can be found there.  Although we
could choose to expose any of these exporters through Kolla-Ansible, it is not
expected that we will implement all of these initially.  It is proposed that we
start with the exporters for which Kolla containers already exist.  cAdvisor is
also recommended for early implementation since it provides more detailed
metrics for Docker container performance.  We can investigate and add exporters
for additional services as time allows, but how far we proceed will depend
largely on the level of interest amongst Kolla-Ansible developers who might help
do the work.

Existing Kolla Containers
^^^^^^^^^^^^^^^^^^^^^^^^^
The following exporters already have associated Kolla containers (used in
Kolla-Kubernetes) and therefore should be minimal work to make available for a
Kolla-Ansible deployment:

* HAProxy
* MySQL
* Node Exporter - This exposes basic performance metrics (CPU, memory, IO, etc)
  on the host itself
* Prometheus - The Prometheus server contains support for monitoring its own
  performance without any need for an additional exporter

Other Possible Integrations
^^^^^^^^^^^^^^^^^^^^^^^^^^^
(in no particular order)

* cAdvisor
* OpenStack discovery - Prometheus contains support for discovering exposed
  services running on OpenStack instances.  It uses OpenStack client APIs to
  locate the instances and then can contact these instances that are accessible
  on the network and load Prometheus data from exporters running on those
  instances. It is not clear exactly how we would make use of this since we
  don't know what services might be running on the instances but it could be
  useful to set up access to a node exporter if it is running.  This not only
  provides insight into the instances' performance, but also would serve as a
  template for operators wishing to expose their own exporters from OpenStack
  instances.
* Docker - The existing Docker metric support is considered "experimental" and
  is subject to change so we may not want to use this until the API becomes more
  stable.
* Memcached
* ElasticSearch
* Fluentd
* Grafana
* Kafka
* InfluxDB

Kolla-Container Exporter
------------------------
One  piece of critical instrumentation is notably lacking from the existing
providers, and that is the ability to determine which Docker containers are
running on a node.  The existing Docker instrumentation can show how many
containers are running, but provides no visibility into which containers they
are.  The cAdvisor exporter also exposes information about containers (and
provides more detailed view into specific containers than the built-in Docker
metrics), but the high-level state of the container is still not available.
Determining which containers may have failed to start or are in the 'restarting'
state is one of the first troubleshooting steps of a broken Kolla-Ansible
deployment, so this is a significant shortcoming.  Therefore, it is proposed
that a simple Prometheus collector be implemented that exposes this data to
Prometheus.

Initially this collector will be quite simple, but more functionality can be
added if and when we find more critical data missing from the existing set of
exporters or when additional health checking becomes available for Kolla-Ansible
containers [3]_.  The key metric exposed by this collector is a gauge called
kolla_containers and has two labels, name and state which refer respectively to
the name of the container (e.g. cinder_volume) and the container state (e.g.
running).  Since the collector runs on each node, Prometheus will also
automatically add an implied label, instance, that indicates which node the
container is running on.  The value of the gauge is either 0 or 1 (1 indicating
the container with that name is in the indicated state).

A few examples of useful queries on this data include:

* Total number of Kolla-Ansible containers across all nodes:
  ``sum(kolla_containers)``
* Number of containers in each state on each node: ``sum(kolla_containers) by
  (instance)``
* Number of containers in each state for a given service. For example, for
  cinder: ``sum(kolla_containers{name=~'cinder_.*'}) by (state)``
* A list of containers not in a normal (running) state:
  ``kolla_containers{state!="running"}``

This is just a sample list and other queries can be constructed to provide more
specific data.

The Kolla-Container collector uses the docker api to query this data and
connects via the unix socket.  It will use Python docker module to connect to
docker and the Prometheus_client module to expose this data in Prometheus
format.  It will filter the docker containers based on container label to only
expose statistics for Kolla-Ansible containers.  Additionally, the collector
should expose certain standard metrics exposed by most collectors such as the
scrape duration which represents the performance characteristics of the
collector itself.

As with other collectors, this will run in its own docker container deployed via
the standard Ansible deployment.

Running Prometheus
------------------
Prometheus itself will run inside a container on each node in the existing
Kolla-Ansible monitoring inventory group.  A Prometheus container already exists
in the Kolla repository (initially provided for Kolla-Kubernetes) and this
container can be used in Kolla-Ansible deployment as well.

Additions will be required to the Kolla-Ansible deployment process to run this
container.  Since this monitoring tool is useful in determining the state of
deployment and analyzing problems that may occur during deployment, the
container should be started as early as possible during deployment.  Although
Prometheus could be started even earlier, it is proposed that the Prometheus
deployment role be applied just after the MariaDB role since the Prometheus
MySQL exporter requires database user creation to function.

We should also expose Prometheus via HAProxy so that Prometheus data can be
queried using the virtual IP that is used to access other OpenStack APIs and
browser UIs.  This also will require modifications to the existing HAProxy
configuration template in the Kolla-Ansible repository.

In the initial implementation, Prometheus will use local data storage for its
metrics.  This means that Prometheus data is not HA and there will be data
retention limits.  Each Prometheus server container will pull metrics
independently from the exporters and therefore the data may be different between
Prometheus servers.  In a future version (or if developer involvement and time
allow), it may be worth considering using external storage solutions to increase
capacity and allow for HA storage, such as can be provided using InfluxDB and
Influx-Relay as described at [4]_.

Data Analysis and Reporting
---------------------------
The Prometheus server can be directly queried to display and graph any of the
metrics collected by the server.  However, with the addition of Grafana, the
information may be organized into dashboards that collect multiple datapoints
into a single page and present them in a manner that is more useful to the
operator consuming this data.  In order to integrate with Grafana, Prometheus
would need to be defined as a datasource using the Grafana provisioning
framework.  Once that is done an operator can create or import dashboards that
make use of this data.

It would also be possible to define one or more default, preloaded dashboards
for Grafana to display the information deemed most useful for Kolla-Ansible
deployment monitoring.  Grafana also has plugins that provide diagrams [5]_ that
could help visualize the state of the Kolla-Ansible deployment.  The amount of
work that can be done in this area will depend upon the level of developer
interest and involvement in the project.

The addition of the data exported by the proposed Kolla-Container Exporter
provides a useful tool for checking the state of a Kolla-Ansible deployment.  By
analyzing the data from this exporter, a tool can provide high-level deployment
status.  This functionality should be provided via a new status command within
the kolla-ansible command (or via a CLI if one is introduced [6]_).  Information
to be displayed will include:

* If Prometheus is not running or cannot be contacted, the status will indicate
  as such.  This could indicate that Prometheus is disabled, that deployment has
  not yet been initiated, or that deployment failed before the Prometheus
  container was started.  In this case, no further information can be provided.
* Nodes on which the Kolla-Container collector are not running should be
  highlighted since other information cannot be obtained on those nodes.  This
  will require correlating the instances on which the kolla_containers metric is
  exposed against the list of inventory hosts.  This could indicate a problem
  with the collector or with deployment of the collector, or it might just
  indicate that deployment has not yet proceeded to the point where the
  collector has been started.
* Kolla-Ansible containers that are not in the running state should be listed.
  For example, containers in a restarting state may represent a misconfiguration
  of the cluster and should be identified.
* Other health statistics: on a normally running cluster, some basic statistics
  can be provided to help identify potential problems.  The set of statistics
  should include such details as the total number of running Kolla-Ansible
  containers on each system (an unexpectedly low number on one or more systems
  might indicate a problem).  Other details can be added in the future as deemed
  necessary.
* Optional arguments could limit the output to a specific host, inventory group,
  or service.

Another common use of Prometheus is the use of a Prometheus Alertmanager which
is capable of sending alerts in cases where problems occur or predefined
thresholds are exceeded.  However, there are a number of complications regarding
the configuration and running of the Alertmanager, and the details are therefore
left for a future blueprint.

Configuration
-------------
As with all optional services in Kolla-Ansible, Prometheus deployment should be
controlled by Kolla-Ansible variables.  A high level enable_prometheus variable
should control whether Prometheus is used at all.  Additionally, additional
variables can be used to control individual exporters.  For example,
enable_prometheus_haproxy could be used to enable/disable the HAProxy exporter
to Prometheus.  By default Prometheus should be enabled and exporters should be
enabled if both Prometheus and the associated service are enabled.

Limitations
-----------
At it's core, Prometheus gathers numerical statistics about exposed services,
and provides a robust query language that allow an operator to query,
manipulate, and graph this data.  However, collecting and exposing this data is
really only half of any system monitoring solution.  Operators may not
understand the inner workings of the system enough for this data to be useful
without interpretation.  Prometheus can provide a lot of detailed data, but it
is not ideal for looking at a complex system and determining at a glance whether
it is running normally.  Initial integrations with Grafana and with a
kolla-ansible (or CLI) status command will provide useful data, but may prove
insufficient for many situations. However, even without more detailed analysis
tools, some benefit can still be drawn from merely collecting and storing the
data in Prometheus.  Knowledgeable operators can perform their own analysis as
long as the raw data is available.  Also, having the raw data available allows
us to incrementally improve on the complex problem of analysis and reporting
over subsequent releases.

Security Impact
---------------
A detailed analysis of the security model of Prometheus and its impact can be
found at [7]_.  In general, Prometheus considers collected metrics to be
insecure data accessible to anybody with access to the HTTP API.  For this
reason, Prometheus should only be exposed on the internal network interface and
VIP address and not exposed externally.  Operators who want to access Prometheus
data via the external network can access the data via the Grafana integration
which adds an additional security layer and requires a password to access any
data.

Performance Impact
------------------
Enabling Prometheus monitoring will have some impact on system performance.  It
adds a number of additional containers including one for each exporter and for
Prometheus itself.  Furthermore, the Prometheus server performs periodic
endpoint scraping where it queries each provider for the latest metrics.  The
impact of this data gathering will vary by exporter.  Although the impact of any
one exporter should be negligible, it's possible that in combination they might
have a measurable impact on the system.

Any potential risk to performance may be mitigated in several ways.  Each
exporter should be able to be enabled or disabled independently through
Kolla-Ansible properties so if an exporter is found to have a significant
detrimental impact it may be disabled. In order to help determine any potential
impact, Prometheus provides metrics for monitoring its own performance, and most
exporters also include performance metrics for the exporters themselves.

Alternatives
------------
There are a number of possible alternatives to Prometheus for collecting,
maintaining, and exposing performance metrics.  Some of the primary options are
discussed at [8]_.  Another potential monitoring solution is Monasca which
provides a centralized service for both tenant and control plane monitoring.
Prometheus is more widely adopted and supported than many of the alternatives
and has rich support for many of the tools already used in the Kolla-Ansible
software stack.  It's integration with Grafana provides an additional advantage
over some of the alternate solutions.

Implementation
==============

Assignee(s)
-----------
  Mark Giles (mark-giles)

Milestones
----------
Target Milestone for completion: Rocky 1

Work Items
----------
1. Prometheus server configuration for Kolla-Ansible
2. Ansible deployment of existing Prometheus server container
3. Configuration of HAProxy to handle Prometheus server
4. Implement Kolla-Container Exporter
5. kolla-ansible (or CLI) status command to display Kolla-Container Exporter
   results
6. Integration with Grafana
7. Implement Grafana dashboard(s) to provide visualization of Kolla-Ansible
   cluster behavior
8. Exporters (see below)

For each exporter, the following work items exist:

1. Create a Docker image for the exporter
2. Depending on the exporter, it may be necessary to modify settings for the
   monitored service's container to properly expose any necessary APIs
3. Implement Ansible deployment of the container
4. Modify Prometheus server configuration to scrape data from the exporter
5. (Optional) Implement or enhance Grafana dashboard(s) as appropriate.

The MySQL exporter in particular will require additional work:

6. Ansible definition to create Prometheus database user

Testing
=======
The existing gate checks will be used to ensure successful deployment.  Behavior
of the newly exposed functionality will require manual testing.

Documentation Impact
====================
A new documentation reference page should be created for "Prometheus in Kolla".
This page will document how to enable or disable Prometheus and/or individual
exporters as well as how to access the exposed data.

References
==========
.. [1] https://prometheus.io
.. [2] https://prometheus.io/docs/instrumenting/exporters/
.. [3] https://blueprints.launchpad.net/kolla/+spec/container-health-check
.. [4] https://docs.openstack.org/developer/performance-docs/methodologies/monitoring/influxha.html
.. [5] https://grafana.com/plugins/jdbranham-diagram-panel
.. [6] http://lists.openstack.org/pipermail/openstack-dev/2018-March/128561.html
.. [7] https://prometheus.io/docs/operating/security/
.. [8] https://prometheus.io/docs/introduction/comparison/
