Skip to content

Commit eeeccfc

Browse files
committed
Add docs and small naming/format changes
1 parent 2ee47e0 commit eeeccfc

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

docs/gitbook/usage/metrics.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,22 @@ Reference the template in the canary analysis:
326326
interval: 1m
327327
```
328328

329+
### Datadog Rate Limits
330+
331+
For bigger setups, you might run into rate limits on the Datadog API. To avoid this,
332+
you can use the Datadog Cluster Agent to retrieve metrics in batches instead. It will then
333+
expose these metrics as an external metrics server.
334+
335+
See [Datadog Documentation](https://docs.datadoghq.com/containers/guide/cluster_agent_autoscaling_metrics).
336+
337+
Once you have enabled Datadog's external metrics endpoint and `DatadogMetric` CRD (without
338+
necessarily using `registerAPIService`), you can use Flagger's
339+
[External Metrics Provider](#kubernetes-external-metrics) to query the metrics from there.
340+
341+
The server address is usually `datadog-cluster-agent-metrics-server` and exposed on port 8443.
342+
ExternalMetrics will be named as `datadogmetric@<namespace>:<metricname>`, for example
343+
`datadogmetric@istio-system:istio-mesh-request-count`.
344+
329345
## Amazon CloudWatch
330346

331347
You can create custom metric checks using the CloudWatch metrics provider.
@@ -781,3 +797,37 @@ Reference the template in the canary analysis:
781797
max: 99
782798
interval: 1m
783799
```
800+
801+
## Kubernetes External Metrics
802+
803+
You can query an external metrics provider that implements the
804+
[Kubernetes External Metrics API](https://kubernetes.io/docs/reference/external-api/external-metrics.v1beta1/).
805+
806+
By default, Flagger will use its bound Service Account for authentication. *Optionally* you can provide a Bearer token through a Secret (that must contain a field named `token`) :
807+
808+
```yaml
809+
apiVersion: v1
810+
kind: Secret
811+
metadata:
812+
name: external-metric-server-token
813+
namespace: default
814+
data:
815+
token: your-access-token
816+
```
817+
818+
External Metrics template example:
819+
820+
```yaml
821+
apiVersion: flagger.app/v1beta1
822+
kind: MetricTemplate
823+
metadata:
824+
name: my-external-metric
825+
namespace: default
826+
spec:
827+
provider:
828+
type: externalmetrics
829+
address: https://external-metrics-server.default.svc.cluster.local:8443
830+
secretRef: # Optional
831+
name: external-metric-server-token
832+
query: webapp-frontend/job-success-rate?labelSelector=env%3Dproduction
833+
```

pkg/metrics/providers/externalmetrics.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func NewExternalMetricsProvider(metricInterval string,
5959
return nil, fmt.Errorf("the Url of the external metric service must be provided")
6060
}
6161

62-
externalMetrics := ExternalMetricsProvider{
62+
emp := ExternalMetricsProvider{
6363
metricServiceEndpoint: fmt.Sprintf("%s%s", provider.Address, metricServiceEndpointPath),
6464
timeout: 5 * time.Second,
6565
client: http.DefaultClient,
@@ -68,33 +68,33 @@ func NewExternalMetricsProvider(metricInterval string,
6868
if provider.InsecureSkipVerify {
6969
t := http.DefaultTransport.(*http.Transport).Clone()
7070
t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
71-
externalMetrics.client = &http.Client{Transport: t}
71+
emp.client = &http.Client{Transport: t}
7272
}
7373

7474
if b, ok := credentials[applicationBearerToken]; ok {
75-
externalMetrics.bearerToken = string(b)
75+
emp.bearerToken = string(b)
7676
} else {
77-
// Read service account token from volume mount
77+
// In the absence of a provided token,
78+
// read service account token from volume mount
7879
token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
7980
if err != nil {
8081
return nil, fmt.Errorf("error reading service account token: %w", err)
8182
}
8283
if len(token) == 0 {
8384
return nil, fmt.Errorf("pod's service account token is empty")
8485
}
85-
externalMetrics.bearerToken = string(token)
86+
emp.bearerToken = string(token)
8687
}
8788

88-
return &externalMetrics, nil
89+
return &emp, nil
8990
}
9091

9192
// RunQuery retrieves the ExternalMetricValue from the ExternalMetricsProvider.metricServiceUrl
9293
// and returns the first result as a float64
9394
func (p *ExternalMetricsProvider) RunQuery(query string) (float64, error) {
95+
u := fmt.Sprintf("%s%s%s", p.metricServiceEndpoint, namespacesPath, query)
9496

95-
metricsQueryUrl := fmt.Sprintf("%s%s%s", p.metricServiceEndpoint, namespacesPath, query)
96-
97-
req, err := http.NewRequest("GET", metricsQueryUrl, nil)
97+
req, err := http.NewRequest("GET", u, nil)
9898
if err != nil {
9999
return 0, fmt.Errorf("error http.NewRequest: %w", err)
100100
}
@@ -134,19 +134,19 @@ func (p *ExternalMetricsProvider) RunQuery(query string) (float64, error) {
134134
}
135135

136136
// IsOnline will only check the TCP endpoint reachability,
137-
// given that external metric servers don't have a common health check endpoint defined
137+
// given that external metric servers don't have a standard health check endpoint defined
138138
func (p *ExternalMetricsProvider) IsOnline() (bool, error) {
139139
var d net.Dialer
140140

141141
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
142142
defer cancel()
143143

144-
metricServiceUrl, err := url.Parse(p.metricServiceEndpoint)
144+
u, err := url.Parse(p.metricServiceEndpoint)
145145
if err != nil {
146146
return false, fmt.Errorf("error parsing metric service url: %w", err)
147147
}
148148

149-
conn, err := d.DialContext(ctx, "tcp", metricServiceUrl.Host)
149+
conn, err := d.DialContext(ctx, "tcp", u.Host)
150150
defer conn.Close()
151151
if err != nil {
152152
return false, fmt.Errorf("connection failed: %w", err)

pkg/metrics/providers/externalmetrics_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestNewExternalMetricsProvider(t *testing.T) {
5353
applicationBearerToken: []byte(testBearerToken),
5454
}
5555

56-
providermetric:= flaggerv1.MetricTemplateProvider{
56+
providermetric := flaggerv1.MetricTemplateProvider{
5757
Address: testMetricServerAddress,
5858
InsecureSkipVerify: false,
5959
}

0 commit comments

Comments
 (0)