Move alertmanager and credential/exporter config APIs into common /v1/ path under the root cluster domain #379
Comments
I added the rules and alert related endpoints to the list. |
@spahl what is the difference between |
Also, let's put all these apis under a common root path. Remember the UI is served at the root too, so lets have a very small number of namespaces (represented by the root of the path) for which we don't render the UI and instead proxy to an api or a system component. |
Ok after investigating a bit more, I think we shouldn't need to expose the /ring and /status on the multitenant_alertmanager api of Cortex (https://cortexmetrics.io/docs/api/#alertmanager-status). We can figure out how to build this state into the UI. In general, I'm of the mindset that we shouldn't expose everything that our internal components expose, unless it's absolutely necessary, because it's another surface that we have to maintain for our users. The other thing to keep in mind is that anything we serve under the root path cannot be authenticated by the ingress because the UI needs to be accessed without authentication (login). Authentication therefore has to be done in the application that is serving the endpoint. The UI does its own authentication, @nickbp's config apis do their own authentication (but still require someone to set the Another important point is that the At this point, I'd rather serve all these tenant-specific apis under the tenant's domain i.e.
The Ingress resource in the |
Extending on my suggestion above, our endpoints now use a combination of dns and path based routing: These two endpoints proxy to the cortex service in the cortex namespace: Credentials and exporters can proxy to the config service in the application namespace: Alertmanager UI is served the same as we currently serve Grafana in each tenant (we just have to create an |
Three pros for the above suggestion:
|
FWIW the current (And the |
@nickbp since the UI doesn't use a Bearer token for auth (uses a session cookie), it will not be able to access the apis. This is one more compelling reason for the UI to interact with the query/exporters apis through Hasura (although there is likely still the challenge of injecting a bearer token from Hasura -> credentials/exporters api). Maybe the authenticator.go middleware also needs to check for a valid session if no Bearer token is provided? |
That does sound like it would be tricky. I assume any session info provided by the UI (e.g. via an HTTP header) isnt going to specify a single tenant, since a UI user may be managing multiple tenants. It does sound like the ideal scenario would be to treat this Go API as something that end-users would be calling, while the UI would talk to graphql directly - and ideally graphql would implement sanity checks via hasura actions like you'd recommended. I'll add notes about this to the hasura actions issue here: #373 In the context of this immediate issue around moving the paths of the current API, it shouldn't be a blocker, but it does sound like we'll need to have a plan for how any such validation would work sooner rather than later so that it isn't blocking the UI. |
Just a couple of misc thoughts having read through all of this...
+1, should we go down this path. In some other cases, we may be able to simplify the root to something shorter, such as a single letter.
+1
If we maintain the subdomains... if we can serve the UI with path-based routing to match /grafana, that seems preferable to me. |
… in GraphQL, the controller will automatically apply that change to Kubernetes. Credentials are converted to Kubernetes `Secret`s, while exporters are converted to Kubernetes `Deployment`s (which may link to the `Secret`s referenced by the exporter config). The synchronization itself works against the existing Kubernetes reconciliation loop in the Controller. The main addition is that the reconciliation state now includes entries originating from GraphQL, but the reconciliation flow itself remains the same structurally and ends up being pretty straightforward. This structure would potentially be extendable to other state retrieved from GraphQL in the future. Summary: - Add GraphQL queries for dumping a "snapshot" of credentials and exporters when starting the sync, in addition to the existing subscription queries. - Add subscription client to controller, largely copied from app. - Implement `informers` for fetching and subscribing to the GraphQL credentials and exporters, and applying this data to the Redux state object. - Implement `resources` for converting the Redux state to Kubernetes objects, with type-specific logic for how to deploy each credential and exporter type. I've so far tested this by hand by creating credentials/exporters via `curl` against the go graphql `config` service (which is due to get moved/renamed), and was able to verify that actual metrics successfully appeared in prometheus/cortex from each of the current two types of exporters. As such this should complete issue #312 and epic #310 . There remains some doc work via #358 which in turn depends on the graphql config API naming that's being updated via #379 . Signed-off-by: Nick Parker <nick@opstrace.com>
…ated/deleted in GraphQL, the controller will automatically apply that change to Kubernetes. Credentials are converted to Kubernetes `Secret`s, while exporters are converted to Kubernetes `Deployment`s (which may link to the `Secret`s referenced by the exporter config). The synchronization itself works against the existing Kubernetes reconciliation loop in the Controller. The main addition is that the reconciliation state now includes entries originating from GraphQL, but the reconciliation flow itself remains the same structurally and ends up being pretty straightforward. This structure would potentially be extendable to other state retrieved from GraphQL in the future. Summary: - Add GraphQL queries for dumping a "snapshot" of credentials and exporters when starting the sync, in addition to the existing subscription queries. - Add subscription client to controller, largely copied from app. - Implement `informers` for fetching and subscribing to the GraphQL credentials and exporters, and applying this data to the Redux state object. - Implement `resources` for converting the Redux state to Kubernetes objects, with type-specific logic for how to deploy each credential and exporter type. I've so far tested this by hand by creating credentials/exporters via `curl` against the go graphql `config` service (which is due to get moved/renamed), and was able to verify that actual metrics successfully appeared in prometheus/cortex from each of the current two types of exporters. As such this should complete issue #312 and epic #310 . There remains some doc work via #358 which in turn depends on the graphql config API naming that's being updated via #379 . Signed-off-by: Nick Parker <nick@opstrace.com>
…ated/deleted in GraphQL, the controller will automatically apply that change to Kubernetes. Credentials are converted to Kubernetes `Secret`s, while exporters are converted to Kubernetes `Deployment`s (which may link to the `Secret`s referenced by the exporter config). The synchronization itself works against the existing Kubernetes reconciliation loop in the Controller. The main addition is that the reconciliation state now includes entries originating from GraphQL, but the reconciliation flow itself remains the same structurally and ends up being pretty straightforward. This structure would potentially be extendable to other state retrieved from GraphQL in the future. Summary: - Add GraphQL queries for dumping a "snapshot" of credentials and exporters when starting the sync, in addition to the existing subscription queries. - Add subscription client to controller, largely copied from app. - Implement `informers` for fetching and subscribing to the GraphQL credentials and exporters, and applying this data to the Redux state object. - Implement `resources` for converting the Redux state to Kubernetes objects, with type-specific logic for how to deploy each credential and exporter type. I've so far tested this by hand by creating credentials/exporters via `curl` against the go graphql `config` service (which is due to get moved/renamed), and was able to verify that actual metrics successfully appeared in prometheus/cortex from each of the current two types of exporters. As such this should complete issue #312 and epic #310 . There remains some doc work via #358 which in turn depends on the graphql config API naming that's being updated via #379 . Signed-off-by: Nick Parker <nick@opstrace.com>
…ated/deleted in GraphQL, the controller will automatically apply that change to Kubernetes. Credentials are converted to Kubernetes `Secret`s, while exporters are converted to Kubernetes `Deployment`s (which may link to the `Secret`s referenced by the exporter config). The synchronization itself works against the existing Kubernetes reconciliation loop in the Controller. The main addition is that the reconciliation state now includes entries originating from GraphQL, but the reconciliation flow itself remains the same structurally and ends up being pretty straightforward. This structure would potentially be extendable to other state retrieved from GraphQL in the future. Summary: - Add GraphQL queries for dumping a "snapshot" of credentials and exporters when starting the sync, in addition to the existing subscription queries. - Add subscription client to controller, largely copied from app. - Implement `informers` for fetching and subscribing to the GraphQL credentials and exporters, and applying this data to the Redux state object. - Implement `resources` for converting the Redux state to Kubernetes objects, with type-specific logic for how to deploy each credential and exporter type. I've so far tested this by hand by creating credentials/exporters via `curl` against the go graphql `config` service (which is due to get moved/renamed), and was able to verify that actual metrics successfully appeared in prometheus/cortex from each of the current two types of exporters. As such this should complete issue #312 and epic #310 . There remains some doc work via #358 which in turn depends on the graphql config API naming that's being updated via #379 . Signed-off-by: Nick Parker <nick@opstrace.com>
Had a quick check-in on Slack, sounds like it's fine to just put the two APIs in question under It sounds like |
Note from @MatApple: Will need to add |
Something I realized this morning with the The Go reverse proxy code supports intercepting the response, so it should be possible to have a rewrite of HTML content if necessary, but if that ends up being needed then IMO it may push things in favor of just having those endpoints accessible at their original root paths and thereby avoid the need for rewrites. This would be at the cost of needing to add special cases for |
Yes that is correct. And there is a setting for this in the cortex config.
|
* controller: Update routes for config APIs - Updates application ingress to route `<cluster>/api/*` to the config-api pod (was: `config.<cluster>/api/*`) - Moves cortex alertmanager and ruler APIs into the config-api pod - Updates the config-api pod with alertmanager and ruler endpoints to be proxied - Refactors auth and proxy handling a bit for reuse across services Signed-off-by: Nick Parker <nick@opstrace.com> * config: Route /api/v1/[ruler,alertmanager,multitenant_alertmanager] -> /* The default logic in `NewSingleHostReverseProxy` just supports appending paths (e.g. `/foo` + `/bar` = `/foo/bar`), but in this case we want to overwrite the source path rather than appending it to the dest path. So make/use a custom director that supports custom rewrites. Signed-off-by: Nick Parker <nick@opstrace.com> * config: Fix lint, simplify redirect handling Signed-off-by: Nick Parker <nick@opstrace.com> * controller: Assign alertmanager UI http prefix, fix config path rewrite Signed-off-by: Nick Parker <nick@opstrace.com>
DEADLINE: Try to have this figured out by the end of the week (Feb 19)
There are currently multiple endpoints for setting configuration for tenants:
config.cluster.example/api/v1/credentials/*
config.cluster.example/api/v1/exporters/*
cortex.cluster.example/ruler/*
cortex.cluster.example/api/v1/rules/*
cortex.cluster.example/api/v1/alerts/*
cortex.cluster.example/alertmanager/*
cortex.cluster.example/multitenant_alertmanager/*
This current structure has a few issues:
config
subdomain used by credential/exporter config may conflict with a tenant namedconfig
, and it's a bit confusing since the subdomains are ideally supposed to all be about tenants anyway.So we'd ideally like to only use subdomains for per-tenant data ingest, and then have these config endpoints at the root domain (shared with the UI). Requests to the config endpoints would identify the tenant name using the
Bearer
token, as is currently the case.The changes will be to move the endpoints to the root domain, under a reserved
/api/*
path like the following:config.cluster.example/api/v1/credentials/*
tocluster.example/api/v1/credentials/*
config.cluster.example/api/v1/exporters/*
tocluster.example/api/v1/exporters/*
cortex.cluster.example/ruler/*
tocluster.example/api/v1/ruler/*
cortex.cluster.example/api/v1/rules/*
tocluster.example/api/v1/rules/*
cortex.cluster.example/api/v1/alerts/*
tocluster.example/api/v1/alerts/*
cortex.cluster.example/alertmanager/*
tocluster.example/api/v1/alertmanager/*
(may go tocluster.example/alertmanager/*
in the future)cortex.cluster.example/multitenant_alertmanager/*
tocluster.example/api/v1/multitenant_alertmanager/*
(may go tocluster.example/multitenant_alertmanager/*
in the future)The changes would be applied in a few places:
/go/cmd/config/
)config.cluster.example/*
K8s Ingest object to instead accept data sent tocluster.example/api/v1/*
. Any requests sent to this endpoint will then be sent to the API config pod, and not the UIconfig-api
toopstrace-api
to align withopstrace-application
used for the UISee also: Current credentials/exporters APIs listed in a README here: https://github.com/opstrace/opstrace/blob/main/go/cmd/config/README.md
The text was updated successfully, but these errors were encountered: