diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0587d5f..d001cd3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,7 +37,8 @@ jobs: --charts charts/api7 \ --charts charts/gateway \ --charts charts/ingress-controller \ - --charts charts/aisix-cp' + --charts charts/aisix-cp \ + --charts charts/ngxdig' - name: Verify Chart.lock files run: | @@ -76,7 +77,8 @@ jobs: && helm repo add jaegertracing https://jaegertracing.github.io/helm-charts \ && ct install \ --charts charts/api7 \ - --charts charts/ingress-controller' + --charts charts/ingress-controller \ + --charts charts/ngxdig' - name: Test gateway charts run: | diff --git a/AGENTS.md b/AGENTS.md index d43d39a..7224295 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,7 @@ This repo (`api7/api7-helm-chart`) holds the Helm charts for API7 EE components | `api7-ingress-controller` | `charts/ingress-controller` | no — independent product version | | `developer-portal-fe` | `charts/developer-portal-fe` | no — independent product version | | `aisix-cp` (AISIX private-deployment control plane) | `charts/aisix-cp` | no — independent product version (source of truth: `api7/AISIX-Cloud` `helm/aisix-cp`) | +| `ngxdig` (eBPF flame-graph / diagnosis agent, DaemonSet) | `charts/ngxdig` | no — independent product version (source of truth: `api7/ngx-flame`) | ## Multi-line maintenance model diff --git a/charts/ngxdig/.helmignore b/charts/ngxdig/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/ngxdig/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/ngxdig/Chart.yaml b/charts/ngxdig/Chart.yaml new file mode 100644 index 0000000..ae91e35 --- /dev/null +++ b/charts/ngxdig/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: ngxdig +description: eBPF on-CPU flame graphs and guided CPU/memory/latency diagnosis for OpenResty/Nginx, deployed as a per-node collector +type: application +version: 0.1.0 +appVersion: "0.1.0" +keywords: + - ebpf + - profiling + - flamegraph + - openresty + - nginx + - apisix + - diagnostics +home: https://github.com/api7/ngx-flame +sources: + - https://github.com/api7/ngx-flame +maintainers: + - name: API7 + email: support@api7.ai + url: https://api7.ai diff --git a/charts/ngxdig/README.md b/charts/ngxdig/README.md new file mode 100644 index 0000000..ad64359 --- /dev/null +++ b/charts/ngxdig/README.md @@ -0,0 +1,138 @@ +# ngxdig + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.0](https://img.shields.io/badge/AppVersion-0.1.0-informational?style=flat-square) + +eBPF on-CPU flame graphs and guided CPU/memory/latency diagnosis for OpenResty/Nginx, deployed as a per-node collector + +**Homepage:** + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| API7 | | | + +## Source Code + +* + +## Install + +```sh +helm repo add api7 https://charts.api7.ai +helm repo update + +helm install ngxdig api7/ngxdig --namespace ngxdig --create-namespace +``` + +ngxdig is deployed as a DaemonSet — one collector Pod per node — so it can +profile the OpenResty/Nginx (and APISIX) worker processes running on that node. + +## Accessing the debug UI + +The chart always creates a Service for the UI. Most deployments run a single +collector — one node, or the DaemonSet pinned to one node (see below) — so the +`ClusterIP` points at that one Pod. + +Quick local access — port-forward to the collector Pod. Scope the selector to +this release, and on a multi-node install pick the Pod on the node you want with +a `spec.nodeName` field selector: + +```sh +NODE= # from `kubectl get nodes`; omit the field selector if single-node +POD=$(kubectl -n ngxdig get pod \ + -l app.kubernetes.io/name=ngxdig,app.kubernetes.io/instance=ngxdig \ + --field-selector spec.nodeName=$NODE \ + -o jsonpath='{.items[0].metadata.name}') +kubectl -n ngxdig port-forward $POD 8080:8080 +# then open http://127.0.0.1:8080/ +``` + +Node-IP access — set the Service to `NodePort`; with `externalTrafficPolicy: +Local`, `:` reaches the collector on that same node: + +```yaml +# values.yaml +service: + type: NodePort + externalTrafficPolicy: Local + # nodePort: 30080 # optional; auto-assigned when omitted +``` + +The UI is not a hardened multi-user service — keep it on a trusted network and +prefer a port-forward over a public ingress. Note the `ClusterIP` Service is not +node-specific: on a single-node or node-pinned install it points at the one +collector, but when the DaemonSet spans several nodes it load-balances across +collectors and each collector only sees its own node's processes — so target a +specific node's Pod (the `spec.nodeName` selector above) rather than the Service. + +## Run on specific node(s) only + +Usually you only want a collector on the node running the workload you are +debugging, not every node. Restrict the DaemonSet with a `nodeSelector`; the +controller then creates a Pod only on matching nodes. + +Pin to a single node by its built-in `kubernetes.io/hostname` label (the value +is the node name shown by `kubectl get nodes`): + +```sh +helm install ngxdig api7/ngxdig --namespace ngxdig --create-namespace \ + --set nodeSelector."kubernetes\.io/hostname"= +``` + +To target a group of nodes, label them first and select by that label: + +```sh +kubectl label node ngxdig=enabled +``` + +```yaml +# values.yaml +nodeSelector: + ngxdig: enabled +``` + +For rules that `nodeSelector` cannot express, use `affinity` instead. Note that +for a DaemonSet you should not set the Pod's `.spec.nodeName` directly — node +placement is owned by the DaemonSet controller, and `nodeSelector`/`affinity` +is the supported way to constrain it. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Affinity rules for the DaemonSet Pods | +| containerPort | int | `8080` | Port the ngxdig UI listens on inside the container | +| extraArgs | list | `[]` | Extra arguments appended to the `ngxdig ui` command | +| extraEnvVars | list | `[]` | Extra environment variables for the collector container | +| extraVolumeMounts | list | `[]` | Extra volume mounts for the collector container | +| extraVolumes | list | `[]` | Extra volumes for the collector Pod | +| fullnameOverride | string | `""` | Override the fully qualified release name | +| hostBtf.enabled | bool | `true` | Mount the node's kernel BTF read-only. Required by the eBPF collector to resolve kernel types without DWARF | +| hostBtf.path | string | `"/sys/kernel/btf"` | Host path to the kernel BTF directory | +| hostPID | bool | `true` | Share the host PID namespace so the collector can see Nginx/OpenResty worker processes elsewhere on the node. Required to profile targets outside the collector's own Pod | +| image.pullPolicy | string | `"Always"` | Image pull policy. Defaults to Always because the image tag is the moving `latest`, so nodes must re-pull to pick up newer builds | +| image.repository | string | `"api7/ngxdig"` | ngxdig image repository | +| image.tag | string | `"latest"` | Image tag. Defaults to the chart appVersion when left empty | +| imagePullSecrets | list | `[]` | Image pull secrets for a private registry | +| livenessProbe | object | `{"httpGet":{"path":"/","port":"http"},"initialDelaySeconds":10,"periodSeconds":15}` | Liveness probe for the collector container | +| nameOverride | string | `""` | Override the chart name | +| nodeSelector | object | `{}` | Node selector for the DaemonSet Pods | +| output.path | string | `"/out"` | Directory inside the container where run artifacts are written | +| output.sizeLimit | string | `""` | sizeLimit for the artifact emptyDir volume. No limit when empty | +| podAnnotations | object | `{}` | Additional annotations for the Pods | +| podLabels | object | `{}` | Additional labels for the Pods | +| podSecurityContext | object | `{}` | Pod-level security context | +| readinessProbe | object | `{"httpGet":{"path":"/","port":"http"},"initialDelaySeconds":5,"periodSeconds":10}` | Readiness probe for the collector container | +| resources | object | `{}` | Resource requests and limits for the collector container | +| securityContext | object | `{"appArmorProfile":{"type":"Unconfined"},"capabilities":{"add":["BPF","PERFMON","SYS_PTRACE","SYS_ADMIN"]},"runAsUser":0,"seccompProfile":{"type":"Unconfined"}}` | Container security context. The defaults grant exactly what the eBPF collector needs: run as root, and the CAP_BPF / CAP_PERFMON / CAP_SYS_PTRACE / CAP_SYS_ADMIN capabilities with unconfined seccomp/AppArmor so BPF, perf events, ptrace, and the perf_uprobe PMU attachments used by `cpu-on` and `latency` are all permitted. CAP_SYS_ADMIN is the smallest addition that satisfies the uprobe perf_event check — `--privileged` is not required | +| service.annotations | object | `{}` | Service annotations | +| service.externalTrafficPolicy | string | `"Local"` | externalTrafficPolicy for NodePort/LoadBalancer. Local keeps traffic on the receiving node, so : reaches that node's own collector instead of being load-balanced to another node | +| service.nodePort | string | `""` | Static node port for type NodePort. Auto-assigned when empty | +| service.port | int | `8080` | Service port | +| service.type | string | `"ClusterIP"` | Service type (ClusterIP, NodePort, or LoadBalancer) | +| serviceAccount.annotations | object | `{}` | Annotations to add to the ServiceAccount | +| serviceAccount.create | bool | `true` | Create a ServiceAccount for the collector | +| serviceAccount.name | string | `""` | Name of the ServiceAccount to use. Generated from the fullname when empty | +| tolerations | list | `[]` | Tolerations for the DaemonSet Pods (e.g. to also run on control-plane nodes) | +| updateStrategy | object | `{}` | Update strategy for the DaemonSet | diff --git a/charts/ngxdig/README.md.gotmpl b/charts/ngxdig/README.md.gotmpl new file mode 100644 index 0000000..cfb6300 --- /dev/null +++ b/charts/ngxdig/README.md.gotmpl @@ -0,0 +1,94 @@ +{{ template "chart.header" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +## Install + +```sh +helm repo add api7 https://charts.api7.ai +helm repo update + +helm install ngxdig api7/ngxdig --namespace ngxdig --create-namespace +``` + +ngxdig is deployed as a DaemonSet — one collector Pod per node — so it can +profile the OpenResty/Nginx (and APISIX) worker processes running on that node. + +## Accessing the debug UI + +The chart always creates a Service for the UI. Most deployments run a single +collector — one node, or the DaemonSet pinned to one node (see below) — so the +`ClusterIP` points at that one Pod. + +Quick local access — port-forward to the collector Pod. Scope the selector to +this release, and on a multi-node install pick the Pod on the node you want with +a `spec.nodeName` field selector: + +```sh +NODE= # from `kubectl get nodes`; omit the field selector if single-node +POD=$(kubectl -n ngxdig get pod \ + -l app.kubernetes.io/name=ngxdig,app.kubernetes.io/instance=ngxdig \ + --field-selector spec.nodeName=$NODE \ + -o jsonpath='{.items[0].metadata.name}') +kubectl -n ngxdig port-forward $POD 8080:8080 +# then open http://127.0.0.1:8080/ +``` + +Node-IP access — set the Service to `NodePort`; with `externalTrafficPolicy: +Local`, `:` reaches the collector on that same node: + +```yaml +# values.yaml +service: + type: NodePort + externalTrafficPolicy: Local + # nodePort: 30080 # optional; auto-assigned when omitted +``` + +The UI is not a hardened multi-user service — keep it on a trusted network and +prefer a port-forward over a public ingress. Note the `ClusterIP` Service is not +node-specific: on a single-node or node-pinned install it points at the one +collector, but when the DaemonSet spans several nodes it load-balances across +collectors and each collector only sees its own node's processes — so target a +specific node's Pod (the `spec.nodeName` selector above) rather than the Service. + +## Run on specific node(s) only + +Usually you only want a collector on the node running the workload you are +debugging, not every node. Restrict the DaemonSet with a `nodeSelector`; the +controller then creates a Pod only on matching nodes. + +Pin to a single node by its built-in `kubernetes.io/hostname` label (the value +is the node name shown by `kubectl get nodes`): + +```sh +helm install ngxdig api7/ngxdig --namespace ngxdig --create-namespace \ + --set nodeSelector."kubernetes\.io/hostname"= +``` + +To target a group of nodes, label them first and select by that label: + +```sh +kubectl label node ngxdig=enabled +``` + +```yaml +# values.yaml +nodeSelector: + ngxdig: enabled +``` + +For rules that `nodeSelector` cannot express, use `affinity` instead. Note that +for a DaemonSet you should not set the Pod's `.spec.nodeName` directly — node +placement is owned by the DaemonSet controller, and `nodeSelector`/`affinity` +is the supported way to constrain it. + +{{ template "chart.valuesSection" . }} diff --git a/charts/ngxdig/ci/ct-values.yaml b/charts/ngxdig/ci/ct-values.yaml new file mode 100644 index 0000000..c6494d5 --- /dev/null +++ b/charts/ngxdig/ci/ct-values.yaml @@ -0,0 +1,5 @@ +# Values used by chart-testing (`ct install`) to validate the chart on a +# single-node kind cluster. Tolerate any node taint so the DaemonSet Pod is +# guaranteed to schedule on the CI node. +tolerations: + - operator: Exists diff --git a/charts/ngxdig/templates/NOTES.txt b/charts/ngxdig/templates/NOTES.txt new file mode 100644 index 0000000..2c83cae --- /dev/null +++ b/charts/ngxdig/templates/NOTES.txt @@ -0,0 +1,45 @@ +ngxdig is installed as a DaemonSet — one collector Pod per node. + +Each Pod runs the ngxdig debug UI and can profile the OpenResty/Nginx (and +APISIX) worker processes running on its own node. + +1. List the collector Pods and the node each one runs on: + + kubectl get pods --namespace {{ .Release.Namespace }} \ + -l "app.kubernetes.io/name={{ include "ngxdig.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" \ + -o wide + +2. Open the debug UI for the node whose workload you want to inspect. The UI is + not a hardened multi-user service, so the recommended access is a + port-forward to the collector Pod on that exact node — no Service, nothing + exposed on the network: + + export NODE= # a node from step 1 / `kubectl get nodes` + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} \ + -l "app.kubernetes.io/name={{ include "ngxdig.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" \ + --field-selector spec.nodeName=$NODE \ + -o jsonpath="{.items[0].metadata.name}") + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:{{ .Values.containerPort }} + + Then browse to http://127.0.0.1:8080/ , pick a worker PID, and run a + diagnostic action (profile / cpu-on / memsnap / latency). + + The UI is also reachable through the Service + {{ include "ngxdig.fullname" . }}:{{ .Values.service.port }} (type {{ .Values.service.type }}). +{{- if eq .Values.service.type "NodePort" }} + With type NodePort{{ if eq (toString .Values.service.externalTrafficPolicy) "Local" }} and externalTrafficPolicy Local{{ end }}, reach a + node's own collector at :: + + kubectl get svc --namespace {{ .Release.Namespace }} {{ include "ngxdig.fullname" . }} -o jsonpath="{.spec.ports[0].nodePort}" +{{- end }} + +3. Check host readiness for eBPF collection on a node: + + kubectl --namespace {{ .Release.Namespace }} exec $POD_NAME -- ngxdig doctor + +Requirements: eBPF collection needs the node to expose kernel BTF +({{ .Values.hostBtf.path }}){{ if not .Values.hostBtf.enabled }} — currently disabled via hostBtf.enabled=false{{ end }}, and the +collector must keep CAP_BPF, CAP_PERFMON, CAP_SYS_PTRACE, and CAP_SYS_ADMIN with +unconfined seccomp/AppArmor (the chart defaults grant these; CAP_SYS_ADMIN is +needed for the perf_uprobe attachments in `cpu-on`/`latency`). If a diagnostic +fails before collecting, `ngxdig doctor` reports the exact fix. diff --git a/charts/ngxdig/templates/_helpers.tpl b/charts/ngxdig/templates/_helpers.tpl new file mode 100644 index 0000000..ce54418 --- /dev/null +++ b/charts/ngxdig/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "ngxdig.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +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 "ngxdig.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ngxdig.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "ngxdig.labels" -}} +helm.sh/chart: {{ include "ngxdig.chart" . }} +{{ include "ngxdig.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: collector +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "ngxdig.selectorLabels" -}} +app.kubernetes.io/name: {{ include "ngxdig.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "ngxdig.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "ngxdig.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/ngxdig/templates/daemonset.yaml b/charts/ngxdig/templates/daemonset.yaml new file mode 100644 index 0000000..99ab26b --- /dev/null +++ b/charts/ngxdig/templates/daemonset.yaml @@ -0,0 +1,113 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "ngxdig.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "ngxdig.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "ngxdig.selectorLabels" . | nindent 6 }} + {{- with .Values.updateStrategy }} + updateStrategy: + {{- toYaml . | nindent 4 }} + {{- end }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "ngxdig.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "ngxdig.serviceAccountName" . }} + hostPID: {{ .Values.hostPID }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - ui + - --listen + - ":{{ .Values.containerPort }}" + - --output + - {{ .Values.output.path | quote }} + - --ngxdig + - /usr/local/bin/ngxdig + {{- with .Values.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.containerPort }} + protocol: TCP + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.extraEnvVars }} + env: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: output + mountPath: {{ .Values.output.path }} + {{- if .Values.hostBtf.enabled }} + - name: host-btf + mountPath: {{ .Values.hostBtf.path }} + readOnly: true + {{- end }} + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: output + {{- if .Values.output.sizeLimit }} + emptyDir: + sizeLimit: {{ .Values.output.sizeLimit | quote }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.hostBtf.enabled }} + - name: host-btf + hostPath: + path: {{ .Values.hostBtf.path }} + {{- end }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/ngxdig/templates/service.yaml b/charts/ngxdig/templates/service.yaml new file mode 100644 index 0000000..756c1f7 --- /dev/null +++ b/charts/ngxdig/templates/service.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ngxdig.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "ngxdig.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and .Values.service.externalTrafficPolicy (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + {{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + selector: + {{- include "ngxdig.selectorLabels" . | nindent 4 }} diff --git a/charts/ngxdig/templates/serviceaccount.yaml b/charts/ngxdig/templates/serviceaccount.yaml new file mode 100644 index 0000000..533d023 --- /dev/null +++ b/charts/ngxdig/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "ngxdig.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "ngxdig.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/ngxdig/values.yaml b/charts/ngxdig/values.yaml new file mode 100644 index 0000000..9953e99 --- /dev/null +++ b/charts/ngxdig/values.yaml @@ -0,0 +1,144 @@ +# ============================================================ +# Image +# ============================================================ +image: + # -- ngxdig image repository + repository: api7/ngxdig + # -- Image pull policy. Defaults to Always because the image tag is the moving + # `latest`, so nodes must re-pull to pick up newer builds + pullPolicy: Always + # -- Image tag. Defaults to the chart appVersion when left empty + tag: "latest" + +# -- Image pull secrets for a private registry +imagePullSecrets: [] + +# -- Override the chart name +nameOverride: "" +# -- Override the fully qualified release name +fullnameOverride: "" + +serviceAccount: + # -- Create a ServiceAccount for the collector + create: true + # -- Annotations to add to the ServiceAccount + annotations: {} + # -- Name of the ServiceAccount to use. Generated from the fullname when empty + name: "" + +# ============================================================ +# Collector (DaemonSet) +# ============================================================ +# ngxdig runs as a DaemonSet — one collector Pod per node — because it profiles +# the OpenResty/Nginx worker processes running on that node, so it must be +# co-located with its targets. There is no replicaCount. + +# -- Share the host PID namespace so the collector can see Nginx/OpenResty +# worker processes elsewhere on the node. Required to profile targets outside +# the collector's own Pod +hostPID: true + +# -- Update strategy for the DaemonSet +updateStrategy: {} + +# -- Extra arguments appended to the `ngxdig ui` command +extraArgs: [] + +# -- Extra environment variables for the collector container +extraEnvVars: [] + +# -- Pod-level security context +podSecurityContext: {} + +# -- Container security context. The defaults grant exactly what the eBPF +# collector needs: run as root, and the CAP_BPF / CAP_PERFMON / CAP_SYS_PTRACE / +# CAP_SYS_ADMIN capabilities with unconfined seccomp/AppArmor so BPF, perf +# events, ptrace, and the perf_uprobe PMU attachments used by `cpu-on` and +# `latency` are all permitted. CAP_SYS_ADMIN is the smallest addition that +# satisfies the uprobe perf_event check — `--privileged` is not required +securityContext: + runAsUser: 0 + capabilities: + add: + - BPF + - PERFMON + - SYS_PTRACE + - SYS_ADMIN + seccompProfile: + type: Unconfined + appArmorProfile: + type: Unconfined + +hostBtf: + # -- Mount the node's kernel BTF read-only. Required by the eBPF collector to + # resolve kernel types without DWARF + enabled: true + # -- Host path to the kernel BTF directory + path: /sys/kernel/btf + +output: + # -- Directory inside the container where run artifacts are written + path: /out + # -- sizeLimit for the artifact emptyDir volume. No limit when empty + sizeLimit: "" + +# ============================================================ +# Debug UI +# ============================================================ +# -- Port the ngxdig UI listens on inside the container +containerPort: 8080 + +# The UI is exposed through a Service (always created). Most deployments run a +# single collector — one node, or the DaemonSet pinned to one node — so a +# ClusterIP points at that one Pod. Setting type to NodePort adds a +# : route; pair it with externalTrafficPolicy Local so that +# route reaches the collector on that same node. For quick local access you can +# also `kubectl port-forward` to the Pod — see the chart README / NOTES. +service: + # -- Service type (ClusterIP, NodePort, or LoadBalancer) + type: ClusterIP + # -- Service port + port: 8080 + # -- Static node port for type NodePort. Auto-assigned when empty + nodePort: "" + # -- externalTrafficPolicy for NodePort/LoadBalancer. Local keeps traffic on the + # receiving node, so : reaches that node's own collector + # instead of being load-balanced to another node + externalTrafficPolicy: Local + # -- Service annotations + annotations: {} + +# -- Liveness probe for the collector container +livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 15 +# -- Readiness probe for the collector container +readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + +# -- Resource requests and limits for the collector container +resources: {} + +# -- Node selector for the DaemonSet Pods +nodeSelector: {} +# -- Tolerations for the DaemonSet Pods (e.g. to also run on control-plane nodes) +tolerations: [] +# -- Affinity rules for the DaemonSet Pods +affinity: {} + +# -- Additional annotations for the Pods +podAnnotations: {} +# -- Additional labels for the Pods +podLabels: {} + +# -- Extra volumes for the collector Pod +extraVolumes: [] +# -- Extra volume mounts for the collector container +extraVolumeMounts: []