Parca
- Canonical Observability
Channel | Revision | Published | Runs on |
---|---|---|---|
latest/stable | 128 | 14 Sep 2023 | |
latest/beta | 137 | 29 Feb 2024 | |
latest/edge | 154 | 29 Jul 2024 |
juju deploy parca
Deploy universal operators easily with Juju, the Universal Operator Lifecycle Manager.
Platform:
charms.parca.v0.parca_scrape
-
- Last updated 05 Jun 2023
- Revision Library version 0.5
Overview.
This document explains how to integrate with the Parca charm for the purpose of providing a profiling endpoint to Parca. It also explains how alternative implementations of the Parca charms may maintain the same interface and be backward compatible with all currently integrated charms.
Provider Library Usage
This Parca charm interacts with its scrape targets using its charm library. Charms seeking to
expose profiling endpoints for the Parca charm, must do so using the ProfilingEndpointProvider
object from this charm library. For the simplest use cases, using the ProfilingEndpointProvider
object only requires instantiating it, typically in the constructor of your charm. The
ProfilingEndpointProvider
constructor requires the name of the relation over which a scrape
target (profiling endpoint) is exposed to the Parca charm. This relation must use the
parca_scrape
interface. By default address of the profiling endpoint is set to the unit IP
address, by each unit of the ProfilingEndpointProvider
charm. These units set their address in
response to the PebbleReady
event of each container in the unit, since container restarts of
Kubernetes charms can result in change of IP addresses. The default name for the profiling endpoint
relation is profiling-endpoint
. It is strongly recommended to use the same relation name for
consistency across charms and doing so obviates the need for an additional constructor argument.
The ProfilingEndpointProvider
object may be instantiated as follows
from charms.parca.v0.parca_scrape import ProfilingEndpointProvider
def __init__(self, *args):
super().__init__(*args)
# ...
self.profiling_endpoint = ProfilingEndpointProvider(self)
# ...
Note that the first argument (self
) to ProfilingEndpointProvider
is always a reference to the
parent (scrape target) charm.
An instantiated ProfilingEndpointProvider
object will ensure that each unit of its parent charm,
is a scrape target for the ProfilingEndpointConsumer
(Parca) charm. By default
ProfilingEndpointProvider
assumes each unit of the consumer charm exports its profiles on port
80. These defaults may be changed by providing the ProfilingEndpointProvider
constructor an
optional argument (jobs
) that represents a Parca scrape job specification using Python standard
data structures. This job specification is a subset of Parca's own scrape
configuration format but represented using Python data
structures. More than one job may be provided using the jobs
argument. Hence jobs
accepts a
list of dictionaries where each dictionary represents one <scrape_config>
object as described in
the Parca documentation. The currently supported configuration subset is: job_name
,
static_configs
Suppose it is required to change the port on which scraped profiles are exposed to 8000. This may be
done by providing the following data structure as the value of jobs
.
[{"static_configs": [{"targets": ["*:8000"]}]}]
The wildcard ("*") host specification implies that the scrape targets will automatically be set to the host addresses advertised by each unit of the consumer charm.
It is also possible to change the profile path and scrape multiple ports, for example
[{"static_configs": [{"targets": ["*:8000", "*:8081"]}]}]
More complex scrape configurations are possible. For example
[{
"static_configs": [{
"targets": ["10.1.32.215:7000", "*:8000"],
"labels": {
"some-key": "some-value"
}
}]
}]
This example scrapes the target "10.1.32.215" at port 7000 in addition to scraping each unit at port 8000. There is however one difference between wildcard targets (specified using "*") and fully qualified targets (such as "10.1.32.215"). The Parca charm automatically associates labels with profiles generated by each target. These labels localise the source of profiles within the Juju topology by specifying its "model name", "model UUID", "application name" and "unit name". However unit name is associated only with wildcard targets but not with fully qualified targets.
Multiple jobs with labels are allowed, but each job must be given a unique name:
[
{
"job_name": "my-first-job",
"static_configs": [
{
"targets": ["*:7000"],
"labels": {
"some-key": "some-value"
}
}
]
},
{
"job_name": "my-second-job",
"static_configs": [
{
"targets": ["*:8000"],
"labels": {
"some-other-key": "some-other-value"
}
}
]
}
]
Important: job_name
should be a fixed string (e.g. hardcoded literal). For instance, if you
include variable elements, like your unit.name
, it may break the continuity of the profile time
series gathered by Parca when the leader unit changes (e.g. on upgrade or rescale).
Consumer Library Usage
The ProfilingEndpointConsumer
object may be used by Parca charms to manage relations with their
scrape targets. For this purposes a Parca charm needs to do two things
- Instantiate the
ProfilingEndpointConsumer
object by providing it a reference to the parent (Parca) charm and optionally the name of the relation that the Parca charm uses to interact with scrape targets. This relation must confirm to theparca_scrape
interface and it is strongly recommended that this relation be namedprofiling-endpoint
which is its default value.
For example a Parca charm may instantiate the ProfilingEndpointConsumer
in its constructor as
follows
from charms.parca.v0.parca_scrape import ProfilingEndpointConsumer
def __init__(self, *args):
super().__init__(*args)
# ...
self.profiling_consumer = ProfilingEndpointConsumer(self)
# ...
A Parca charm also needs to respond to the
TargetsChangedEvent
event of theProfilingEndpointConsumer
by adding itself as an observer for these events, as inself.framework.observe( self.profiling_consumer.on.targets_changed, self._on_scrape_targets_changed, )
In responding to the TargetsChangedEvent
event the Parca charm must update the Parca
configuration so that any new scrape targets are added and/or old ones removed from the list of
scraped endpoints. For this purpose the ProfilingEndpointConsumer
object exposes a jobs()
method that returns a list of scrape jobs. Each element of this list is the Parca scrape
configuration for that job. In order to update the Parca configuration, the Parca charm needs to
replace the current list of jobs with the list provided by jobs()
as follows
def _on_scrape_targets_changed(self, event):
...
scrape_jobs = self.profiling_consumer.jobs()
for job in scrape_jobs:
parca_scrape_config.append(job)
...
Relation Data
Units of profiles provider charms advertise their names and addresses over unit relation data using
the parca_scrape_unit_name
and parca_scrape_unit_address
keys. While the scrape_metadata
,
scrape_jobs
and alert_rules
keys in application relation data of profiles provider charms hold
eponymous information.
Index
class RelationNotFoundError
Description
Raise if there is no relation with the given name is found. None
Methods
RelationNotFoundError. __init__( self , relation_name: str )
class RelationInterfaceMismatchError
Description
Raise if the relation with the given name has a different interface. None
Methods
RelationInterfaceMismatchError. __init__( self , relation_name: str , expected_relation_interface: str , actual_relation_interface: str )
class RelationRoleMismatchError
Description
Raise if the relation with the given name has a different role. None
Methods
RelationRoleMismatchError. __init__( self , relation_name: str , expected_relation_role , actual_relation_role )
class ProviderTopology
Description
Class for initializing topology information for ProfilingEndpointProvider. None
Methods
ProviderTopology. scrape_identifier( self )
Description
Format the topology information into a scrape identifier. None
class TargetsChangedEvent
Description
Event emitted when Parca scrape targets change. None
Methods
TargetsChangedEvent. __init__( self , handle , relation_id )
TargetsChangedEvent. snapshot( self )
Description
Save scrape target relation information. None
TargetsChangedEvent. restore( self , snapshot )
Description
Restore scrape target relation information. None
class MonitoringEvents
Description
Event descriptor for events raised by ProfilingEndpointConsumer
. None
class ProfilingEndpointConsumer
Description
Parca based monitoring service. None
Methods
ProfilingEndpointConsumer. __init__( self , charm , relation_name: str )
Construct a Parca based monitoring service.
Arguments
a ops.CharmBase
instance that manages this instance of the Parca service.
an optional string name of the relation between charm
and the Parca charmed service. The default is "profiling-endpoint".
ProfilingEndpointConsumer. on_profiling_provider_relation_changed( self , event )
Handle changes with related profiling providers.
Arguments
a CharmEvent
resulting in the Parca charm updating its scrape configuration
Description
Anytime there are changes in relations between Parca and profiling provider charms the
Parca charm is informed, through a TargetsChangedEvent
event. The Parca charm can then
choose to update its scrape configuration.
ProfilingEndpointConsumer. jobs( self )
Fetch the list of scrape jobs.
Returns
A list consisting of all the static scrape configurations for each related
ProfilingEndpointProvider
that has specified its scrape targets.
class ProfilingEndpointProvider
Description
Profiling endpoint for Parca. None
Methods
ProfilingEndpointProvider. __init__( self , charm , relation_name: str , jobs , refresh_event )
Construct a profiling provider for a Parca charm.
Arguments
a ops.CharmBase
object that manages this
ProfilingEndpointProvider
object. Typically this is self
in the instantiating
class.
an optional string name of the relation between charm
and the Parca charmed service. The default is "profiling-endpoint". It is strongly
advised not to change the default, so that people deploying your charm will have a
consistent experience with all other charms that provide profiling endpoints.
an optional list of dictionaries where each dictionary represents the Parca
scrape configuration for a single job. When not provided, a default scrape
configuration is provided polling all units of the charm on port 80
using the
ProfilingEndpointProvider
object.
an optional bound event or list of bound events which will be observed to re-set scrape job data (IP address and others)
Description
If your charm exposes a Parca profiling endpoint, the ProfilingEndpointProvider
object
enables your charm to easily communicate how to reach that endpoint.
By default, a charm instantiating this object has the profiling endpoints of each of its units scraped by the related Parca charms.
The scraped profiles are automatically tagged by the Parca charms with Juju topology data
via the juju_model_name
, juju_model_uuid
, juju_application_name
and juju_unit
labels. To support such tagging ProfilingEndpointProvider
automatically forwards scrape
metadata to a ProfilingEndpointConsumer
(Parca charm).
Scrape targets provided by ProfilingEndpointProvider
can be customized when instantiating
this object. For example in the case of a charm exposing the profiling endpoint for each of
its units on port 8080, the ProfilingEndpointProvider
can be
instantiated as follows:
self.profiling_endpoint_provider = ProfilingEndpointProvider(
self, jobs=[{"static_configs": [{"targets": ["*:8080"]}]}]
)
The notation *:<port>
means "scrape each unit of this charm on port <port>
.