feat(sidecar+coordinator): add support for HTTPS /metrics - #2752
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The updated docs/metrics.md section documents enabling TLS but does not describe the implemented “log error and disable /metrics with no HTTP fallback” behavior, which is operationally significant.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds an opt-in TLS mode for the sidecar’s /metrics endpoint so operators can serve Prometheus metrics over HTTPS using a provided tls.crt/tls.key, while keeping the data-plane proxy’s TLS configuration independent.
Changes:
- Introduces
--metrics-cert-path(and YAMLmetrics-cert-path) to enable HTTPS for/metricswhen set. - Updates the metrics server startup path to use TLS with cert hot-reload, and to log-and-disable metrics on startup failure (instead of failing the whole proxy).
- Adds tests and documentation updates for the new flag.
File summaries
| File | Description |
|---|---|
| pkg/sidecar/proxy/proxy.go | Extends sidecar runtime config with MetricsCertPath. |
| pkg/sidecar/proxy/options.go | Adds CLI/YAML wiring for --metrics-cert-path. |
| pkg/sidecar/proxy/options_test.go | Adds precedence/merge tests for YAML vs CLI for the new option. |
| pkg/sidecar/proxy/MORIIO_README.md | Documents HTTPS behavior and no-fallback semantics for /metrics. |
| pkg/sidecar/proxy/dns_metrics.go | Implements HTTPS serving and cert reloading for the metrics server; logs errors without taking down the proxy. |
| pkg/sidecar/proxy/dns_metrics_test.go | Adds coverage for HTTP/TLS metrics serving and invalid cert path behavior. |
| docs/metrics.md | Documents the new --metrics-cert-path flag for the sidecar metrics endpoint. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| The endpoint serves plain HTTP by default. Pass `--metrics-cert-path` with a | ||
| directory containing `tls.crt` and `tls.key` to serve it over TLS instead. | ||
| This is independent of `--secure-proxy` and `--cert-path`, which apply to | ||
| the sidecar's data-plane listener. |
e46aa72 to
795b16f
Compare
|
makrdown link checked fixed in #2782 |
|
@zdtsw pls rebase |
I would follow the same pattern as in router:
|
Yes, please. |
795b16f to
e7d3d2f
Compare
ab409aa to
c2a299b
Compare
|
@roytman is this good to go? |
I'll go over it tomorrow. |
roytman
left a comment
There was a problem hiding this comment.
This is a good PR: clear docs, thorough tests on both the coordinator and sidecar sides (plain HTTP, TLS success, missing/invalid cert, and the drain-on-fatal-error path for the coordinator), and a sensible split in failure behavior between the two components.
A few small comments left inline.
One broader question, more about the existing convention than this specific PR: the certificate and key file names (tls.crt, tls.key) are hardcoded, and only their containing directory is configurable via --metrics-cert-dir (. A more common pattern (e.g. vLLM) is to configure the full paths to each file separately:
vllm serve <model> \\
--ssl-keyfile /path/to/key.pem \\
--ssl-certfile /path/to/cert.pem
I know this isn't something this PR introduces; the sidecar's data-plane TLS (--cert-path) and the Router's --cert-path/--metrics-cert-dir already follow the same directory-plus-fixed-names convention, so this PR stays consistent with what's already there. It's not an architectural constraint of the reload mechanism, though: common.NewCertReloader watches the directory with fsnotify, which fires on any file change regardless of name, but its reload step has "tls.crt"/"tls.key" hardcoded as literal strings (pkg/common/certs.go). Making those configurable would be a small change to that one helper, not a redesign.
Not asking to change this PR, but raising it as a question for the project: if we ever need to support certs that don't come from a single "one directory, standard names" mount (e.g. cert-manager output with different filenames, or split cert/key locations), would we want a --ssl-certfile/--ssl-keyfile-style option alongside or instead of the directory one?
Worth a separate issue/discussion if others think it's worth supporting, not something to resolve here.
CC: @ahg-g @elevran
| } | ||
| grp.Go(func() error { | ||
| return s.serveMetrics(ctx, addr) | ||
| if err := s.serveMetrics(ctx, addr); err != nil { |
There was a problem hiding this comment.
Today this swallows every error serveMetrics can return: a broken --metrics-cert-dir and an unrelated --metrics-port bind conflict get exactly the same treatment: one log line, then the proxy carries on with no /metrics endpoint at all, indefinitely.
Concrete case: cert dir is misconfigured (e.g. tls.key missing from the mounted volume). The sidecar starts fine, serves inference traffic normally, and just silently has no /metrics. Nothing pages anyone; the only signal is one log line, unless something is specifically watching for it. Compared to the coordinator (or vllm itself, where /metrics isn't a separate server or listener), which refuses to start on the same misconfiguration, loud, immediate, shows up as CrashLoopBackOff, gets caught during rollout instead of during an incident three weeks later when someone goes looking for a metric that isn't there.
Before this PR, any serveMetrics error propagated through the shared errgroup in Run and stopped the whole proxy, data plane included. This change was presumably meant to stop a metrics-only problem from taking down inference serving, which is a reasonable goal, but the failure modes here (bad cert, bad port) only happen at startup; CertReloader handles cert rotation failures internally later on without erroring out, so nothing here can kill an already-running data plane.
Given that, I don't think there's much risk in just letting the error propagate again and failing the sidecar on any metrics startup error, TLS or not, the same as vllm and the coordinator do. That's simpler than adding a sentinel to special-case only TLS failures, and it means a broken --metrics-port doesn't go unnoticed either.
| // the HTTPS metrics server. Changes to either file take effect without | ||
| // restarting the sidecar. | ||
| func (s *Server) metricsTLSConfig(ctx context.Context) (*tls.Config, error) { | ||
| certFile := s.config.MetricsCertDir + "/tls.crt" |
There was a problem hiding this comment.
Nit: This builds the path with string concatenation (s.config.MetricsCertDir + "/tls.crt"), while the coordinator's equivalent (cmd/coordinator/main.go, metricsTLSConfig) uses filepath.Join(certDir, "tls.crt"). Both are plain string fields, so this isn't a type difference, just two different styles for the same thing in the same PR.
Functionally, it doesn't matter here: if MetricsCertDir has a trailing slash, concatenation produces a double slash (/etc/certs//tls.crt), but POSIX collapses repeated slashes during path resolution, so tls.LoadX509KeyPair and the fsnotify directory watch both resolve it identically either way. So this is a style/consistency nit, not a correctness issue, worth matching the coordinator's filepath.Join just so the two near-identical functions read the same way, not because the current code is broken.
| t.Fatalf("no listener came up on %s within %s", addr, timeout) | ||
| } | ||
|
|
||
| func writeMetricsCertificate(t *testing.T, dir string) { |
There was a problem hiding this comment.
This hand-rolls ECDSA key + cert generation from scratch. The repo already has a helper for exactly this - internal/tls.CreateSelfSignedTLSCertificate (importable from cmd/coordinator since internal/tls sits at the module root), and it's already being reused in this same PR in pkg/sidecar/proxy/dns_metrics_test.go's writeSelfSignedCert (call the helper, then re-PEM-encode cert.Certificate[0] / cert.PrivateKey). Would avoid a third from-scratch implementation of test cert generation in the codebase.
|
I've opened a follow-up issue: #2817 |
- sidecar metrics currently does not provide HTTPS but only HTTP - make it close to how its data-plane which support HTTPS, by adding a new flag --metrics-cert-path - only need point to the path where certs are, if not set the flag, use HTTP, if set the flag but cannot find either certs file, log an error and disable /metrics but sidecar data-plane keep working Signed-off-by: Wen Zhou <wenzhou@redhat.com>
- Allow the coordinator metrics listener to use tls.crt and tls.key Signed-off-by: Wen Zhou <wenzhou@redhat.com>
Signed-off-by: Wen Zhou <wenzhou@redhat.com>
- reuse helper CreateSelfSignedTLSCertificate() instead of rewrite logic - update logic on sidecar: if tls enabled but cert file(S) invalid, stop sidecar including data-plane not just metrics - add new test and update docs Signed-off-by: Wen Zhou <wenzhou@redhat.com>
c2a299b to
fd0213f
Compare
Thanks for the detail review!
|
roytman
left a comment
There was a problem hiding this comment.
/lgtm for this PR! I'd be happy to get thoughts on the broader questions as well.
What type of PR is this?
/kind feature
What this PR does / why we need it:
/metricsendpoint currently only support HTTP.--metrics-cert-dirflag to each, pointing to a directory with hardcoded file nametls.crt/tls.key. The flag matches the router's existing flag. Also settable as the sidecar YAML keymetrics-cert-dirand as the coordinator'sserver.metrics_cert_dir(envCOORDINATOR_SERVER_METRICS_CERT_DIR)./metricsover HTTP.tls.crt/tls.keydoesn't need a restart.Which issue(s) this PR fixes:
Fixes #
Release note (write
NONEif no user-facing change):