diff --git a/README.md b/README.md index 853864d..a95d58e 100644 --- a/README.md +++ b/README.md @@ -221,22 +221,26 @@ Check out the docker-compose folder ### Kubernetes/Helm -You can install the included [Helm](https://docs.helm.sh/install/) chart to your k8s cluster with: +Deploy PageSpeed Exporter to Kubernetes using the included [Helm](https://helm.sh/) chart. First, create a secret with your API key (only required if monitoring more than 2 targets/sec): +```bash +kubectl create secret generic pagespeed-configuration-secret \ + --from-literal=PAGESPEED_API_KEY=your-api-key-here ``` -$ helm install helm/pagespeed-exporter -``` -And then, to quickly test it: +Install the chart with your target URLs: + +```bash +helm install pagespeed-exporter ./helm/pagespeed-exporter \ + --set 'config.targets={https://www.example.com,https://www.yoursite.com}' \ + --set config.parallel=true ``` -$ kubectl get pods -pagespeed-exporter-riotous-dragonfly-6b99955999-hj2kw 1/1 Running 0 1m -$ kubectl exec -ti pagespeed-exporter-riotous-dragonfly-6b99955999-hj2kw -- sh -# apk add curl -# curl localhost:9271/metrics -pagespeed_lighthouse_audit_score{audit="first-contentful-paint",host="https://www.google.com",path="/",strategy="mobile"} 1 -pagespeed_lighthouse_audit_score{audit="first-contentful-paint",host="https://www.google.com",path="/webhp",strategy="desktop"} 1 -pagespeed_lighthouse_audit_score{audit="first-contentful-paint",host="https://www.google.com",path="/webhp",strategy="mobile"} 1 -... +Test the deployment: + +```bash +kubectl port-forward svc/pagespeed-exporter 9271:9271 +curl http://localhost:9271/metrics ``` + +For detailed configuration options, installation examples, and Prometheus integration, see the [Helm Chart README](helm/pagespeed-exporter/README.md). diff --git a/collector/collector.go b/collector/collector.go index 90a10b2..4781535 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -160,76 +160,12 @@ func collectLoadingExperience(prefix string, lexp *pagespeedonline.PagespeedApiL for k, v := range lexp.Metrics { name := strings.TrimSuffix(strings.ToLower(k), "_ms") - // Export P75 percentile (existing metric - unchanged) ch <- prometheus.MustNewConstMetric( prometheus.NewDesc(fqname(prefix, "metrics", name, "duration_seconds"), "Percentile metrics for "+strings.Replace(name, "_", " ", -1), nil, constLables), prometheus.GaugeValue, float64(v.Percentile)/1000) - // Export category distribution ratios (NEW) - if len(v.Distributions) >= 3 { - categories := []string{"fast", "average", "slow"} - for i, dist := range v.Distributions { - if i >= 3 { - break - } - ch <- prometheus.MustNewConstMetric( - prometheus.NewDesc(fqname(prefix, "metrics", name, "category_ratio"), "Proportion of users experiencing "+categories[i]+" performance", []string{"category"}, constLables), - prometheus.GaugeValue, - dist.Proportion, - categories[i]) - } - } - - // Export Core Web Vitals thresholds (NEW) - if len(v.Distributions) >= 2 { - // Determine if this is CLS (uses hundredths) or time-based (uses ms) - isCLS := strings.Contains(strings.ToLower(k), "cumulative_layout_shift") - - // Extract good threshold (upper bound of FAST bucket) - if v.Distributions[0].Max > 0 { - goodThreshold := float64(v.Distributions[0].Max) - if isCLS { - goodThreshold = goodThreshold / 100.0 // Convert hundredths to decimal - } else { - goodThreshold = goodThreshold / 1000.0 // Convert ms to seconds - } - - metricSuffix := "duration_seconds" - if isCLS { - metricSuffix = "" // CLS is unitless - } - - ch <- prometheus.MustNewConstMetric( - prometheus.NewDesc(fqname(prefix, "metrics", name, "threshold", metricSuffix), "Core Web Vitals threshold for "+strings.Replace(name, "_", " ", -1), []string{"threshold"}, constLables), - prometheus.GaugeValue, - goodThreshold, - "good") - } - - // Extract poor threshold (upper bound of AVERAGE bucket) - if v.Distributions[1].Max > 0 { - poorThreshold := float64(v.Distributions[1].Max) - if isCLS { - poorThreshold = poorThreshold / 100.0 - } else { - poorThreshold = poorThreshold / 1000.0 - } - - metricSuffix := "duration_seconds" - if isCLS { - metricSuffix = "" - } - - ch <- prometheus.MustNewConstMetric( - prometheus.NewDesc(fqname(prefix, "metrics", name, "threshold", metricSuffix), "Core Web Vitals threshold for "+strings.Replace(name, "_", " ", -1), []string{"threshold"}, constLables), - prometheus.GaugeValue, - poorThreshold, - "poor") - } - } } - } func collectLighthouseResults(prefix string, cats []string, lhr *pagespeedonline.LighthouseResultV5, constLabels prometheus.Labels, ch chan<- prometheus.Metric) { diff --git a/collector/collector_test.go b/collector/collector_test.go index f2ca054..5ceb2c3 100644 --- a/collector/collector_test.go +++ b/collector/collector_test.go @@ -1,12 +1,21 @@ package collector import ( + "os" + "path/filepath" "reflect" "testing" + "github.com/joho/godotenv" "github.com/prometheus/client_golang/prometheus" + "google.golang.org/api/option" ) +func loadTestEnv() { + envPath := filepath.Join("..", ".env") + _ = godotenv.Load(envPath) +} + func Test_getConstLabels(t *testing.T) { type args struct { scrape *ScrapeResult @@ -91,3 +100,93 @@ func Test_fqname(t *testing.T) { }) } } + +func Test_CollectorIntegration(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + + loadTestEnv() + + var options []option.ClientOption + + if apiKey := os.Getenv("PAGESPEED_API_KEY"); apiKey != "" { + options = append(options, option.WithAPIKey(apiKey)) + } + + if cf := os.Getenv("PAGESPEED_CREDENTIALS_FILE"); cf != "" { + options = append(options, option.WithCredentialsFile(cf)) + } + + if len(options) == 0 { + t.Skip("skipping integration test unless PAGESPEED_API_KEY or PAGESPEED_CREDENTIALS_FILE is set") + } + + config := Config{ + ScrapeRequests: []ScrapeRequest{ + { + Url: "https://www.example.com", + Strategy: StrategyMobile, + Categories: []string{CategoryPerformance}, + }, + }, + GoogleAPIKey: os.Getenv("PAGESPEED_API_KEY"), + Parallel: false, + } + + if cf := os.Getenv("PAGESPEED_CREDENTIALS_FILE"); cf != "" { + config.CredentialsFile = cf + } + + coll, err := newCollector(config) + if err != nil { + t.Fatalf("failed to create collector: %v", err) + } + + ch := make(chan prometheus.Metric, 100) + done := make(chan bool) + + var metrics []prometheus.Metric + go func() { + for m := range ch { + metrics = append(metrics, m) + } + done <- true + }() + + coll.Collect(ch) + close(ch) + <-done + + if len(metrics) == 0 { + t.Fatal("expected at least one metric to be collected") + } + + t.Logf("Successfully collected %d metrics from https://www.example.com", len(metrics)) + + hasExpectedLabels := false + for _, m := range metrics { + desc := m.Desc().String() + if contains(desc, "host") && contains(desc, "path") && contains(desc, "strategy") { + hasExpectedLabels = true + break + } + } + + if !hasExpectedLabels { + t.Error("expected metrics to contain host, path, and strategy labels") + } +} + +func contains(s, substr string) bool { + return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || containsSubstring(s, substr))) +} + +func containsSubstring(s, substr string) bool { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} diff --git a/go.mod b/go.mod index c203e76..cc4dc6a 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/kr/text v0.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/go.sum b/go.sum index 1315e91..e61dbfb 100644 --- a/go.sum +++ b/go.sum @@ -61,6 +61,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gT github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= diff --git a/helm/pagespeed-exporter/.helmignore b/helm/pagespeed-exporter/.helmignore index f0c1319..691fa13 100644 --- a/helm/pagespeed-exporter/.helmignore +++ b/helm/pagespeed-exporter/.helmignore @@ -14,8 +14,10 @@ *.swp *.bak *.tmp +*.orig *~ # Various IDEs .project .idea/ *.tmproj +.vscode/ \ No newline at end of file diff --git a/helm/pagespeed-exporter/Chart.yaml b/helm/pagespeed-exporter/Chart.yaml index b6909f6..0f6246e 100644 --- a/helm/pagespeed-exporter/Chart.yaml +++ b/helm/pagespeed-exporter/Chart.yaml @@ -1,5 +1,15 @@ -apiVersion: v1 -description: Pagespeed Exporter +apiVersion: v2 name: pagespeed-exporter -version: 2.1.6 -appVersion: 2.1.6 +description: A Helm chart for deploying PageSpeed Exporter to monitor website performance metrics +type: application +version: 0.1.0 +appVersion: "3.1.2" +keywords: + - monitoring + - prometheus + - pagespeed + - metrics +maintainers: + - name: Infrastructure Team +sources: + - https://github.com/foomo/pagespeed_exporter \ No newline at end of file diff --git a/helm/pagespeed-exporter/README.md b/helm/pagespeed-exporter/README.md new file mode 100644 index 0000000..3192fab --- /dev/null +++ b/helm/pagespeed-exporter/README.md @@ -0,0 +1,246 @@ +# PageSpeed Exporter Helm Chart + +## Overview + +This Helm chart deploys the [PageSpeed Exporter](https://github.com/foomo/pagespeed_exporter) for Prometheus monitoring. The exporter collects Google PageSpeed Insights metrics using the Lighthouse auditing tool to monitor website performance. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.0+ +- A Kubernetes secret named `pagespeed-configuration-secret` containing the Google PageSpeed API key +- Prometheus for metrics collection (optional, but recommended) + +## Installation + +### 1. Create the API Key Secret + +First, create a secret containing your Google PageSpeed API key: + +```bash +kubectl create secret generic pagespeed-configuration-secret \ + --from-literal=PAGESPEED_API_KEY=your-api-key-here +``` + +**Note:** An API key is only required if you're monitoring more than 2 targets per second. You can obtain one from the [Google PageSpeed Insights API](https://developers.google.com/speed/docs/insights/v5/get-started). + +### 2. Install the Chart + +#### Basic Installation + +```bash +helm install pagespeed-exporter ./charts/pagespeed-exporter +``` + +#### Installation with Custom Targets (Simple Method) + +```bash +helm install pagespeed-exporter ./charts/pagespeed-exporter \ + --set 'config.targets={https://www.example.com,https://www.google.com}' \ + --set config.parallel=true \ + --set config.cacheTTL="30m" +``` + +#### Installation with Custom Values File + +Create a `custom-values.yaml` file: + +```yaml +# Simple configuration method (recommended) +config: + targets: + - https://www.yoursite.com + - https://www.anothersite.com + - https://www.thirdsite.com + parallel: true + categories: + - performance + - seo + cacheTTL: "120m" # Cache for 2 hours (or set to null to disable) + +resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "128Mi" + cpu: "100m" +``` + +Then install: + +```bash +helm install pagespeed-exporter ./charts/pagespeed-exporter -f custom-values.yaml +``` + +## Configuration + +The following table lists the configurable parameters and their default values: + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `replicaCount` | Number of replicas (fixed to 1 for simplicity) | `1` | +| `image.repository` | Image repository | `foomo/pagespeed_exporter` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `image.tag` | Image tag | `latest` | +| `imagePullSecrets` | Image pull secrets | `[]` | +| `nameOverride` | Override the chart name | `""` | +| `fullnameOverride` | Override the full name | `""` | +| `serviceAccount.create` | Create service account | `true` | +| `serviceAccount.annotations` | Service account annotations | `{}` | +| `serviceAccount.name` | Service account name | `""` | +| `podAnnotations` | Pod annotations (includes Prometheus scrape config) | See values.yaml | +| `podSecurityContext` | Pod security context | `{}` | +| `securityContext` | Container security context | `{}` | +| `service.type` | Service type | `ClusterIP` | +| `service.port` | Service port | `9271` | +| `service.targetPort` | Container port | `9271` | +| `service.annotations` | Service annotations (includes Prometheus scrape config) | See values.yaml | +| `resources` | CPU/Memory resource requests/limits | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | +| `secretName` | Name of the secret containing API key | `pagespeed-configuration-secret` | +| `config.targets` | List of URLs to monitor (simple method) | `[]` | +| `config.parallel` | Enable parallel execution | `false` | +| `config.categories` | Categories to check (empty = all) | `[]` | +| `config.cacheTTL` | Cache TTL for API results (e.g., "60s", "5m") | `"60m"` | +| `args` | Raw command-line arguments (advanced) | `[]` | +| `extraEnvVars` | Additional environment variables | `[]` | + +## Command-Line Arguments + +The PageSpeed Exporter supports the following command-line arguments. Configure them through the `args` array in values.yaml: + +### Available Arguments + +| Argument | Description | Default | Example | +|----------|-------------|---------|---------| +| `-targets` | Comma-separated list of targets to measure | None | `"-targets=https://example.com,https://google.com"` | +| `-t` | Multi-value target array (can be used multiple times) | None | `"-t=https://example.com"` | +| `-api-key` | Google API key (alternatively use env var) | None | `"-api-key=your-key-here"` | +| `-categories` | Categories to check | `accessibility,best-practices,performance,pwa,seo` | `"-categories=performance,seo"` | +| `-listener` | Listener address for the exporter | `:9271` | `"-listener=:8080"` | +| `-parallel` | Enable parallel execution | `false` | `"-parallel=true"` | +| `-cache-ttl` | Cache TTL for API results | None (disabled) | `"-cache-ttl=5m"` | +| `-pushGatewayUrl` | Push Gateway URL | None | `"-pushGatewayUrl=http://pushgateway:9091"` | +| `-pushGatewayJob` | Push Gateway job name | `pagespeed_exporter` | `"-pushGatewayJob=my-job"` | + +### Configuration Examples + +#### Simple Configuration (Recommended) + +Use the `config` section for common use cases: + +```yaml +config: + targets: + - https://www.example.com + - https://www.mysite.com + categories: + - performance + - seo + - accessibility + parallel: true + cacheTTL: "60m" # Cache results for 60 minutes (default) +``` + +#### Advanced: Using Raw Args + +For advanced use cases, use the `args` array directly: + +```yaml +args: + - "-targets=https://www.example.com,https://www.mysite.com" + - "-categories=performance,seo,accessibility" + - "-parallel=true" +``` + +#### Multi-Value Target Flags + +```yaml +args: + - "-t=https://www.example.com" + - "-t=https://www.google.com" + - "-t=https://www.github.com" +``` + +#### Push to Prometheus Push Gateway + +```yaml +args: + - "-targets=https://www.example.com" + - "-pushGatewayUrl=http://prometheus-pushgateway:9091" + - "-pushGatewayJob=pagespeed-monitoring" +``` + +## Prometheus Integration + +The chart includes Prometheus annotations on both the pods and service for automatic discovery: + +```yaml +prometheus.io/scrape: "true" +prometheus.io/port: "9271" +prometheus.io/path: "/metrics" +``` + + +## Metrics + +The exporter provides the following types of metrics: + +- **Performance Score**: Overall performance score (0-100) +- **Accessibility Score**: Website accessibility rating +- **Best Practices Score**: Adherence to web best practices +- **SEO Score**: Search engine optimization rating +- **PWA Score**: Progressive Web App compliance + +All metrics are prefixed with `pagespeed_` and include labels for the target URL and strategy (mobile/desktop). + +## Example Metrics Output + +``` +# HELP pagespeed_lighthouse_audit_score Lighthouse audit score (0-100) +# TYPE pagespeed_lighthouse_audit_score gauge +pagespeed_lighthouse_audit_score{audit="performance",url="https://www.example.com",strategy="mobile"} 95 +pagespeed_lighthouse_audit_score{audit="accessibility",url="https://www.example.com",strategy="mobile"} 98 +pagespeed_lighthouse_audit_score{audit="seo",url="https://www.example.com",strategy="mobile"} 100 +``` + +## Troubleshooting + +### Check Pod Status + +```bash +kubectl get pods -l app.kubernetes.io/name=pagespeed-exporter +``` + +### View Logs + +```bash +kubectl logs -l app.kubernetes.io/name=pagespeed-exporter +``` + +### Test Metrics Endpoint + +```bash +kubectl port-forward svc/pagespeed-exporter 9271:9271 +curl http://localhost:9271/metrics +``` + +### Common Issues + +1. **API Key Missing**: Ensure the secret `pagespeed-configuration-secret` exists with key `PAGESPEED_API_KEY` +2. **Rate Limiting**: Without an API key, you're limited to 2 requests per second +3. **Target Unreachable**: Verify that the targets specified are accessible from your cluster + +## Uninstallation + +```bash +helm uninstall pagespeed-exporter +``` + +## Support + +For issues related to the Helm chart, please check the repository documentation. +For issues with the exporter itself, refer to the [upstream repository](https://github.com/foomo/pagespeed_exporter). \ No newline at end of file diff --git a/helm/pagespeed-exporter/templates/NOTES.txt b/helm/pagespeed-exporter/templates/NOTES.txt index 707a96c..0e7c628 100644 --- a/helm/pagespeed-exporter/templates/NOTES.txt +++ b/helm/pagespeed-exporter/templates/NOTES.txt @@ -10,6 +10,23 @@ echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "pagespeed-exporter.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT {{- end }} + +2. PageSpeed Exporter is now running and exposing metrics on port {{ .Values.service.port }} + +3. Prometheus should automatically discover and scrape the metrics if the annotations are configured correctly. + +{{- if .Values.args }} +4. The exporter is configured with the following arguments: +{{- range .Values.args }} + {{ . }} +{{- end }} +{{- else }} +4. The exporter is running with default configuration. To specify targets, configure the 'args' value with: + args: + - "-targets" + - "https://example.com,https://google.com" +{{- end }} \ No newline at end of file diff --git a/helm/pagespeed-exporter/templates/_helpers.tpl b/helm/pagespeed-exporter/templates/_helpers.tpl index c7430d8..b74fdbf 100644 --- a/helm/pagespeed-exporter/templates/_helpers.tpl +++ b/helm/pagespeed-exporter/templates/_helpers.tpl @@ -7,8 +7,6 @@ Expand the name of the chart. {{/* Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. */}} {{- define "pagespeed-exporter.fullname" -}} {{- if .Values.fullnameOverride }} @@ -23,33 +21,6 @@ If release name contains chart name it will be used as a full name. {{- end }} {{- end }} -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "pagespeed-exporter.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "pagespeed-exporter.labels" -}} -helm.sh/chart: {{ include "pagespeed-exporter.chart" . }} -{{ include "pagespeed-exporter.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "pagespeed-exporter.selectorLabels" -}} -app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - {{/* Create the name of the service account to use */}} @@ -59,4 +30,4 @@ Create the name of the service account to use {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} -{{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/pagespeed-exporter/templates/cronjob.yaml b/helm/pagespeed-exporter/templates/cronjob.yaml deleted file mode 100644 index d927784..0000000 --- a/helm/pagespeed-exporter/templates/cronjob.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if .Values.cronjob.enabled }} -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: {{ include "pagespeed-exporter.fullname" . }} - labels: - {{- include "pagespeed-exporter.labels" . | nindent 4 }} -spec: - schedule: "{{ .Values.cronjob.schedule }}" - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - spec: - containers: - - name: {{ .Values.cronjob.image.name }} - image: "{{ .Values.cronjob.image.repository }}:{{ .Values.cronjob.image.tag | default "latest" }}" - imagePullPolicy: {{ .Values.cronjob.image.pullPolicy }} - args: - - -sSv - - -H - - "X-Prometheus-Scrape-Timeout-Seconds: {{ .Values.cronjob.scrapeTimeoutSeconds }}" - - "http://{{ include "pagespeed-exporter.fullname" . }}:{{ .Values.service.port }}/probe?target={{- join "&target=" .Values.exporter.targets }}" - restartPolicy: OnFailure -{{- end }} \ No newline at end of file diff --git a/helm/pagespeed-exporter/templates/deployment.yaml b/helm/pagespeed-exporter/templates/deployment.yaml index 8e81b9c..c3c6560 100644 --- a/helm/pagespeed-exporter/templates/deployment.yaml +++ b/helm/pagespeed-exporter/templates/deployment.yaml @@ -3,19 +3,30 @@ kind: Deployment metadata: name: {{ include "pagespeed-exporter.fullname" . }} labels: - {{- include "pagespeed-exporter.labels" . | nindent 4 }} + app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service }} spec: + replicas: {{ .Values.replicaCount }} selector: matchLabels: - {{- include "pagespeed-exporter.selectorLabels" . | nindent 6 }} + app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} template: metadata: - {{- with .Values.podAnnotations }} annotations: + {{- if .Values.prometheus.scrape }} + prometheus.io/scrape: "true" + prometheus.io/port: {{ .Values.service.targetPort | quote }} + prometheus.io/path: {{ .Values.prometheus.path | quote }} + {{- end }} + {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} labels: - {{- include "pagespeed-exporter.selectorLabels" . | nindent 8 }} + app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: @@ -30,19 +41,53 @@ spec: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.args }} args: - - "-api-key={{ .Values.exporter.googleapikey }}" - {{- range $_, $target := .Values.exporter.targets }} - - "-t={{ $target }}" - {{- end }} - {{- with .Values.exporter.pushGatewayUrl }} - - "-pushGatewayUrl={{ . }}" + {{- toYaml .Values.args | nindent 12 }} + {{- else if or .Values.config.targets .Values.config.categories .Values.config.parallel .Values.config.cacheTTL }} + args: + {{- if .Values.config.targets }} + {{- if gt (len .Values.config.targets) 1 }} + {{- range .Values.config.targets }} + - "-t={{ . }}" + {{- end }} + {{- else }} + - "-targets={{ index .Values.config.targets 0 }}" + {{- end }} + {{- end }} + {{- if .Values.config.categories }} + - "-categories={{ .Values.config.categories | join "," }}" + {{- end }} + {{- if .Values.config.parallel }} + - "-parallel=true" + {{- end }} + {{- with .Values.config.cacheTTL }} + - "-cache-ttl={{ . }}" + {{- end }} {{- end }} - - "-listener=:{{ .Values.targetPort }}" ports: - - name: http - containerPort: {{ .Values.service.port }} + - name: metrics + containerPort: {{ .Values.service.targetPort }} protocol: TCP + env: + - name: PAGESPEED_API_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.secretName }} + key: PAGESPEED_API_KEY + {{- with .Values.extraEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + livenessProbe: + tcpSocket: + port: metrics + initialDelaySeconds: 30 + periodSeconds: 30 + readinessProbe: + tcpSocket: + port: metrics + initialDelaySeconds: 10 + periodSeconds: 10 resources: {{- toYaml .Values.resources | nindent 12 }} {{- with .Values.nodeSelector }} @@ -56,4 +101,4 @@ spec: {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} \ No newline at end of file diff --git a/helm/pagespeed-exporter/templates/service.yaml b/helm/pagespeed-exporter/templates/service.yaml index f49b99c..bde703d 100644 --- a/helm/pagespeed-exporter/templates/service.yaml +++ b/helm/pagespeed-exporter/templates/service.yaml @@ -1,17 +1,28 @@ apiVersion: v1 kind: Service -apiVersion: v1 -kind: Service metadata: name: {{ include "pagespeed-exporter.fullname" . }} labels: - {{- include "pagespeed-exporter.labels" . | nindent 4 }} + app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + annotations: + {{- if .Values.prometheus.scrape }} + prometheus.io/scrape: "true" + prometheus.io/port: {{ .Values.service.targetPort | quote }} + prometheus.io/path: {{ .Values.prometheus.path | quote }} + {{- end }} + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: {{ .Values.targetPort }} + targetPort: {{ .Values.service.targetPort }} protocol: TCP - name: http + name: metrics selector: - {{- include "pagespeed-exporter.selectorLabels" . | nindent 4 }} + app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} \ No newline at end of file diff --git a/helm/pagespeed-exporter/templates/serviceaccount.yaml b/helm/pagespeed-exporter/templates/serviceaccount.yaml index 0b2e867..e75eb03 100644 --- a/helm/pagespeed-exporter/templates/serviceaccount.yaml +++ b/helm/pagespeed-exporter/templates/serviceaccount.yaml @@ -4,9 +4,12 @@ kind: ServiceAccount metadata: name: {{ include "pagespeed-exporter.serviceAccountName" . }} labels: - {{- include "pagespeed-exporter.labels" . | nindent 4 }} + app.kubernetes.io/name: {{ include "pagespeed-exporter.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} -{{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/pagespeed-exporter/values.yaml b/helm/pagespeed-exporter/values.yaml index 8f740f9..fa09403 100644 --- a/helm/pagespeed-exporter/values.yaml +++ b/helm/pagespeed-exporter/values.yaml @@ -1,8 +1,9 @@ +replicaCount: 1 + image: - name: pagespeed_exporter repository: foomo/pagespeed_exporter - pullPolicy: Always - tag: 2.1.6 + pullPolicy: IfNotPresent + tag: "latest" imagePullSecrets: [] nameOverride: "" @@ -14,20 +15,36 @@ serviceAccount: name: "" podAnnotations: {} +# Additional pod annotations can be added here + +# Prometheus scrape annotations configuration +# Note: Standard Prometheus only honors scrape, port, path, and scheme annotations. +prometheus: + # Enable Prometheus scraping annotations + scrape: true + # Metrics path + path: "/metrics" -podSecurityContext: {} +podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 -securityContext: {} +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + capabilities: + drop: + - ALL service: type: ClusterIP - port: 80 - annotations: - # Careful, the http calls will need to occur within the prometheus timeout threshold - # This is not required for a CronJob that pushes to a gateway - prometheus.io/scrape: "false" - -targetPort: 9271 + port: 9271 + targetPort: 9271 # This is the metrics port used throughout + annotations: {} + # Additional service annotations can be added here resources: {} @@ -37,18 +54,62 @@ tolerations: [] affinity: {} -exporter: - googleapikey: "" - pushGatewayUrl: "" +# Name of the secret containing the API key +# The secret must have a key named PAGESPEED_API_KEY +secretName: pagespeed-configuration-secret + +# Simple configuration (will be converted to args) +config: + # List of targets to monitor targets: [] + # Example: + # targets: + # - https://www.example.com + # - https://www.google.com + + # Enable parallel execution + parallel: false + + # Categories to check (leave empty for default: all categories) + categories: [] + # Example: + # categories: + # - performance + # - seo + # - accessibility + + # Cache TTL for API results (e.g., "60s", "5m", "1h") + # Set to null or empty string to disable caching + cacheTTL: "60m" + +# Advanced: Raw command line arguments (overrides config above) +# All available arguments from https://github.com/foomo/pagespeed_exporter +args: [] +# Examples (uncomment and modify as needed): +# args: +# # Comma separated list of targets to measure +# - "-targets=https://www.example.com,https://www.google.com" +# +# # OR use multi-value target array (-t flag) +# # - "-t=https://www.example.com" +# # - "-t=https://www.google.com" +# # - "-t=https://www.github.com" +# +# # Google API key (alternatively can be set via environment variable) +# # - "-api-key=your-api-key-here" +# +# # Categories to check (default: accessibility,best-practices,performance,pwa,seo) +# # - "-categories=performance,seo,accessibility" +# +# # Listener address (default: :9271) +# # - "-listener=:9271" +# +# # Enable parallel execution (default: false) +# # - "-parallel=true" +# +# # Push Gateway configuration +# # - "-pushGatewayUrl=http://prometheus-pushgateway:9091" +# # - "-pushGatewayJob=pagespeed_exporter" -cronjob: - enabled: false - image: - name: curl - repository: curlimages/curl - pullPolicy: Always - tag: 7.73.0 - # Executes every 10 minutes - schedule: "*/10 * * * *" - scrapeTimeoutSeconds: 120 +# Additional environment variables +extraEnvVars: []