feat(monitoring): replace scrape dump with vmagent
ci / lint-prettier (push) Skipped
ci / lint-ruff (push) Skipped
ci / lint-yaml (push) Skipped
ci / lint-dockerfiles (push) Skipped
ci / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (pull_request) Successful in 11s
ci / lint-actionlint (pull_request) Successful in 6s
ci / lint-shellcheck (pull_request) Successful in 16s
ci / lint-dockerfiles (pull_request) Successful in 6s
ci / lint-prettier (pull_request) Successful in 16s
ci / lint-ruff (pull_request) Successful in 7s
ci / lint-yaml (pull_request) Successful in 10s
ci / validate (pull_request) Successful in 7s
ci / build (pull_request) Skipped
renovate-ci / validate-renovate (pull_request) Failing after 1m40s

This commit is contained in:
forust committed 2026-10-06 18:03:59 +02:00
1 parent 78cd15f12c
commit 8c0e36a5c0
20 files changed
+74 -3190

No files matched your search

+5
View File
@@ -294,6 +294,11 @@ jobs:
echo "server-side dry-run: ${#manifests[@]} manifests, ${#kustomize_apps[@]} kustomize apps"
failed=0
for m in ${manifests[@]+"${manifests[@]}"}; do
if [[ "$m" == "prometheus-stack/k8s/vmagent.yaml" ]] \
&& ! kubectl get crd vmagents.operator.victoriametrics.com >/dev/null 2>&1; then
echo "skip server-side dry-run until the VictoriaMetrics Operator CRD is installed: $m"
continue
fi
if ! out="$(kubectl apply --dry-run=server -f "$m" 2>&1)"; then
failed=1
echo "::error file=${m}::$(printf '%s' "$out" | head -1)"
+2
View File
@@ -546,6 +546,7 @@ rollback_workloads() {
# have to be declared as custom.regex managers in renovate/renovate.json.
HELM_RELEASES=(
"prometheus-stack|prometheus-community/kube-prometheus-stack|prometheus|86.2.3|prometheus-stack/k8s/grafana-values.yaml|prometheus-stack/k8s/active"
"victoria-operator|victoriametrics/victoria-metrics-operator|prometheus|0.68.1|prometheus-stack/k8s/victoria-operator-values.yaml|prometheus-stack/k8s/active"
"loki|grafana/loki|prometheus|7.3.0|loki/k8s/loki-values.yaml|loki/k8s/active"
"alloy|grafana/alloy|prometheus|1.12.1|loki/k8s/alloy-values.yaml|loki/k8s/active"
"reloader|stakater/reloader|reloader|2.2.17|reloader/k8s/reloader-values.yaml|reloader/k8s/active"
@@ -557,6 +558,7 @@ helm_repo_for() {
prometheus-community/*) echo "prometheus-community https://prometheus-community.github.io/helm-charts" ;;
grafana/*) echo "grafana https://grafana.github.io/helm-charts" ;;
stakater/*) echo "stakater https://stakater.github.io/stakater-charts" ;;
victoriametrics/*) echo "victoriametrics https://victoriametrics.github.io/helm-charts" ;;
esac
}
+17
View File
@@ -0,0 +1,17 @@
# VictoriaMetrics
The `victoria-operator` Helm release converts Prometheus Operator
`ServiceMonitor` resources into owned `VMServiceScrape` resources. The
`VMAgent` selects converted scrapes labeled `release: prometheus-stack` in all
namespaces and writes them to the existing single-node VictoriaMetrics
instance. Changes to selected `ServiceMonitor` resources are reconciled
automatically; there is no copied Prometheus scrape-config blob to regenerate.
The agent drops targets for the Prometheus server service to avoid duplicating
its self-scrape. `scraper: victoria` identifies the samples ingested by this
VMAgent.
The VictoriaMetrics Operator chart and its CRDs are installed before the
Kubernetes manifests by the normal deploy workflow. On a cluster where the
operator CRDs are not installed yet, CI skips the server-side dry-run of the
`VMAgent` resource; the deploy installs the chart before applying that resource.
@@ -0,0 +1,12 @@
nameOverride: victoria-operator
operator:
enable_converter_ownership: true
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 200m
memory: 256Mi
File diff suppressed because it is too large. Load diff
@@ -1,8 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: victoria-secrets
namespace: prometheus
type: Opaque
stringData:
uptime-kuma-password: "REPLACE_ME"
-43
View File
@@ -1,23 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: victoria
namespace: prometheus
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: victoria
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus-stack-kube-prom-prometheus
subjects:
- kind: ServiceAccount
name: victoria
namespace: prometheus
---
apiVersion: v1
kind: Service
metadata:
name: victoria-metrics
@@ -59,7 +40,6 @@ spec:
labels:
app: victoria-metrics
spec:
serviceAccountName: victoria
containers:
- name: victoria
image: victoriametrics/victoria-metrics:v1.153.0-scratch
@@ -67,8 +47,6 @@ spec:
- -storageDataPath=/vmdata
- -retentionPeriod=30d
- -httpListenAddr=:8428
- -promscrape.config=/etc/vm/conf/scrape.yaml
- -promscrape.configCheckInterval=60s
ports:
- containerPort: 8428
readinessProbe:
@@ -88,15 +66,6 @@ spec:
volumeMounts:
- name: vmdata
mountPath: /vmdata
- name: scrape-config
mountPath: /etc/vm/conf
readOnly: true
- name: vm-secrets
mountPath: /etc/vm/secrets
readOnly: true
- name: prom-admission-ca
mountPath: /etc/prometheus/certs
readOnly: true
resources:
requests:
cpu: "100m"
@@ -108,15 +77,3 @@ spec:
- name: vmdata
persistentVolumeClaim:
claimName: victoria-pvc
- name: scrape-config
configMap:
name: victoria-scrape
- name: vm-secrets
secret:
secretName: victoria-secrets
- name: prom-admission-ca
secret:
secretName: prometheus-stack-kube-prom-admission
items:
- key: ca
path: 0_prometheus_prometheus-stack-kube-prom-admission_ca
+29
View File
@@ -0,0 +1,29 @@
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
name: vmagent
namespace: prometheus
spec:
image:
tag: v1.153.0
scrapeInterval: 30s
externalLabels:
scraper: victoria
serviceScrapeNamespaceSelector: {}
serviceScrapeSelector:
matchLabels:
release: prometheus-stack
globalScrapeRelabelConfigs:
- action: drop
source_labels:
- __meta_kubernetes_service_name
regex: prometheus-stack-kube-prom-prometheus
remoteWrite:
- url: http://victoria-metrics.prometheus.svc.cluster.local:8428/api/v1/write
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1000m"
memory: 1Gi
+9
View File
@@ -52,6 +52,15 @@
"depNameTemplate": "kube-prometheus-stack",
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
},
{
"customType": "regex",
"description": "VictoriaMetrics Operator chart version pinned in the deploy workflow",
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|victoriametrics/victoria-metrics-operator\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm",
"depNameTemplate": "victoria-metrics-operator",
"registryUrlTemplate": "https://victoriametrics.github.io/helm-charts"
},
{
"customType": "regex",
"description": "grafana/loki chart version pinned in the deploy workflow",
-543
View File
@@ -1,543 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
# name: unique within the namespace
name: nginx-deployment
# namespace: logical isolation
namespace: example
labels:
# free-form key/value tags used for selection and grouping.
app: nginx
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: nginx-example
app.kubernetes.io/version: "1.27"
app.kubernetes.io/component: server
app.kubernetes.io/part-of: example
app.kubernetes.io/managed-by: kubectl
annotations:
# Key/value, but never used for selection
# Only for metadata (descriptions, owners, timestamps).
description: "deployment example"
owner: team-platform
# finalizers: identifiers that block deletion until some controller removes
# them after cleanup. RARE on workloads.
# finalizers:
# - example.com/cleanup
spec:
# replicas: how many pod copies to keep running. Default 1.
replicas: 3
# revisionHistoryLimit: how many old ReplicaSets are kept so you can roll
# back. Default 10.
revisionHistoryLimit: 5
# progressDeadlineSeconds: if a rollout makes no progress for this long it
# is marked ProgressDeadlineExceeded. Default 600.
progressDeadlineSeconds: 600
# minReadySeconds: a new pod must stay Ready for this long before it counts
# as available. Protects against pods that flap right after start.
minReadySeconds: 10
# paused: freezes the rollout controller. RARE - used to accumulate several
# changes and release them as a single rollout.
paused: false
# selector: defines which pods belong to this Deployment. Must match the
# pod template labels exactly. Immutable after creation.
selector:
matchLabels:
app: nginx
# matchExpressions: set-based selection (In, NotIn, Exists, DoesNotExist).
# RARE on Deployments.
# matchExpressions:
# - key: tier
# operator: In
# values: [frontend]
strategy:
# type: RollingUpdate (replace gradually, default) or Recreate (kill all
# old pods first). Recreate fits state that cannot have two writers at
# once (SQLite file, exclusive lock).
type: RollingUpdate
rollingUpdate:
# maxSurge: how many pods above `replicas` may exist mid-rollout.
# Number or percentage.
maxSurge: 1
# maxUnavailable: how many pods may be simultaneously down mid-rollout.
# Number or percentage.
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
app.kubernetes.io/name: nginx
annotations:
description: "nginx pod"
spec:
# serviceAccountName: the identity pods use against the API server.
serviceAccountName: default
# automountServiceAccountToken: mount the API token into pods. Set false
# for pods that never call the API to shrink the escape blast radius.
automountServiceAccountToken: true
# schedulerName: which scheduler places the pod. The default scheduler
# handles virtually everything.
schedulerName: default-scheduler
# nodeName: pin the pod to one node, bypassing the scheduler. RARE and
# brittle - nodeSelector/affinity express intent better.
# nodeName: node-1
# nodeSelector: hard requirement on node labels.
nodeSelector:
kubernetes.io/os: linux
# hostname/subdomain: give the pod a stable hostname and DNS entry
# <hostname>.<subdomain>.<namespace>.svc.cluster.local. Mostly a
# StatefulSet concern (which gets this automatically).
hostname: nginx
subdomain: example-subdomain
# setHostnameAsFQDN: use the FQDN above as the hostname. Default false.
setHostnameAsFQDN: false
# priorityClassName: scheduling priority; higher values preempt lower.
# priorityClassName: high-priority
# preemptionPolicy: Never stops this pod from preempting others.
# Default PreemptLowerPriority.
preemptionPolicy: PreemptLowerPriority
# runtimeClassName: alternate container runtime (gVisor, Kata).
# Omit for the default runtime.
# runtimeClassName: gvisor
# enableServiceLinks: inject <SVC>_SERVICE_HOST style env vars. True by
# default; false keeps the environment clean when you use DNS only.
enableServiceLinks: true
# hostAliases: extra /etc/hosts lines. RARE - usually means DNS should
# have been fixed instead.
hostAliases:
- ip: 192.168.1.10
hostnames:
- legacy-db.example.com
# hostNetwork/hostPID/hostIPC: share the node's network/process/IPC
# namespaces. Needed for node-level agents; dangerous for apps.
hostNetwork: false
hostPID: false
hostIPC: false
# shareProcessNamespace: all containers in the pod see each other's
# processes. Handy for sidecar debuggers; off by default.
shareProcessNamespace: false
# dnsPolicy: ClusterFirst (default, .svc names resolve), Default
# (inherit the node's resolver), ClusterFirstWithHostNet (for
# hostNetwork pods), None (dnsConfig takes over completely).
dnsPolicy: ClusterFirst
dnsConfig:
nameservers:
- 1.1.1.1
searches:
- example.com
options:
- name: ndots
value: "2"
# readinessGates: custom conditions (reported by external controllers)
# that must be true before the pod counts as Ready. RARE.
# readinessGates:
# - conditionType: example.com/lb-attached
# topologySpreadConstraints: spread pods across zones/hosts with skew
# control. The modern, expressive successor of bare podAntiAffinity.
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: nginx
affinity:
nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution: hard node rule -
# pods that violate it are never scheduled there.
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values: [amd64]
# preferredDuringSchedulingIgnoredDuringExecution: soft node rule -
# the scheduler tries, but schedules anyway if impossible.
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10
preference:
matchExpressions:
- key: node-role.kubernetes.io/worker
operator: Exists
podAffinity:
# Attract to nodes already running matching pods (data locality).
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
podAffinityTerm:
labelSelector:
matchLabels:
app: cache
topologyKey: kubernetes.io/hostname
podAntiAffinity:
# Repel from nodes running matching pods (spread replicas).
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: nginx
topologyKey: kubernetes.io/hostname
tolerations:
# Tolerate a node taint to allow scheduling there. Without a matching
# toleration, a tainted node rejects the pod.
- key: dedicated
operator: Equal
value: "true"
effect: NoSchedule
# tolerationSeconds: with effect NoExecute, tolerate for this long
# before eviction. Omit for infinite tolerance.
tolerationSeconds: 3600
# imagePullSecrets: credentials for private registries.
# imagePullSecrets:
# - name: registry-credentials
# securityContext (pod-level): defaults inherited by every container
# unless a container overrides them.
securityContext:
runAsUser: 101
runAsGroup: 101
# runAsNonRoot: refuse to start as uid 0.
runAsNonRoot: true
# fsGroup: group that owns mounted volumes; kubelet chowns on mount.
fsGroup: 101
# fsGroupChangePolicy: Always (chown on every mount, slow on large
# volumes) or OnRootMismatch (chown only when needed).
fsGroupChangePolicy: OnRootMismatch
# supplementalGroups: extra groups granted for volume access.
supplementalGroups: [102]
# sysctls: namespaced kernel parameters. Unsafe ones need explicit
# kubelet opt-in.
sysctls:
- name: net.core.somaxconn
value: "1024"
# seLinuxOptions: SELinux user/role/type/level. RARE outside MLS.
seLinuxOptions:
level: s0:c123,c456
# seccompProfile: syscall sandbox. RuntimeDefault is the sane
# baseline; Localhost loads a custom profile from the node.
seccompProfile:
type: RuntimeDefault
# windowsOptions: GMSA / runAsUserName for Windows nodes.
initContainers:
# Run strictly in order, each to completion, before app containers
# start. Used for migrations, permission fixes, dependency waits.
- name: init-permissions
image: busybox:1.36
command: ["sh", "-c", "chown -R 101:101 /data"]
volumeMounts:
- name: html
mountPath: /data
resources:
requests:
cpu: "10m"
memory: "16Mi"
limits:
cpu: "50m"
memory: "64Mi"
# restartPolicy on a container (not the pod): Always turns it into
# a native sidecar that keeps running next to the app (1.28+).
# restartPolicy: Always
containers:
- name: nginx
# image: repository plus tag. Pin tags - `latest` moves under you.
image: nginx:1.27.3
# imagePullPolicy: Always (re-pull even pinned tags), IfNotPresent
# (use cache, works offline), Never (cache only, fails otherwise).
imagePullPolicy: IfNotPresent
# command: overrides the image ENTRYPOINT. args: overrides CMD.
# command: ["nginx"]
# args: ["-g", "daemon off;"]
# workingDir: overrides the image WORKDIR.
workingDir: /usr/share/nginx/html
# stdin/stdinOnce/tty: interactive input. For debug shells and
# one-shot runs, never for servers.
stdin: false
stdinOnce: false
tty: false
ports:
- name: http
containerPort: 80
protocol: TCP
# hostPort: expose straight on the node, bypassing Services.
# RARE - allows only one such pod per node per port.
# hostPort: 8080
# hostIP: which node address hostPort binds to.
# hostIP: 127.0.0.1
env:
- name: NGINX_PORT
value: "80"
- name: POD_NAME
valueFrom:
fieldRef:
# fieldPath exposes pod metadata: metadata.name,
# metadata.namespace, metadata.uid, spec.nodeName,
# spec.serviceAccountName, status.podIP(s), etc.
fieldPath: metadata.name
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_MEMORY_LIMIT
valueFrom:
# resourceFieldRef exposes this container's own
# requests/limits. divisor formats the value.
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
- name: API_PASSWORD
valueFrom:
secretKeyRef:
name: example-secrets
key: api-password
# optional: tolerate a missing key (variable stays unset).
optional: false
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: example-config
key: log-level
optional: false
envFrom:
# Bulk-inject every key of a ConfigMap/Secret as env vars.
- configMapRef:
name: example-config
optional: false
# prefix: prepended to every injected key, avoids collisions.
prefix: APP_
- secretRef:
name: example-secrets
optional: false
resources:
# requests: guaranteed reservation used for scheduling. Set at
# measured idle/p95 - over-requesting starves neighboring pods.
requests:
cpu: "100m"
memory: "128Mi"
# limits: hard ceiling. Breaching memory kills the container
# (OOMKilled); breaching CPU only throttles it (slow, not dead).
limits:
cpu: "500m"
memory: "512Mi"
# claims: reference a ResourceClaim for dynamic resources
# (GPUs via DRA, 1.26+). RARE.
# claims:
# - name: gpu
# resizePolicy: what happens on in-place container resize (1.27+).
# NotRequired keeps running; RestartContainer restarts to apply.
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: false
# subPath: mount a single file/dir of the volume instead of
# its root. Typical for single-file config mounts.
# subPath: index.html
# subPathExpr: subPath assembled from env variables.
# subPathExpr: $(POD_NAME)/data
# mountPropagation: share mounts back with the host
# (HostToContainer, Bidirectional). Storage-driver territory.
mountPropagation: None
- name: tmp
mountPath: /tmp
# volumeDevices: raw block devices without a filesystem. RARE -
# databases on local PVs with volumeMode: Block.
# volumeDevices:
# - name: blockvol
# devicePath: /dev/xvda
livenessProbe:
# Exactly one handler per probe: httpGet, tcpSocket, exec, grpc.
httpGet:
path: /healthz
port: http
scheme: HTTP
# httpHeaders: extra headers sent with the probe request.
httpHeaders:
- name: Host
value: example.com
# initialDelaySeconds: wait after start before first probe.
initialDelaySeconds: 15
# periodSeconds: interval between probes.
periodSeconds: 20
# timeoutSeconds: when a single probe counts as failed.
timeoutSeconds: 5
# successThreshold: consecutive successes to count as healthy.
# Keep 1.
successThreshold: 1
# failureThreshold: consecutive failures to trigger the action.
failureThreshold: 3
readinessProbe:
# Failing readiness removes the pod from Services (no traffic)
# without restarting it. Failing liveness restarts it.
httpGet:
path: /readyz
port: 80
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
startupProbe:
# Disables liveness/readiness until it first succeeds. Total
# budget = failureThreshold * periodSeconds (here 30 * 10s).
# The cure for slow-starting apps that otherwise get
# restart-looped before they finish booting.
tcpSocket:
port: 80
# host: probe a different host than the pod IP. RARE.
failureThreshold: 30
periodSeconds: 10
timeoutSeconds: 5
lifecycle:
# postStart runs right after start; preStop runs before SIGTERM.
# Slow hooks stall the pod transition - keep them fast.
postStart:
exec:
command: ["sh", "-c", "echo started > /tmp/started"]
# Classic preStop: sleep so endpoints are removed everywhere
# before the process receives SIGTERM.
preStop:
exec:
command: ["sh", "-c", "sleep 5"]
# terminationMessagePath: file whose content becomes the container's
# final status message. FallbackToLogsOnError appends log tail when
# the file is empty.
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 101
runAsGroup: 101
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
seccompProfile:
type: RuntimeDefault
# ephemeralContainers: troubleshooting shells injected into a RUNNING
# pod with kubectl debug. Declared ad-hoc in practice, never committed.
# ephemeralContainers:
# - name: debugger
# image: busybox:1.36
# command: ["sh"]
# stdin: true
# tty: true
# targetContainerName: nginx
volumes:
- name: html
persistentVolumeClaim:
claimName: example-pvc
# readOnly: mount the claim read-only in this pod.
readOnly: false
- name: tmp
emptyDir:
# medium "" (node disk) or Memory (tmpfs). sizeLimit evicts the
# pod when exceeded. Dies with the pod either way.
medium: ""
sizeLimit: 256Mi
- name: config-files
configMap:
# Each key becomes a file under the mount path.
name: example-config-files
defaultMode: 0644
optional: false
items:
- key: nginx.conf
path: nginx.conf
mode: 0644
- name: tls
secret:
# Secret volumes are tmpfs-backed, never touch node disk.
secretName: example-tls
defaultMode: 0644
optional: false
items:
- key: tls.crt
path: tls.crt
mode: 0644
- name: host-time
hostPath:
path: /etc/localtime
# type: DirectoryOrCreate, Directory, FileOrCreate, File,
# Socket, CharDevice, BlockDevice. Always set it: a missing
# path then fails loudly instead of silently creating the
# wrong filesystem object.
type: File
- name: podinfo
downwardAPI:
# Expose pod metadata as files.
items:
- path: labels
fieldRef:
fieldPath: metadata.labels
- path: cpu-request
resourceFieldRef:
resource: requests.cpu
containerName: nginx
divisor: 1m
- name: all-config
projected:
# Merge several sources into a single directory.
defaultMode: 0644
sources:
- configMap:
name: example-config
items:
- key: log-level
path: log-level
- secret:
name: example-secrets
items:
- key: api-password
path: password
- downwardAPI:
items:
- path: podname
fieldRef:
fieldPath: metadata.name
# Further volume types share the same `name:` + type shape:
# nfs: { server, path }, csi: (storage drivers), persistentVolumeClaim
# shown above, plus legacy in-tree plugins (fc, iscsi, rbd, glusterfs)
# and gitRepo (deprecated - use initContainers + emptyDir instead).
# restartPolicy: only Always is valid for Deployments. (Jobs use
# OnFailure/Never; bare pods accept all three.)
restartPolicy: Always
terminationGracePeriodSeconds: 30
# activeDeadlineSeconds: kill the pod after this long no matter what.
# A Job concern, not a server concern - shown only for completeness.
# activeDeadlineSeconds: 3600
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: example-pvc
namespace: example
spec:
# accessModes: ReadWriteOnce (one node), ReadOnlyMany, ReadWriteMany
# (needs a shared filesystem), ReadWriteOncePod (single pod, strictest).
accessModes:
- ReadWriteOnce
# storageClassName: selects the provisioner. "" (empty) disables dynamic
# provisioning and binds a pre-created volume instead.
storageClassName: standard
# volumeMode: Filesystem (default) or Block (used with volumeDevices).
volumeMode: Filesystem
resources:
requests:
storage: 5Gi
# limits: accepted on paper, almost no provisioner enforces them.
# selector: bind a specific pre-created PV by labels. RARE with dynamic
# provisioning.
# selector:
# matchLabels:
# disk: ssd
# dataSource: clone this PVC from another PVC or a snapshot at creation.
# dataSource:
# name: example-snapshot
# kind: VolumeSnapshot
# apiGroup: snapshot.storage.k8s.io
# dataSourceRef: cross-namespace-capable successor of dataSource.
-63
View File
@@ -1,63 +0,0 @@
# Exhaustive EndpointSlice reference (discovery.k8s.io/v1).
# EndpointSlices are the address lists behind a Service: each entry says
# "IP X serves port Y, ready or not". Normally the endpoint controller writes
# them automatically from the Service selector. You write one by hand in a
# single case: a selector-less Service pointing OUTSIDE the cluster (a host
# daemon, a LAN appliance, an external database). The pair looks like:
# Service (no selector, same port names) + this EndpointSlice.
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: app-external-abc123
namespace: example
labels:
# kubernetes.io/service-name: THE binding label. It must equal the
# selector-less Service name - this is what attaches the slice to it.
# The endpoint controller owns slices it creates; hand-written ones
# just need this label to be picked up.
kubernetes.io/service-name: app-external-service
app: app
annotations:
description: "hand-written slice for an off-cluster backend"
# addressType: IPv4, IPv6, or FQDN. All endpoints in one slice share it -
# mix families with one slice per family.
addressType: IPv4
ports:
- name: http
# name: MUST match the Service port name it serves.
protocol: TCP
# port: the REAL backend port (may differ from the Service port - the
# Service port is the in-cluster alias, this is where packets go).
port: 8080
# appProtocol: payload hint, mirrors the Service field.
appProtocol: http
endpoints:
# One entry per backend address. kube-proxy load-balances across the ones
# whose conditions say ready+serving+terminating=false.
- addresses:
# addresses: one or more IPs (or a single DNS name for FQDN slices).
- 192.168.1.50
conditions:
# ready: backend accepts traffic. False removes it from rotation
# without deleting the entry (flap-friendly).
ready: true
# serving: the process is up. Differs from ready during shutdown:
# serving=false + terminating=true = draining.
serving: true
# terminating: the endpoint is going away. Draining traffic, not dead.
terminating: false
# hostname: DNS name published for this endpoint (headless Services).
# hostname: backend-1
# targetRef: link back to the pod/node object (set automatically on
# controller-managed slices; omit on hand-written ones).
# targetRef:
# kind: Pod
# namespace: example
# name: app-67890abcde-fghij
# uid: 12345678-1234-1234-1234-123456789abc
# nodeName: the node hosting this endpoint (topology-aware routing).
# zone: override the endpoint zone (defaults from nodeName).
# hints: topology hints for zone-aware routing (PreferClose).
# hints:
# forZones:
# - name: zone-a
-100
View File
@@ -1,100 +0,0 @@
# Exhaustive Gateway reference (gateway.networking.k8s.io/v1).
# A Gateway is the entry door: it owns listener ports/protocols/hostnames and
# delegates actual routing to Route objects (HTTPRoute, TCPRoute, ...), which
# attach via parentRefs. One Gateway usually fronts many Routes.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example
namespace: example
labels:
app: example
annotations:
description: "exhaustive gateway example"
spec:
# gatewayClassName: which controller implements this Gateway
# (kubectl get gatewayclass). The controller only touches Gateways naming
# its own class; anything else stays Ignored.
gatewayClassName: example-class
# addresses: VIPs/hostnames to request for the Gateway. Most controllers
# (including cloud LBs) allocate and fill status.addresses automatically;
# setting this pins a static IP. Omit for auto-assignment.
# addresses:
# - type: IPAddress
# value: 203.0.113.10
# - type: Hostname
# value: lb.example.com
# infrastructure: controller-specific settings for the provisioned data
# plane (labels/annotations propagated to it). RARE - most setups never
# need it.
# infrastructure:
# labels:
# environment: prod
# annotations:
# example.com/keep: "true"
listeners:
# Each listener = one port + protocol + optional hostname + TLS + which
# Routes may attach. Listener names are referenced by Route parentRefs
# via sectionName.
- name: http
# port: 1-65535. Must be free on the data plane (controllers often
# require 80/443 to match their own entrypoints, otherwise the
# listener is marked Invalid/Conflicted).
port: 80
# protocol: HTTP, HTTPS, TLS, TCP, UDP.
protocol: HTTP
# hostname: restrict this listener to one DNS name. Omit to accept all
# (Routes then narrow via their own hostnames). Listener hostname and
# Route hostnames must intersect or the Route is rejected.
hostname: app.example.com
# allowedRoutes: which Routes may bind here.
allowedRoutes:
namespaces:
# from: Same (only this namespace), All (any namespace), or
# Selector (namespaces matching the selector below).
from: Same
# selector: used only with from: Selector.
# selector:
# matchLabels:
# shared-gateway-access: "true"
# kinds: restrict by Route kind. Default allows whatever the
# listener protocol supports (HTTPRoute on HTTP, etc.).
kinds:
- kind: HTTPRoute
- name: https
port: 443
protocol: HTTPS
hostname: app.example.com
# tls: termination settings for HTTPS/TLS listeners.
tls:
# mode: Terminate (decrypt here, default) or Passthrough (forward
# encrypted bytes to the backend - the backend holds the key).
mode: Terminate
# certificateRefs: TLS Secrets (or other kinds) in the SAME namespace
# (cross-namespace needs a ReferenceGrant). SNI picks among them.
certificateRefs:
- name: app-prod-tls
# kind/group default to Secret / core. Other kinds (e.g. a
# cert-manager Certificate via a plugin) set kind + group.
kind: Secret
group: ""
# options: controller-specific TLS knobs, referenced by name
# (cipher suites, min version). RARE.
# options:
# name: tls-options
- name: tcp
port: 2222
protocol: TCP
allowedRoutes:
namespaces:
from: Same
kinds:
- kind: TCPRoute
- name: udp
port: 3478
protocol: UDP
allowedRoutes:
namespaces:
from: Same
kinds:
- kind: UDPRoute
-181
View File
@@ -1,181 +0,0 @@
# Exhaustive HTTPRoute reference (gateway.networking.k8s.io/v1).
# Attaches to a Gateway listener via parentRefs and routes HTTP(S) by
# hostname + path/method/headers/query. Rules are evaluated in order; the
# first matching rule wins.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app
namespace: example
labels:
app: app
spec:
parentRefs:
# Every entry picks one listener to bind to. Omit sectionName/port to
# attach to ALL listeners of the Gateway (common for simple setups).
- name: example
# namespace: Gateway's namespace. Omit when same-namespace (the norm;
# cross-namespace needs the Gateway to allow it).
# namespace: example
# kind/group: default Gateway / gateway.networking.k8s.io. Set
# explicitly only for non-Gateway parents (mesh service parents).
kind: Gateway
group: gateway.networking.k8s.io
# sectionName: the listener name from the Gateway (http/https/...).
sectionName: https
# port: narrow further to one listener port. RARE when sectionName is
# already set.
port: 443
# hostnames: which Host headers this Route serves. Must intersect the
# listener hostname; otherwise the Route is rejected as incompatible.
# Omit to match every hostname on the listener.
hostnames:
- app.example.com
- www.example.com
rules:
# Rule 1: API traffic with header manipulation and canary split.
- matches:
# All conditions inside one match are ANDed; several matches in the
# list are ORed.
- path:
# type: Exact (one URL), PathPrefix (subtree), RegularExpression.
type: PathPrefix
value: /api
method: POST
headers:
# type: Exact or RegularExpression. Names are case-insensitive
# per HTTP spec; values are case-sensitive.
- type: Exact
name: X-Api-Version
value: v2
queryParams:
# Match on ?debug=true style parameters.
- type: Exact
name: debug
value: "true"
filters:
# Filters run in order and transform the request/response.
- type: RequestHeaderModifier
requestHeaderModifier:
# add: append even if present (duplicates allowed). set:
# overwrite-or-add. remove: delete by name.
add:
- name: X-Gateway
value: example
set:
- name: X-Forwarded-Proto
value: https
remove:
- X-Internal-Token
- type: ResponseHeaderModifier
responseHeaderModifier:
set:
- name: X-Frame-Options
value: DENY
remove:
- Server
# backendRefs below carry per-backend filters too; rule-level filters
# apply to every backend of this rule.
backendRefs:
- name: app-service
# port: the Service port (number). Required - unlike backendRef in
# Ingress, there is no default.
port: 80
# group/kind: default Service / core (""). Other kinds (e.g. a
# ServiceImport for multi-cluster) set kind + group explicitly.
kind: Service
group: ""
# weight: traffic share. 90/10 below = canary: 90% stable, 10% new.
weight: 90
filters:
# Per-backend filter: only this backend's requests get it.
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Backend
value: stable
- name: app-canary-service
port: 80
weight: 10
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Backend
value: canary
# timeouts: per-attempt deadlines. request = whole gateway-to-client
# exchange; backendRequest = single backend try.
timeouts:
request: 30s
backendRequest: 10s
# sessionPersistence: stick a client to one backend (cookie-based).
# Type Cookie or Header; absoluteTimeout caps the stickiness.
sessionPersistence:
sessionName: route-session
type: Cookie
absoluteTimeout: 1h
cookieConfig:
lifetimeType: Session
# Rule 2: redirect old path to a new URL.
- matches:
- path:
type: PathPrefix
value: /old-docs
filters:
- type: RequestRedirect
requestRedirect:
# Any combination: scheme/host/port/path/statusCode. Unset fields
# keep the original value.
scheme: https
hostname: docs.example.com
path:
# type: ReplaceFullPath or ReplacePrefixMatch (rewrite the
# matched prefix, keep the remainder).
type: ReplacePrefixMatch
replacePrefixMatch: /docs
port: 443
# statusCode: 301 (permanent) or 302 (temporary).
statusCode: 301
# Rule 3: rewrite the URL but still proxy (client sees no redirect).
- matches:
- path:
type: PathPrefix
value: /shop
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /store
# hostname: also rewrite the Host header sent upstream.
# hostname: store-internal.example.com
backendRefs:
- name: app-service
port: 80
# Rule 4: mirror (shadow) traffic to a second backend for testing.
# The mirror gets a copy; its response is discarded.
- matches:
- path:
type: Exact
value: /checkout
filters:
- type: RequestMirror
requestMirror:
backendRef:
name: app-shadow-service
port: 80
backendRefs:
- name: app-service
port: 80
# Rule 5: delegate to an implementation-specific filter (auth plugin,
# rate limit, wasm). The controller documents the group/kind it honors.
# - filters:
# - type: ExtensionRef
# extensionRef:
# group: example.com
# kind: AuthPolicy
# name: app-auth
# Catch-all rule (no matches): everything not matched above lands here.
- backendRefs:
- name: app-service
port: 80
-52
View File
@@ -1,52 +0,0 @@
# Exhaustive Traefik IngressRouteTCP reference (traefik.io/v1alpha1).
# Routes raw TCP: SSH, databases, or TLS-passthrough where Traefik never
# decrypts. Two TLS modes exist - termination (Traefik holds the cert) and
# passthrough (backend holds the cert) - and they are mutually exclusive.
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: app-ssh
namespace: example
labels:
app: app
spec:
entryPoints:
- ssh
routes:
# Plain TCP (SSH here): no TLS block at all, bytes flow as-is.
- match: HostSNI(`*`)
# HostSNI matches the TLS Server Name Indication. `*` accepts anything
# (required for non-TLS protocols like SSH that send no SNI).
# With TLS + a real hostname: HostSNI(`db.example.com`).
# middlewares: TCP middleware chain (IP allowlist, rate limit...).
# middlewares:
# - name: ssh-allowlist
# priority: same semantics as HTTP - higher wins.
# priority: 10
services:
- name: app-service
port: 2222
# weight: share of connections across backends.
# weight: 1
# terminationDelay: linger after backend close to drain in-flight
# data. Default 100ms; raise for slow protocols.
terminationDelay: 100
# proxyProtocol: PROXY header toward the backend (v1/v2) so it
# learns real client IPs.
# proxyProtocol:
# version: 2
# TLS termination: Traefik decrypts with its own cert, forwards plaintext.
# - match: HostSNI(`db.example.com`)
# services:
# - name: app-service
# port: 5432
# tls: enable TLS handling on this route. Omit entirely for plain TCP.
# tls:
# Either termination...
# secretName: app-tcp-tls
# options:
# name: modern-tls
# domains:
# - main: db.example.com
# ...or passthrough (Traefik never sees plaintext; needs SNI routing):
# passthrough: true
-19
View File
@@ -1,19 +0,0 @@
# Exhaustive Traefik IngressRouteUDP reference (traefik.io/v1alpha1).
# Routes UDP datagrams (DNS, STUN/TURN, syslog...). No match rules exist -
# UDP has no hostname/SNI to route on, so one route per entrypoint simply
# forwards everything it receives.
apiVersion: traefik.io/v1alpha1
kind: IngressRouteUDP
metadata:
name: app-stun
namespace: example
labels:
app: app
spec:
entryPoints:
- stun
services:
- name: app-service
port: 3478
# weight: share of datagrams when several backends are listed.
weight: 1
-93
View File
@@ -1,93 +0,0 @@
# Exhaustive Traefik IngressRoute reference (traefik.io/v1alpha1, HTTP).
# Routes are evaluated top to bottom by priority, then by rule length: the
# first matching route handles the request. Keep specific rules above the
# catch-all.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: app-prod
namespace: example
labels:
app: app
annotations:
description: "exhaustive traefik http route example"
spec:
# entryPoints: static entrypoints the route listens on (ports Traefik was
# started with: web=:80, websecure=:443, plus any custom ones).
entryPoints:
- websecure
routes:
# Rule 1: API subtree with middleware chain and weighted backends.
- match: Host(`app.example.com`) && PathPrefix(`/api`)
# kind: Rule (match traffic) or the same match used for redirections.
kind: Rule
# priority: explicit precedence. Higher wins regardless of position.
# Default is the rule length in characters - explicit numbers beat
# clever ordering.
priority: 100
# middlewares: request pipeline, in order (auth, headers, rate limit,
# redirect, strip prefix...). Same-namespace by name; cross-namespace
# as name@namespace (never across providers without the suffix).
middlewares:
- name: app-auth
- name: security-headers
services:
- name: app-service
# port: Service port number or name.
port: 80
# scheme: http (default), https (TLS backend), h2c (cleartext
# HTTP/2, e.g. gRPC without TLS).
scheme: http
# weight: traffic share for canary/blue-green splits.
weight: 90
# serversTransport: ServersTransport CRD with TLS/forwarding
# tuning for this backend (rootCAs, insecureSkipVerify...).
# serversTransport: app-transport
# responseForwarding:
# flushInterval: 100ms
# passHostHeader: forward the original Host header (default true).
# passHostHeader: true
# proxyProtocol: speak PROXY protocol to the backend so it sees
# real client IPs. Version v1 or v2; backend must understand it.
# proxyProtocol:
# version: 2
- name: app-canary-service
port: 80
weight: 10
# Rule 2: multiple hosts, regex path, external backend by URL.
- match: (Host(`app.example.com`) || Host(`www.example.com`)) && PathRegexp(`^/files/.*$`)
kind: Rule
priority: 50
services:
# servers: bypass the Service and address backends directly.
# Only one of name/port (cluster Service) or servers (explicit
# URLs) may be set.
- name: app-service
port: 80
# Catch-all rule: everything not matched above.
- match: Host(`app.example.com`)
kind: Rule
priority: 1
services:
- name: app-service
port: 80
# tls: terminate TLS on this route. Omit the whole block for plain HTTP.
tls:
# secretName: TLS Secret (tls.crt/tls.key) in THIS namespace.
secretName: app-prod-tls
# options: TLSOption CRD (minVersion, cipherSuites, sniStrict...).
# options:
# name: modern-tls
# certResolver: ACME resolver name (letsencrypt-style) that issues the
# certificate on demand. Use EITHER certResolver OR secretName, not both:
# resolver for auto-issued certs, secretName for pre-made ones.
# certResolver: letsencrypt
# store: custom TLSStore for the certificate. Default store otherwise.
# store:
# name: default
# domains: certificates to request/serve (main + SANs). With secretName
# this documents intent; with certResolver it drives issuance.
domains:
- main: app.example.com
sans:
- www.example.com
-100
View File
@@ -1,100 +0,0 @@
# Exhaustive Service reference (v1).
# A Service is a stable virtual endpoint in front of pods: one DNS name and
# one cluster IP that load-balances to the currently Ready pods behind it.
# Pods come and go; the Service name (app-service.example.svc.cluster.local)
# never changes.
apiVersion: v1
kind: Service
metadata:
name: app-service
namespace: example
labels:
app: app
annotations:
description: "exhaustive service example"
spec:
# selector: pods carrying these labels receive traffic. Empty selector =
# no automatic endpoints (pair with a hand-written EndpointSlice to aim at
# an external address - see endpointslice.yaml).
selector:
app: app
ports:
- name: http
# protocol: TCP (default), UDP, or SCTP. Each port entry needs one.
protocol: TCP
# port: the port clients connect to on the Service IP.
port: 80
# targetPort: the port on the pod. Number or container port NAME
# (names decouple the Service from container port renumbering).
# Omit when it equals `port`.
targetPort: http
# nodePort: fixed node port for type NodePort/LoadBalancer (range
# 30000-32767). Omit for auto-assignment.
# nodePort: 30080
# appProtocol: protocol hint for the payload (http, https, grpc, h2c,
# ws...). Used by meshes and LBs, ignored by plain kube-proxy routing.
appProtocol: http
- name: metrics
protocol: TCP
port: 9090
targetPort: 9090
# type: ClusterIP (default, internal VIP), NodePort (also open a fixed port
# on every node), LoadBalancer (NodePort + cloud LB in front),
# ExternalName (DNS alias, no proxying - see below).
type: ClusterIP
# clusterIP: pin the virtual IP. "None" makes the Service headless: no VIP,
# DNS returns pod IPs directly (required base for StatefulSets).
# clusterIP: None
# clusterIPs / ipFamilies / ipFamilyPolicy: dual-stack control.
# ipFamilies: [IPv4] (default), [IPv6], or [IPv4, IPv6].
# ipFamilyPolicy: SingleStack (default), PreferDualStack, RequireDualStack.
# ipFamilies:
# - IPv4
# ipFamilyPolicy: SingleStack
# sessionAffinity: None (default, spread every connection) or ClientIP
# (same client IP sticks to one pod).
sessionAffinity: None
# sessionAffinityConfig: stickiness TTL for ClientIP affinity.
# sessionAffinityConfig:
# clientIP:
# timeoutSeconds: 10800
# publishNotReadyAddresses: send traffic to not-Ready pods too. Needed for
# peer discovery where members must find each other before anyone is Ready.
publishNotReadyAddresses: false
# internalTrafficPolicy: Cluster (default, route to pods on any node) or
# Local (only pods on the receiving node - preserves source IP, drops
# traffic on nodes without local pods).
internalTrafficPolicy: Cluster
# --- NodePort / LoadBalancer extras (ignored by pure ClusterIP) ---
# externalTrafficPolicy: Cluster (default) or Local. Local preserves the
# client source IP but drops traffic arriving on nodes with no local pod.
# externalTrafficPolicy: Cluster
# healthCheckNodePort: fixed node port for the LB health check (Local
# policy). Omit for auto-assignment.
# healthCheckNodePort: 32111
# allocateLoadBalancerNodePorts: set false to skip node-port allocation on
# a LoadBalancer (when the LB routes straight to pods). Default true.
# allocateLoadBalancerNodePorts: true
# loadBalancerIP: request a specific IP from the cloud provider. Provider
# support varies; most now prefer annotations or IP pools.
# loadBalancerIP: 203.0.113.10
# loadBalancerSourceRanges: client CIDRs allowed through the cloud LB.
# Unset = world-open. This is the cloud firewall in front of the Service.
# loadBalancerSourceRanges:
# - 203.0.113.0/24
# loadBalancerClass: use a custom LB implementation instead of the cloud
# default (e.g. MetalLB speaker). The named controller must be installed.
# loadBalancerClass: example.com/custom-lb
# trafficDistribution: hint how to prefer endpoints (PreferClose = same
# zone first). Best-effort, kube-proxy dependent.
# trafficDistribution: PreferClose
# --- other types ---
# externalIPs: extra IPs (already routed to nodes) that also serve this
# Service. Traffic arriving there is proxied like ClusterIP traffic.
# externalIPs:
# - 203.0.113.20
# ExternalName type: no proxying at all - DNS CNAME to the target.
# Ports are informational. Used to reference outside names under a stable
# in-cluster name.
# type: ExternalName
# externalName: db.example.com
-166
View File
@@ -1,166 +0,0 @@
# Exhaustive StatefulSet reference (apps/v1), shown with its headless Service.
# StatefulSets give each pod a stable name and stable storage:
# web-0, web-1, ... each reattached to its own volume after rescheduling.
# The classic use is databases and anything with an identity (postgres,
# redis, kafka). For the full container/pod field catalog see
# deployment.yaml - only StatefulSet-specific fields are expanded here.
apiVersion: v1
kind: Service
metadata:
name: example-sts
namespace: example
labels:
app: example-sts
spec:
# clusterIP: None makes the Service headless: no virtual IP, DNS returns
# the pod IPs directly (web-0.example-sts...). Required for StatefulSets -
# it is how stable network identity works.
clusterIP: None
# publishNotReadyAddresses: include not-Ready pods in DNS. Needed for
# peer discovery when members must find each other before anyone is Ready
# (etcd, clustered databases).
publishNotReadyAddresses: false
selector:
app: example-sts
ports:
- name: db
port: 5432
targetPort: db
# sessionAffinity: None (default, spread connections) or ClientIP (sticky
# sessions to one pod). Stateful apps sometimes want ClientIP.
sessionAffinity: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: example-sts
namespace: example
labels:
app: example-sts
spec:
# serviceName: the headless Service above. Must exist; governs the pods'
# DNS domain. Changing it requires recreating the StatefulSet.
serviceName: example-sts
# replicas: pod count. Pods start in order 0..N-1 and stop in reverse.
replicas: 3
# revisionHistoryLimit: old ControllerRevisions kept for rollback.
revisionHistoryLimit: 5
# minReadySeconds: pod must stay Ready this long to count as available.
minReadySeconds: 10
# podManagementPolicy: OrderedReady (default - strict 0,1,2 startup order,
# each predecessor must be Ready) or Parallel (start/stop all at once,
# faster for stateless-ish sets that only want stable names).
podManagementPolicy: OrderedReady
# persistentVolumeClaimRetentionPolicy: what happens to per-pod PVCs on
# scale-down (whenDeleted) and StatefulSet deletion (whenScaled). Retain
# keeps data (safe default); Delete wipes it. Set explicitly - the default
# Retain surprises people who expected cleanup.
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain
whenScaled: Retain
# ordinals: first ordinal (default 0). RARE - used when migrating an
# existing cluster whose numbering starts elsewhere.
# ordinals:
# start: 0
selector:
matchLabels:
app: example-sts
updateStrategy:
# type: RollingUpdate (default) or OnDelete (new pods only replace old
# ones when you delete them manually - full control for databases).
type: RollingUpdate
rollingUpdate:
# partition: only ordinals >= partition are updated. Lets you canary:
# partition 2 updates web-2 first, then lower to 0 for the rest.
partition: 0
# maxUnavailable: how many pods may be down during the update (1.25+).
# StatefulSets traditionally allowed exactly 1; now configurable.
maxUnavailable: 1
template:
metadata:
labels:
app: example-sts
spec:
serviceAccountName: default
automountServiceAccountToken: true
terminationGracePeriodSeconds: 60
# Databases want a long grace: 30s kills a checkpointing postmaster
# mid-write. 60-120 is typical for postgres.
containers:
- name: db
image: postgres:17
imagePullPolicy: IfNotPresent
ports:
- name: db
containerPort: 5432
env:
- name: POSTGRES_USER
value: example
- name: POSTGRES_DB
value: example
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: example-secrets
key: db-password
# Probes for a database: pg_isready via exec is the standard.
# Budgets are generous - killing a recovering database only buys
# another full replay.
startupProbe:
exec:
command: ["sh", "-c", "pg_isready -U example -d example"]
# failureThreshold * periodSeconds = total startup budget
# (60 * 10s = 10 minutes here).
failureThreshold: 60
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
command: ["sh", "-c", "pg_isready -U example -d example"]
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command: ["sh", "-c", "pg_isready -U example -d example"]
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "1Gi"
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
# subPath: mounting the volume root directly breaks postgres
# (it wants an empty dir); subPath gives it a subdirectory.
subPath: pgdata
volumes: []
# No shared volumes here: each pod gets its own PVC from the template
# below, mounted under the same `data` name.
volumeClaimTemplates:
# One template entry per volume. Pod web-N gets PVC data-web-N,
# created on first scheduling and (per the retention policy) kept after.
- metadata:
name: data
labels:
app: example-sts
annotations:
description: "per-pod database storage"
spec:
accessModes:
# Must be ReadWriteOnce: one pod owns its volume. (Shared RWX
# defeats the whole point of per-pod volumes.)
- ReadWriteOnce
storageClassName: standard
volumeMode: Filesystem
resources:
requests:
storage: 10Gi
# selector/dataSource/dataSourceRef: same semantics as a plain PVC
# (bind a specific PV, clone, restore from snapshot). See
# deployment.yaml.
-35
View File
@@ -1,35 +0,0 @@
# Exhaustive TCPRoute reference (gateway.networking.k8s.io/v1alpha2).
# Routes raw TCP (SSH, databases, any non-HTTP protocol) from a TCP listener
# to backends. No hostname/path matching exists at this layer - there is
# nothing but the destination port to route on. For TLS with SNI-based
# routing see TLSRoute; for HTTP see HTTPRoute.
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: app-ssh
namespace: example
labels:
app: app
spec:
parentRefs:
# Bind to the TCP listener of the Gateway. Same fields as HTTPRoute
# parentRefs: name/kind/group plus sectionName and/or port narrowing.
- name: example
kind: Gateway
group: gateway.networking.k8s.io
sectionName: tcp
port: 2222
rules:
- backendRefs:
- name: app-service
# port: backend Service port. Required.
port: 2222
kind: Service
group: ""
# weight: share of connections when several backends are listed.
weight: 1
# Second backend: every new connection goes 3:1 here. Weights are
# the only traffic-shaping knob TCP routing has.
- name: app-replica-service
port: 2222
weight: 3
-29
View File
@@ -1,29 +0,0 @@
# Exhaustive UDPRoute reference (gateway.networking.k8s.io/v1alpha2).
# Routes raw UDP datagrams (DNS, STUN/TURN, game servers, QUIC-before-TLS)
# from a UDP listener to backends. Same minimal shape as TCPRoute: UDP has
# no sessions or headers to match on, so backendRefs carry the whole rule.
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
name: app-stun
namespace: example
labels:
app: app
spec:
parentRefs:
# Bind to the UDP listener of the Gateway. Same fields as HTTPRoute
# parentRefs: name/kind/group plus sectionName and/or port narrowing.
- name: example
kind: Gateway
group: gateway.networking.k8s.io
sectionName: udp
port: 3478
rules:
- backendRefs:
- name: app-service
# port: backend Service port. Required.
port: 3478
kind: Service
group: ""
# weight: share of traffic when several backends are listed.
weight: 1