Compare commits
19
Commits
900eb1719d
..
main
@@ -0,0 +1,161 @@
|
|||||||
|
argo-cd:
|
||||||
|
# GKE counterpart of helm-overrides/k8s-admin-prd-ase1/argocd-admin-prd.
|
||||||
|
#
|
||||||
|
# Installed once by hand with `helm install argocd-admin-prd` (namespace
|
||||||
|
# "argocd"), then manages itself through the argocd Application in
|
||||||
|
# devops-infra-argo-config-gcp, whose nameOverride matches that release.
|
||||||
|
# Deliberately no image tag pin, unlike the homelab: the chart's own
|
||||||
|
# appVersion (v3.5.2) governs, so the image cannot drift from the chart.
|
||||||
|
# A pin that outlives its chart is close to the failure this upgrade
|
||||||
|
# fixes — software older than the cluster it manages.
|
||||||
|
#
|
||||||
|
# Upgraded from chart 7.7.23 / Argo CD v2.13.8. Three v3 behaviour changes
|
||||||
|
# apply to this deployment, none of which needs a values change today:
|
||||||
|
# - logs RBAC is now enforced, so an account that reads pod logs needs
|
||||||
|
# an explicit `logs, get` policy. jenkins-ci below only syncs.
|
||||||
|
# - update/delete no longer inherit to an application's sub-resources.
|
||||||
|
# - resource tracking moves from labels to annotations, so the first
|
||||||
|
# sync after the upgrade re-stamps every managed resource.
|
||||||
|
|
||||||
|
# SSO still deferred, same as the homelab.
|
||||||
|
dex:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
controller:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 400Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 768Mi
|
||||||
|
|
||||||
|
redis-ha:
|
||||||
|
enabled: false
|
||||||
|
redis:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
# repo-server does the manifest rendering (helm template per Application),
|
||||||
|
# so it is the component that actually saturates when many apps sync at
|
||||||
|
# once. Stateless, safe to run several behind its Service. With
|
||||||
|
# autoscaling on, the chart omits `replicas` from the Deployment, so the
|
||||||
|
# HPA and ArgoCD's own self-management do not fight over the count.
|
||||||
|
#
|
||||||
|
# CPU only. The chart's default also scales on memory, but a Go process
|
||||||
|
# does not hand memory back promptly after a spike, so a memory target
|
||||||
|
# scales up and then never scales down. Setting it to null removes it.
|
||||||
|
repoServer:
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 3
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: null
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 300m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# API/UI. Stateless, sessions live in Redis, so replicas are
|
||||||
|
# interchangeable. Same CPU-only reasoning as repoServer above.
|
||||||
|
server:
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 3
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: null
|
||||||
|
# --insecure is NOT set here as an extra arg: configs.params below
|
||||||
|
# carries server.insecure, which is the supported way to express it and
|
||||||
|
# is what the chart renders into argocd-cmd-params-cm. Setting both
|
||||||
|
# works but leaves two places to disagree.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: contour
|
||||||
|
hostname: "argocd.infra.deployshed.com"
|
||||||
|
# TLS via extraTls rather than the `tls: true` boolean, deliberately.
|
||||||
|
#
|
||||||
|
# The boolean hardcodes `secretName: argocd-server-tls` (see the
|
||||||
|
# chart's argocd-server/ingress.yaml). This deployment already holds a
|
||||||
|
# valid, issued certificate for this exact hostname in
|
||||||
|
# argocd-deployshed-tls, created by the standalone Ingress that served
|
||||||
|
# the real domain while nip.io was still on `hostname`. Flipping the
|
||||||
|
# boolean would ignore that and request a second certificate for the
|
||||||
|
# same name — a needless issuance and a gap while it is obtained.
|
||||||
|
#
|
||||||
|
# extraTls takes an explicit secretName, so the existing certificate is
|
||||||
|
# adopted as-is and the standalone Ingress can simply be deleted.
|
||||||
|
extraTls:
|
||||||
|
- hosts:
|
||||||
|
- argocd.infra.deployshed.com
|
||||||
|
secretName: argocd-deployshed-tls
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
# applicationSet.enabled no longer exists in this chart, and there is no
|
||||||
|
# replacement: unlike dex and notifications below, the ApplicationSet
|
||||||
|
# controller's Deployment has no conditional at all. replicas: 0 is the
|
||||||
|
# only lever — the Deployment exists but runs nothing. Carrying the old
|
||||||
|
# `enabled: false` forward would have quietly started the controller,
|
||||||
|
# since Helm ignores unknown keys.
|
||||||
|
#
|
||||||
|
# Nothing here uses the ApplicationSet CRD; Applications are rendered by
|
||||||
|
# generic-argo-apps-chart instead.
|
||||||
|
applicationSet:
|
||||||
|
replicas: 0
|
||||||
|
notifications:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
configs:
|
||||||
|
# Contour terminates TLS in front of Argo CD; leaving Argo CD's own TLS
|
||||||
|
# on as well produces a redirect loop. This renders into
|
||||||
|
# argocd-cmd-params-cm, which the server actually reads.
|
||||||
|
#
|
||||||
|
# This file previously expressed it as server.extraArgs: [--insecure],
|
||||||
|
# inherited from the homelab. Both work, but only one should exist, and
|
||||||
|
# the rendered ConfigMap is the thing to check when it looks wrong.
|
||||||
|
params:
|
||||||
|
server.insecure: true
|
||||||
|
cm:
|
||||||
|
# https now that the only hostname served carries a real certificate.
|
||||||
|
# This is what ArgoCD builds its own links from, so leaving it http
|
||||||
|
# would hand out plain-HTTP URLs for a TLS-only deployment.
|
||||||
|
url: "https://argocd.infra.deployshed.com"
|
||||||
|
timeout.reconciliation: 3m
|
||||||
|
timeout.reconciliation.jitter: 60s
|
||||||
|
# No Ingress health override, unlike the homelab: there Contour sat
|
||||||
|
# behind hostPort, so nothing ever wrote an Ingress's load balancer
|
||||||
|
# status. On GKE Envoy gets a real LoadBalancer Service and Contour
|
||||||
|
# writes that status, so ArgoCD's built-in check works as intended.
|
||||||
|
#
|
||||||
|
# Scoped account for Jenkins' syncArgoApp step — same as the homelab.
|
||||||
|
accounts.jenkins-ci: apiKey
|
||||||
|
accounts.jenkins-ci.enabled: "true"
|
||||||
|
rbac:
|
||||||
|
policy.csv: |
|
||||||
|
p, jenkins-ci, applications, sync, webapp/*, allow
|
||||||
|
p, jenkins-ci, applications, get, webapp/*, allow
|
||||||
|
# Reached over cluster DNS, never through Contour — which is what lets
|
||||||
|
# Contour itself be ArgoCD-managed. The repos are private on this
|
||||||
|
# public-facing Gitea, so ArgoCD reads them with a repo-creds Secret
|
||||||
|
# (created at bootstrap, covering everything under gitadmin/), not
|
||||||
|
# anonymously as in the homelab.
|
||||||
|
repositories:
|
||||||
|
devops-infra-helm-charts-gcp:
|
||||||
|
url: http://gitea-http.gitea.svc.cluster.local:3000/gitadmin/devops-infra-helm-charts-gcp.git
|
||||||
|
devops-infra-argo-config-gcp:
|
||||||
|
url: http://gitea-http.gitea.svc.cluster.local:3000/gitadmin/devops-infra-argo-config-gcp.git
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# GKE values for the vendored cert-manager chart (helm-templates/cert-manager,
|
||||||
|
# v1.20.1). Written fresh rather than copied from k8s-admin-prd-ase1, whose
|
||||||
|
# file was never adapted from the fleet: it pulls images from a private
|
||||||
|
# Meesho Artifact Registry and pins pods to a "dedicated: devops" node pool
|
||||||
|
# that does not exist here.
|
||||||
|
#
|
||||||
|
# Installed once by hand with `helm install cert-manager` (namespace
|
||||||
|
# "cert-manager"), then adopted by the cert-manager Application in
|
||||||
|
# devops-infra-argo-config-gcp.
|
||||||
|
#
|
||||||
|
# Its job here is Harbor's certificate, issued from the private registry CA
|
||||||
|
# that toolshed-gke-infra's 10-infra creates and the node pool trusts. The
|
||||||
|
# CA key pair reaches the cluster as the "registry-ca" Secret in this
|
||||||
|
# namespace (kubectl, from terraform output); the ClusterIssuer that uses it
|
||||||
|
# lives with Harbor's config, not here.
|
||||||
|
# The vendored chart's own values.yaml was edited in the fleet to pull every
|
||||||
|
# image from Meesho's private Artifact Registry, which these nodes cannot
|
||||||
|
# reach. Back to upstream's registry (quay.io/jetstack/cert-manager-*).
|
||||||
|
imageRegistry: quay.io
|
||||||
|
imageNamespace: jetstack
|
||||||
|
|
||||||
|
crds:
|
||||||
|
enabled: true
|
||||||
|
# A helm uninstall must not take every Certificate in the cluster with it.
|
||||||
|
keep: true
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 96Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
webhook:
|
||||||
|
replicaCount: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 48Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
cainjector:
|
||||||
|
enabled: true
|
||||||
|
replicaCount: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 96Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
startupapicheck:
|
||||||
|
enabled: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
enabled: true
|
||||||
|
servicemonitor:
|
||||||
|
enabled: false
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
contour:
|
||||||
|
# GKE counterpart of helm-overrides/k8s-admin-prd-ase1/contour. Same
|
||||||
|
# official projectcontour chart (0.7.0, see helm-templates/contour), but
|
||||||
|
# exposed the opposite way.
|
||||||
|
#
|
||||||
|
# The homelab binds Envoy to node ports 80/443 with hostPort, because
|
||||||
|
# VMware bridging over Wi-Fi never made a LoadBalancer IP reachable
|
||||||
|
# (claude.md issue #6). None of that applies here: this is a real cloud
|
||||||
|
# load balancer on the reserved address, and it is the ONE inbound path
|
||||||
|
# into the cluster now that the nodes have no public IPs of their own.
|
||||||
|
|
||||||
|
contour:
|
||||||
|
replicaCount: 1
|
||||||
|
# Ingress objects across this cluster say `ingressClassName: contour`,
|
||||||
|
# so the class must be created under exactly that name. The chart's
|
||||||
|
# default is an empty string, which derives a name from the release.
|
||||||
|
ingressClass:
|
||||||
|
name: contour
|
||||||
|
create: true
|
||||||
|
default: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 192Mi
|
||||||
|
|
||||||
|
envoy:
|
||||||
|
# DaemonSet (the chart default): one Envoy per node, which pairs with
|
||||||
|
# externalTrafficPolicy: Local below — every node the load balancer can
|
||||||
|
# send to is running a proxy that can serve the request locally.
|
||||||
|
kind: daemonset
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: LoadBalancer
|
||||||
|
|
||||||
|
# The reserved address from Terraform (module.network's
|
||||||
|
# google_compute_address). Every hostname in this deployment — the
|
||||||
|
# deployshed.com records, including the two wildcards — resolves here,
|
||||||
|
# so this pin is what makes DNS work at all: an unpinned Service takes
|
||||||
|
# a fresh ephemeral IP and every hostname points at nothing.
|
||||||
|
#
|
||||||
|
# More load-bearing now, not less, than when hostnames were
|
||||||
|
# <name>.35.238.248.203.nip.io. Those encoded the address, so a changed
|
||||||
|
# IP produced names that were merely wrong. Real DNS records point here
|
||||||
|
# until somebody edits them in Cloudflare, so a changed IP is an
|
||||||
|
# outage across every hostname at once.
|
||||||
|
#
|
||||||
|
# spec.loadBalancerIP is deprecated upstream (Kubernetes 1.24), and
|
||||||
|
# GKE's replacement is the annotation
|
||||||
|
# networking.gke.io/load-balancer-ip-addresses. That annotation is NOT
|
||||||
|
# a drop-in: it takes the address resource's NAME rather than the
|
||||||
|
# address, and on an external Service it also requires
|
||||||
|
# spec.loadBalancerClass: networking.gke.io/l4-regional-external,
|
||||||
|
# which changes which controller programs the load balancer. GKE still
|
||||||
|
# honours this field, so the deprecated-but-working one is the smaller
|
||||||
|
# change; revisit if a GKE upgrade ever stops honouring it.
|
||||||
|
loadBalancerIP: "35.238.248.203"
|
||||||
|
|
||||||
|
# Chart default, kept deliberately: preserves the real client IP
|
||||||
|
# instead of replacing it with a node's address. Valid here precisely
|
||||||
|
# because Envoy is a DaemonSet.
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 96Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
external-secrets:
|
||||||
|
# Same as the homelab's, which carries nothing cluster-specific: the
|
||||||
|
# controller is configured entirely by the ClusterSecretStore and
|
||||||
|
# ExternalSecret objects in devops-infra-argo-config-gcp, not by values.
|
||||||
|
#
|
||||||
|
# This is the piece every credential in the cluster hangs off — Harbor,
|
||||||
|
# Jenkins, Grafana and the pipeline all read their secrets from Vault
|
||||||
|
# through it, so it comes up before any of them.
|
||||||
|
#
|
||||||
|
# Two things must exist in Vault before the first ExternalSecret can sync,
|
||||||
|
# and neither is declarative: the KV v2 engine at secret/, and the
|
||||||
|
# Kubernetes auth method with a role bound to this controller's service
|
||||||
|
# account. Until then ExternalSecrets stay in a retry loop rather than
|
||||||
|
# failing outright.
|
||||||
|
#
|
||||||
|
# installCRDs defaults to true — kept, as on a fresh cluster there are no
|
||||||
|
# existing SecretStore/ExternalSecret CRs whose schema it could clobber.
|
||||||
|
#
|
||||||
|
# All three components default to unbounded resources; trimmed here for
|
||||||
|
# the same reason as everything else in this repo.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
webhook:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
certController:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
gitea:
|
||||||
|
# GKE counterpart of helm-overrides/k8s-admin-prd-ase1/gitea — same
|
||||||
|
# SQLite/no-cache shape, with what differs on GKE called out inline.
|
||||||
|
#
|
||||||
|
# Installed once by hand with `helm install gitea` (release "gitea",
|
||||||
|
# namespace "gitea"), then adopted by ArgoCD via the nameOverride in
|
||||||
|
# devops-infra-argo-config-gcp's values file. Gitea has to exist before
|
||||||
|
# ArgoCD can read anything, since both config repos live inside it.
|
||||||
|
|
||||||
|
# Recreate for a different reason than the homelab's LevelDB lock: on
|
||||||
|
# three nodes with a ReadWriteOnce persistent disk, the chart's default
|
||||||
|
# RollingUpdate (maxUnavailable: 0) starts the new pod first, and if it
|
||||||
|
# lands on another node it waits forever on Multi-Attach.
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
size: 10Gi
|
||||||
|
# GKE's default class (pd-balanced), in place of the homelab's
|
||||||
|
# local-path. Counts against the project's 250GB SSD quota.
|
||||||
|
storageClass: standard-rwo
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
postgresql-ha:
|
||||||
|
enabled: false
|
||||||
|
valkey:
|
||||||
|
enabled: false
|
||||||
|
valkey-cluster:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
|
limits:
|
||||||
|
memory: 500Mi
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
config:
|
||||||
|
database:
|
||||||
|
DB_TYPE: sqlite3
|
||||||
|
actions:
|
||||||
|
ENABLED: true
|
||||||
|
server:
|
||||||
|
ROOT_URL: https://gitea.infra.deployshed.com/
|
||||||
|
service:
|
||||||
|
# The homelab sat on a LAN; this Gitea is on a public IP. Open
|
||||||
|
# registration would let anyone on the internet create an account.
|
||||||
|
DISABLE_REGISTRATION: true
|
||||||
|
security:
|
||||||
|
# The homelab allowed "*" because every host was on a private LAN.
|
||||||
|
# Here "*" would also allow webhooks to the node metadata server, so
|
||||||
|
# this stays narrowed to private ranges — which covers every
|
||||||
|
# in-cluster Service (Jenkins included) reached over cluster DNS.
|
||||||
|
#
|
||||||
|
# The one public entry is toolshed's own dashboard host, and it is a
|
||||||
|
# STOPGAP. toolshed builds each app's webhook target from the
|
||||||
|
# hostname the dashboard was browsed on (internal/api/apps.go's
|
||||||
|
# queueRepo), with no override, so an app registered through the
|
||||||
|
# public URL gets a public webhook target and Gitea refuses to call
|
||||||
|
# it: "webhook can only call allowed HTTP servers".
|
||||||
|
#
|
||||||
|
# The cost is real but bounded: this permits exactly one hostname,
|
||||||
|
# which happens to be our own load balancer, so the callback
|
||||||
|
# hairpins out and back in rather than staying pod-to-pod. It does
|
||||||
|
# not re-expose the metadata server, which is why "*" was rejected.
|
||||||
|
#
|
||||||
|
# The proper fix is a configurable webhook base URL in toolshed
|
||||||
|
# pointing at toolshed-api.toolshed.svc.cluster.local:8080, after
|
||||||
|
# which this entry should be removed.
|
||||||
|
ALLOWED_HOST_LIST: private,console.deployshed.com
|
||||||
|
admin:
|
||||||
|
username: gitadmin
|
||||||
|
# Created by hand with kubectl at bootstrap, because Vault and ESO
|
||||||
|
# are not running yet. Same Secret name as the homelab so the
|
||||||
|
# ExternalSecret (secretstores/gitea-admin-credentials.yaml) can take
|
||||||
|
# it over unchanged once Vault is up.
|
||||||
|
existingSecret: gitea-admin-credentials
|
||||||
|
email: "admin@local.lab"
|
||||||
|
|
||||||
|
# Contour does not exist yet at bootstrap — the Ingress just sits unused
|
||||||
|
# until ArgoCD installs it.
|
||||||
|
#
|
||||||
|
# One host. The nip.io name was served alongside this one while the
|
||||||
|
# deployment moved onto its own domain, and came out once everything
|
||||||
|
# referencing it had been repointed: ROOT_URL above, the webhook allow-list
|
||||||
|
# above that, and any git remote anyone had configured.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: contour
|
||||||
|
annotations:
|
||||||
|
# Issues the certificate named in tls below. This could only ever cover
|
||||||
|
# the real domain: Let's Encrypt cannot issue for nip.io, so while both
|
||||||
|
# names were served, asking for one certificate spanning them returned
|
||||||
|
# nothing for either.
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- host: gitea.infra.deployshed.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: gitea-tls
|
||||||
|
hosts:
|
||||||
|
- gitea.infra.deployshed.com
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
grafana:
|
||||||
|
# From Vault via ExternalSecret (devops-infra-argo-config/secretstores/
|
||||||
|
# grafana-admin-credentials.yaml), same pattern as gitea/harbor/jenkins
|
||||||
|
# admin credentials elsewhere in this project — never a plaintext
|
||||||
|
# adminPassword in this file.
|
||||||
|
admin:
|
||||||
|
existingSecret: grafana-admin-credentials
|
||||||
|
userKey: username
|
||||||
|
passwordKey: password
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
# 1Gi, not the chart's 10Gi default: this holds dashboards, folders and
|
||||||
|
# Grafana's own sqlite state, not metric data — VictoriaMetrics keeps
|
||||||
|
# that. Unlike the homelab's local-path, standard-rwo can be expanded
|
||||||
|
# later if that ever proves tight.
|
||||||
|
enabled: true
|
||||||
|
storageClassName: standard-rwo
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 384Mi
|
||||||
|
|
||||||
|
# Provisioned at boot, not clicked through in the UI — the same reason
|
||||||
|
# every other credential/config in this project is committed rather
|
||||||
|
# than set by hand: it survives a pod restart and a fresh install gets
|
||||||
|
# it automatically. VictoriaMetrics speaks Prometheus's own query API,
|
||||||
|
# so `type: prometheus` here is correct even though the URL is VM's —
|
||||||
|
# see this repo's victoria-metrics-single chart for why.
|
||||||
|
datasources:
|
||||||
|
datasources.yaml:
|
||||||
|
apiVersion: 1
|
||||||
|
datasources:
|
||||||
|
- name: VictoriaMetrics
|
||||||
|
# Fixed uid, not left to auto-generate — the provisioned
|
||||||
|
# dashboard below references this datasource by uid, and an
|
||||||
|
# auto-generated one would only exist after Grafana's first
|
||||||
|
# boot, too late for a dashboard provisioned in the same boot.
|
||||||
|
uid: victoriametrics
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428
|
||||||
|
isDefault: true
|
||||||
|
|
||||||
|
# Dashboard provisioning. Provisioned rather than built by hand in the
|
||||||
|
# UI for the same reason the datasource above is: it survives a pod
|
||||||
|
# restart (this deployment has no persistent Grafana database beyond
|
||||||
|
# the 1Gi PVC, and even with one, a fresh install should not start
|
||||||
|
# with an empty dashboard list) and a `git diff` shows what changed.
|
||||||
|
dashboardProviders:
|
||||||
|
dashboardproviders.yaml:
|
||||||
|
apiVersion: 1
|
||||||
|
providers:
|
||||||
|
- name: default
|
||||||
|
orgId: 1
|
||||||
|
folder: ""
|
||||||
|
type: file
|
||||||
|
disableDeletion: false
|
||||||
|
editable: true
|
||||||
|
options:
|
||||||
|
path: /var/lib/grafana/dashboards/default
|
||||||
|
|
||||||
|
# "Homelab Overview" — total Envoy/Contour RPS, per-namespace CPU and
|
||||||
|
# memory (the $namespace template variable filters every relevant
|
||||||
|
# panel), cluster-wide utilization against actual node capacity, and a
|
||||||
|
# total-resources row (cores/memory/pods/disk). Envoy and node-exporter
|
||||||
|
# metrics both required their own vmagent scrape job — see
|
||||||
|
# helm-overrides/.../vmagent/custom-values.yaml for why neither was
|
||||||
|
# reachable through the chart's own defaults in this cluster.
|
||||||
|
#
|
||||||
|
# Every panel except "Disk free" was run against the live deployment
|
||||||
|
# (vmui, over Tailscale) before being written in here — RPS, per-
|
||||||
|
# namespace CPU/memory, machine_cpu_cores/machine_memory_bytes all
|
||||||
|
# returned real data. "Disk free" depends on the node-exporter scrape
|
||||||
|
# job added alongside this same change, which had not been live yet to
|
||||||
|
# verify against — worth checking once this actually deploys, same as
|
||||||
|
# everything else in this repo that gets a `helm template` check but
|
||||||
|
# cannot get a live one before the first sync.
|
||||||
|
dashboards:
|
||||||
|
default:
|
||||||
|
homelab:
|
||||||
|
json: |
|
||||||
|
{
|
||||||
|
"title": "Homelab Overview",
|
||||||
|
"uid": "homelab-overview",
|
||||||
|
"schemaVersion": 39,
|
||||||
|
"editable": true,
|
||||||
|
"timezone": "browser",
|
||||||
|
"time": { "from": "now-1h", "to": "now" },
|
||||||
|
"refresh": "30s",
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "namespace",
|
||||||
|
"type": "query",
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"query": "label_values(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}, namespace)",
|
||||||
|
"refresh": 2,
|
||||||
|
"multi": true,
|
||||||
|
"includeAll": true,
|
||||||
|
"current": { "selected": true, "text": "All", "value": "$__all" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"panels": [
|
||||||
|
{ "type": "row", "title": "Ingress (Envoy / Contour)", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 100 },
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Total RPS", "id": 1,
|
||||||
|
"gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "sum(rate(envoy_http_downstream_rq_total{namespace=\"projectcontour\"}[5m]))", "legendFormat": "rps" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "reqps", "decimals": 2 }, "overrides": [] },
|
||||||
|
"options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "graphMode": "area" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Active downstream connections", "id": 2,
|
||||||
|
"gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "sum(envoy_http_downstream_cx_active{namespace=\"projectcontour\"})", "legendFormat": "connections" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "short" }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries", "title": "Requests by response class", "id": 3,
|
||||||
|
"gridPos": { "h": 6, "w": 12, "x": 12, "y": 1 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{
|
||||||
|
"expr": "sum by (envoy_response_code_class) (rate(envoy_http_downstream_rq_xx{namespace=\"projectcontour\"}[5m]))",
|
||||||
|
"legendFormat": "{{envoy_response_code_class}}xx"
|
||||||
|
}],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "reqps" }, "overrides": [] },
|
||||||
|
"options": { "legend": { "displayMode": "list", "placement": "bottom" } }
|
||||||
|
},
|
||||||
|
|
||||||
|
{ "type": "row", "title": "Service level (by namespace)", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 7 }, "id": 101 },
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "timeseries", "title": "CPU usage by namespace", "id": 10,
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{
|
||||||
|
"expr": "sum by (namespace) (rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"}[5m]))",
|
||||||
|
"legendFormat": "{{namespace}}"
|
||||||
|
}],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "short", "custom": { "fillOpacity": 10, "stacking": { "mode": "normal" } } }, "overrides": [] },
|
||||||
|
"options": { "legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max"] } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries", "title": "Memory usage by namespace", "id": 11,
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{
|
||||||
|
"expr": "sum by (namespace) (container_memory_working_set_bytes{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"})",
|
||||||
|
"legendFormat": "{{namespace}}"
|
||||||
|
}],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "bytes", "custom": { "fillOpacity": 10, "stacking": { "mode": "normal" } } }, "overrides": [] },
|
||||||
|
"options": { "legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max"] } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table", "title": "Current usage per namespace", "id": 12,
|
||||||
|
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 16 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [
|
||||||
|
{ "expr": "sum by (namespace) (rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"}[5m]))", "format": "table", "instant": true, "refId": "A" },
|
||||||
|
{ "expr": "sum by (namespace) (container_memory_working_set_bytes{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"})", "format": "table", "instant": true, "refId": "B" },
|
||||||
|
{ "expr": "count by (namespace) (count by (namespace, pod) (container_memory_working_set_bytes{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"}))", "format": "table", "instant": true, "refId": "C" }
|
||||||
|
],
|
||||||
|
"transformations": [
|
||||||
|
{ "id": "merge", "options": {} },
|
||||||
|
{ "id": "organize", "options": {
|
||||||
|
"excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time 3": true },
|
||||||
|
"renameByName": { "Value #A": "CPU (cores)", "Value #B": "Memory", "Value #C": "Pods" }
|
||||||
|
} }
|
||||||
|
],
|
||||||
|
"fieldConfig": { "defaults": {}, "overrides": [
|
||||||
|
{ "matcher": { "id": "byName", "options": "Memory" }, "properties": [{ "id": "unit", "value": "bytes" }] },
|
||||||
|
{ "matcher": { "id": "byName", "options": "CPU (cores)" }, "properties": [{ "id": "unit", "value": "short" }, { "id": "decimals", "value": 3 }] }
|
||||||
|
] }
|
||||||
|
},
|
||||||
|
|
||||||
|
{ "type": "row", "title": "Cluster utilization", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 24 }, "id": 102 },
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "gauge", "title": "CPU utilization", "id": 20,
|
||||||
|
"gridPos": { "h": 7, "w": 6, "x": 0, "y": 25 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "100 * sum(rate(container_cpu_usage_seconds_total{container!=\"\", container!=\"POD\"}[5m])) / sum(machine_cpu_cores)" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "percent", "min": 0, "max": 100,
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [
|
||||||
|
{ "color": "green", "value": null }, { "color": "yellow", "value": 70 }, { "color": "red", "value": 90 }
|
||||||
|
] } }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "gauge", "title": "Memory utilization", "id": 21,
|
||||||
|
"gridPos": { "h": 7, "w": 6, "x": 6, "y": 25 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "100 * sum(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}) / sum(machine_memory_bytes)" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "percent", "min": 0, "max": 100,
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [
|
||||||
|
{ "color": "green", "value": null }, { "color": "yellow", "value": 70 }, { "color": "red", "value": 90 }
|
||||||
|
] } }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "timeseries", "title": "Cluster CPU utilization over time", "id": 22,
|
||||||
|
"gridPos": { "h": 7, "w": 12, "x": 12, "y": 25 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [
|
||||||
|
{ "expr": "100 * sum(rate(container_cpu_usage_seconds_total{container!=\"\", container!=\"POD\"}[5m])) / sum(machine_cpu_cores)", "legendFormat": "CPU %" },
|
||||||
|
{ "expr": "100 * sum(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}) / sum(machine_memory_bytes)", "legendFormat": "Memory %" }
|
||||||
|
],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "percent", "min": 0 }, "overrides": [] }
|
||||||
|
},
|
||||||
|
|
||||||
|
{ "type": "row", "title": "Total resources", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 32 }, "id": 103 },
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Node CPU capacity", "id": 30,
|
||||||
|
"gridPos": { "h": 5, "w": 4, "x": 0, "y": 33 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "max(machine_cpu_cores)" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "short", "displayName": "cores" }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Node memory capacity", "id": 31,
|
||||||
|
"gridPos": { "h": 5, "w": 4, "x": 4, "y": 33 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "max(machine_memory_bytes)" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "bytes" }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "CPU used (cluster)", "id": 32,
|
||||||
|
"gridPos": { "h": 5, "w": 4, "x": 8, "y": 33 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"\", container!=\"POD\"}[5m]))" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "short", "displayName": "cores", "decimals": 2 }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Memory used (cluster)", "id": 33,
|
||||||
|
"gridPos": { "h": 5, "w": 4, "x": 12, "y": 33 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "sum(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"})" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "bytes" }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Running pods", "id": 34,
|
||||||
|
"gridPos": { "h": 5, "w": 4, "x": 16, "y": 33 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "count(count by (namespace, pod) (container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}))" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "short" }, "overrides": [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stat", "title": "Disk free (root)", "id": 35,
|
||||||
|
"gridPos": { "h": 5, "w": 4, "x": 20, "y": 33 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
|
||||||
|
"targets": [{ "expr": "node_filesystem_avail_bytes{mountpoint=\"/\"}" }],
|
||||||
|
"fieldConfig": { "defaults": { "unit": "bytes",
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [
|
||||||
|
{ "color": "red", "value": null }, { "color": "yellow", "value": 5000000000 }, { "color": "green", "value": 15000000000 }
|
||||||
|
] } }, "overrides": [] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: contour
|
||||||
|
annotations:
|
||||||
|
# The real domain is now the only host, so this covers everything
|
||||||
|
# served. While nip.io was alongside it, only the real domain could
|
||||||
|
# appear in tls below — Let's Encrypt cannot issue for nip.io, and one
|
||||||
|
# certificate spanning both would have failed outright rather than
|
||||||
|
# covering the half it could serve.
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
path: /
|
||||||
|
hosts:
|
||||||
|
- grafana.infra.deployshed.com
|
||||||
|
tls:
|
||||||
|
- secretName: grafana-tls
|
||||||
|
hosts:
|
||||||
|
- grafana.infra.deployshed.com
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
harbor:
|
||||||
|
# GKE counterpart of helm-overrides/k8s-admin-prd-ase1/harbor, same chart
|
||||||
|
# (1.19.1), with one fundamental difference: this Harbor is served over
|
||||||
|
# real TLS, and it has to be.
|
||||||
|
#
|
||||||
|
# The homelab runs Harbor on plain HTTP and works around containerd's
|
||||||
|
# refusal to pull from an insecure registry by hand-editing
|
||||||
|
# /etc/containerd/certs.d/<host>/hosts.toml on the node. GKE nodes are
|
||||||
|
# managed and replaced, so that edit cannot survive.
|
||||||
|
#
|
||||||
|
# That used to mean a private CA: the registry was a nip.io name, Let's
|
||||||
|
# Encrypt cannot issue for one (not on the public suffix list, and every
|
||||||
|
# *.nip.io certificate shares a single rate limit), so Terraform generated
|
||||||
|
# a CA, the node pool was told at creation to trust it for exactly that
|
||||||
|
# hostname, and cert-manager signed Harbor from it. It worked for pulls,
|
||||||
|
# which is what mattered, but every browser warned on the Harbor UI and
|
||||||
|
# every docker client that was not a node needed the CA mounted by hand.
|
||||||
|
#
|
||||||
|
# Owning a domain removes all of it. harbor.infra.deployshed.com takes an
|
||||||
|
# ordinary Let's Encrypt certificate that everything already trusts — the
|
||||||
|
# nodes, dockerd in a build pod, a laptop, a browser. What retires with it:
|
||||||
|
# registry-ca-clusterissuer.yaml, registry-ca-configmap.yaml, the CA mount
|
||||||
|
# in every dind pod, and eventually the node pool's own
|
||||||
|
# private_registry_access_config block in Terraform.
|
||||||
|
#
|
||||||
|
# The nip.io name is still served, by a standalone Ingress alongside this
|
||||||
|
# one, and still signed by the private CA. It has to be: apps deployed
|
||||||
|
# before the move recorded their image as harbor.35.238.248.203.nip.io/...
|
||||||
|
# in toolshed's database, and that reference only changes when each app is
|
||||||
|
# rebuilt. Retiring the old name before then breaks their next image pull.
|
||||||
|
expose:
|
||||||
|
type: ingress
|
||||||
|
tls:
|
||||||
|
enabled: true
|
||||||
|
# secret, not the chart's "auto": auto generates its own self-signed
|
||||||
|
# certificate, which nothing has any reason to trust.
|
||||||
|
certSource: secret
|
||||||
|
secret:
|
||||||
|
secretName: harbor-deployshed-tls
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
core: "harbor.infra.deployshed.com"
|
||||||
|
className: contour
|
||||||
|
annotations:
|
||||||
|
# cert-manager's ingress-shim watches for this and creates the
|
||||||
|
# Certificate itself, writing the result into the secret named
|
||||||
|
# above. Nothing here ever touches a Certificate resource directly.
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
|
||||||
|
# The update strategy for the two deployments with persistent volumes,
|
||||||
|
# jobservice and registry. Recreate, not the chart's default RollingUpdate,
|
||||||
|
# because their volumes are standard-rwo — ReadWriteOnce — and a rolling
|
||||||
|
# update starts the replacement pod before the old one releases the disk.
|
||||||
|
# The new pod then waits on "Multi-Attach error for volume ... already used
|
||||||
|
# by pod" forever, and the rollout never converges: this cluster sat in
|
||||||
|
# exactly that state, old pods serving while new ones hung in
|
||||||
|
# ContainerCreating. The chart's own comment on this value says to set it
|
||||||
|
# this way when RWM volumes are unavailable.
|
||||||
|
#
|
||||||
|
# The cost is honest: Harbor is briefly down during an upgrade, because the
|
||||||
|
# old pod must stop before the new one starts. That beats an update that
|
||||||
|
# cannot complete at all.
|
||||||
|
updateStrategy:
|
||||||
|
type: Recreate
|
||||||
|
|
||||||
|
# https, matching the ingress above. Harbor hands this URL to docker
|
||||||
|
# clients in its own API responses, so a mismatch here breaks pushes in
|
||||||
|
# ways that look like registry errors rather than configuration — and it is
|
||||||
|
# what the "docker login / docker push" commands shown in Harbor's own UI
|
||||||
|
# are built from, which is where a stale value is noticed first.
|
||||||
|
externalURL: "https://harbor.infra.deployshed.com"
|
||||||
|
|
||||||
|
# From Vault through External Secrets — see
|
||||||
|
# secretstores/harbor-admin-credentials.yaml and Vault path
|
||||||
|
# secret/harbor/admin.
|
||||||
|
existingSecretAdminPassword: harbor-admin-credentials
|
||||||
|
existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD
|
||||||
|
|
||||||
|
# The one genuinely optional component. Harbor's database and redis are
|
||||||
|
# its own required internal state, not add-ons.
|
||||||
|
trivy:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
# Keeps the PVCs if the release is ever uninstalled: these hold the
|
||||||
|
# actual images.
|
||||||
|
resourcePolicy: "keep"
|
||||||
|
persistentVolumeClaim:
|
||||||
|
registry:
|
||||||
|
storageClass: standard-rwo
|
||||||
|
size: 5Gi
|
||||||
|
jobservice:
|
||||||
|
jobLog:
|
||||||
|
storageClass: standard-rwo
|
||||||
|
size: 1Gi
|
||||||
|
database:
|
||||||
|
storageClass: standard-rwo
|
||||||
|
size: 1Gi
|
||||||
|
redis:
|
||||||
|
storageClass: standard-rwo
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
portal:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
core:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
jobservice:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
registry:
|
||||||
|
registry:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
controller:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
database:
|
||||||
|
internal:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
redis:
|
||||||
|
internal:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
jenkins:
|
||||||
|
# GKE counterpart of helm-overrides/k8s-admin-prd-ase1/jenkins, same chart
|
||||||
|
# (5.8.58). Dynamic Kubernetes build agents, so idle cost is the
|
||||||
|
# controller alone.
|
||||||
|
#
|
||||||
|
# Every plugin pin below is carried over deliberately, not copied
|
||||||
|
# blindly — each one fixes a failure that is not obvious from its symptom.
|
||||||
|
# See the homelab file for the full history.
|
||||||
|
|
||||||
|
controller:
|
||||||
|
image:
|
||||||
|
# The chart's own default plugin list requires core >= 2.504.3, while
|
||||||
|
# its default image tag is 2.504.2. An upstream inconsistency in the
|
||||||
|
# chart, not our configuration: bumping core is the fix, since the
|
||||||
|
# plugins involved (kubernetes above all) are what dynamic agents
|
||||||
|
# depend on.
|
||||||
|
tag: "2.504.3-jdk21"
|
||||||
|
|
||||||
|
# Helm replaces lists wholesale rather than merging, so this is the
|
||||||
|
# chart's full default list with one version corrected, plus two
|
||||||
|
# additions — not a hand-picked subset.
|
||||||
|
installPlugins:
|
||||||
|
# Pinned as a pair. kubernetes needs kubernetes-client-api >=
|
||||||
|
# 7.3.1-256.v788a_0b_787114; left unpinned it resolves to an older
|
||||||
|
# version at image-build time and every agent launch dies with
|
||||||
|
# NoSuchMethodError while constructing the client. The pods start
|
||||||
|
# fine, so it presents as builds hanging forever at "Still waiting to
|
||||||
|
# schedule task" rather than as a plugin problem.
|
||||||
|
- kubernetes:4437.v3a_18554d3f32
|
||||||
|
- kubernetes-client-api:7.3.1-256.v788a_0b_787114
|
||||||
|
- workflow-aggregator:608.v67378e9d3db_1
|
||||||
|
- git:5.7.0
|
||||||
|
# kubernetes/git/credentials need this version, though the chart's
|
||||||
|
# own default list pins an older one. Same class of upstream
|
||||||
|
# inconsistency as the image tag.
|
||||||
|
- configuration-as-code:2006.v001a_2ca_6b_574
|
||||||
|
# Not in the chart's default list at all — provides readYaml, which
|
||||||
|
# the shared library's loadConfig stage uses to parse each repo's
|
||||||
|
# config.yaml.
|
||||||
|
- pipeline-utility-steps:3.810.va_7672d206740
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
admin:
|
||||||
|
# From Vault through External Secrets, never a plaintext password
|
||||||
|
# here. Requires secretstores/jenkins-admin-credentials.yaml to have
|
||||||
|
# synced, which in turn requires the Vault path secret/jenkins/admin.
|
||||||
|
existingSecret: jenkins-admin-credentials
|
||||||
|
userKey: jenkins-admin-user
|
||||||
|
passwordKey: jenkins-admin-password
|
||||||
|
|
||||||
|
# One hostname, on the primary ingress, with its certificate.
|
||||||
|
#
|
||||||
|
# This chart's primary ingress supports exactly one hostName — no
|
||||||
|
# extraHosts like argo-cd — so while nip.io was also served, the real
|
||||||
|
# domain lived in a whole second Ingress object (secondaryingress). That
|
||||||
|
# was the only way to keep the certificate clean, since a certificate
|
||||||
|
# covering both names is impossible: Let's Encrypt cannot issue for
|
||||||
|
# nip.io. With nip.io gone there is one name, so the second object is
|
||||||
|
# gone with it and the certificate moves onto the primary.
|
||||||
|
#
|
||||||
|
# controller.ingress.tls is a LIST here, not a boolean, taking an
|
||||||
|
# explicit secretName — so jenkins-tls, already issued for this exact
|
||||||
|
# hostname by the secondary ingress, is adopted rather than reissued.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
hostName: "jenkins.infra.deployshed.com"
|
||||||
|
ingressClassName: contour
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
tls:
|
||||||
|
- secretName: jenkins-tls
|
||||||
|
hosts:
|
||||||
|
- jenkins.infra.deployshed.com
|
||||||
|
|
||||||
|
agent:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: standard-rwo
|
||||||
|
size: 5Gi
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
prometheus-node-exporter:
|
||||||
|
# Unchanged from the homelab's — nothing here is cluster-specific. One
|
||||||
|
# DaemonSet pod per node on hostNetwork; three pods here rather than one.
|
||||||
|
#
|
||||||
|
# Host-level metrics are independent of which TSDB stores them, which is
|
||||||
|
# why this is its own release rather than a subchart of anything.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
# The chart's Service carries prometheus.io/scrape by default. vmagent
|
||||||
|
# also targets these pods directly by container port, because that
|
||||||
|
# annotation-based path found nothing in the homelab — see the vmagent
|
||||||
|
# values for the detail.
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# PostgreSQL for toolshed's control plane, on GKE.
|
||||||
|
#
|
||||||
|
# Its own namespace rather than toolshed's, so it is addressed over cluster
|
||||||
|
# DNS like any other platform component and outlives its first consumer:
|
||||||
|
#
|
||||||
|
# postgresql.postgres.svc.cluster.local:5432
|
||||||
|
#
|
||||||
|
# Hand-written chart, not Bitnami's: that registry has been unstable, and
|
||||||
|
# PostgreSQL ships no official chart.
|
||||||
|
#
|
||||||
|
# Credentials come from Vault through External Secrets — see
|
||||||
|
# secretstores/toolshed-postgres-credentials.yaml. The Secret must exist
|
||||||
|
# before this pod starts; without it the pod sits in
|
||||||
|
# CreateContainerConfigError, which does not explain itself.
|
||||||
|
|
||||||
|
fullnameOverride: postgresql
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
tag: "16-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
existingSecret: postgresql-credentials
|
||||||
|
database: toolshed
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: standard-rwo
|
||||||
|
size: 5Gi
|
||||||
|
|
||||||
|
config:
|
||||||
|
# Kept at the homelab's deliberately small values even though this
|
||||||
|
# cluster has room to spare: for a handful of control-plane tables it
|
||||||
|
# makes no measurable difference, and matching the homelab keeps one
|
||||||
|
# fewer variable between the two deployments. Raise it if a real query
|
||||||
|
# workload ever shows up here.
|
||||||
|
sharedBuffers: 32MB
|
||||||
|
maxConnections: "50"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# Redis backing toolshed's managed cache add-on, on GKE.
|
||||||
|
#
|
||||||
|
# Its own namespace, same reasoning as postgresql:
|
||||||
|
#
|
||||||
|
# redis.redis.svc.cluster.local:6379
|
||||||
|
#
|
||||||
|
# Hand-written chart, not Bitnami's, for the same reason as postgresql.
|
||||||
|
#
|
||||||
|
# Read the chart's own values.yaml before changing anything about
|
||||||
|
# authentication. The absence of requirepass is deliberate and
|
||||||
|
# security-relevant, not an oversight: access is defined by an ACL file
|
||||||
|
# seeded from Vault through External Secrets
|
||||||
|
# (secretstores/toolshed-redis-credentials.yaml). The Secret must exist
|
||||||
|
# before this pod starts, or the init container cannot seed that file.
|
||||||
|
|
||||||
|
fullnameOverride: redis
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: redis
|
||||||
|
tag: "7-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
existingSecret: redis-credentials
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: standard-rwo
|
||||||
|
# Holds the ACL file and nothing else worth keeping, since snapshotting
|
||||||
|
# is off. 1Gi is already far more than needed.
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
config:
|
||||||
|
# Kept at the homelab's value. It was chosen there to fit an 8GB node
|
||||||
|
# under pressure, and while this cluster has room, a bigger cache buys
|
||||||
|
# nothing for a handful of small internal tools.
|
||||||
|
maxmemory: 48mb
|
||||||
|
maxmemoryPolicy: allkeys-lru
|
||||||
|
save: ""
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 96Mi
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
vault:
|
||||||
|
# GKE counterpart of helm-overrides/k8s-admin-prd-ase1/vault, same chart
|
||||||
|
# (0.34.1) and same shape — production mode, file storage, standalone, no
|
||||||
|
# HA — with one substantial difference: this Vault unseals itself from
|
||||||
|
# Cloud KMS instead of by hand.
|
||||||
|
#
|
||||||
|
# The homelab unseals with 3 of 5 Shamir keys after every restart. That
|
||||||
|
# was fine on an always-on VM. Here the nodes are spot and can be
|
||||||
|
# reclaimed at any hour, and a sealed Vault means every secret in the
|
||||||
|
# cluster is unavailable until a human notices. The trade, stated plainly:
|
||||||
|
# unsealing now depends on GCP IAM rather than on people holding key
|
||||||
|
# shares.
|
||||||
|
#
|
||||||
|
# This is a fresh install, not an adoption. Init is still a one-off manual
|
||||||
|
# step (`vault operator init`), and with a KMS seal it returns RECOVERY
|
||||||
|
# keys plus a root token — recovery keys cannot unseal a running Vault,
|
||||||
|
# they exist to recover or rekey it. Keep them and the root token in a
|
||||||
|
# password manager; they belong in neither Git nor Vault itself.
|
||||||
|
|
||||||
|
injector:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
server:
|
||||||
|
# The Workload Identity binding Terraform created names exactly
|
||||||
|
# vault/vault — this namespace and this service account name. The
|
||||||
|
# annotation is the other half of that pair. Miss either and Vault
|
||||||
|
# starts, fails to reach KMS, and stays sealed with a permission error
|
||||||
|
# that does not mention Workload Identity at all.
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
name: vault
|
||||||
|
annotations:
|
||||||
|
iam.gke.io/gcp-service-account: toolshed-vault@toolshed-testing-508208.iam.gserviceaccount.com
|
||||||
|
|
||||||
|
dataStorage:
|
||||||
|
enabled: true
|
||||||
|
# 10Gi rather than the homelab's 5Gi: that number exists only because
|
||||||
|
# local-path cannot expand a bound volume. standard-rwo can expand, so
|
||||||
|
# this is the chart default, not a constraint.
|
||||||
|
size: 10Gi
|
||||||
|
storageClass: standard-rwo
|
||||||
|
|
||||||
|
ha:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
standalone:
|
||||||
|
enabled: true
|
||||||
|
# `ui = true` here AND ui.enabled below are both required — the chart
|
||||||
|
# has two separate toggles for the same thing, and setting only one
|
||||||
|
# leaves the UI 404ing (claude.md issue #10).
|
||||||
|
#
|
||||||
|
# The seal stanza's values come from terraform output vault_seal, so
|
||||||
|
# Terraform and this file cannot disagree about which key Vault
|
||||||
|
# unseals with. No credentials appear here: the pod authenticates to
|
||||||
|
# KMS as its Workload Identity, so there is no key file to mount,
|
||||||
|
# rotate, or leak.
|
||||||
|
config: |
|
||||||
|
ui = true
|
||||||
|
listener "tcp" {
|
||||||
|
address = "[::]:8200"
|
||||||
|
cluster_address = "[::]:8201"
|
||||||
|
tls_disable = "true" # lab only - enable TLS for anything beyond local testing
|
||||||
|
}
|
||||||
|
storage "file" {
|
||||||
|
path = "/vault/data"
|
||||||
|
}
|
||||||
|
seal "gcpckms" {
|
||||||
|
project = "toolshed-testing-508208"
|
||||||
|
region = "us-central1"
|
||||||
|
key_ring = "toolshed-vault"
|
||||||
|
crypto_key = "unseal"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Single host — no Tailscale here. Plain HTTP through Contour, matching
|
||||||
|
# tls_disable above.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: contour
|
||||||
|
annotations:
|
||||||
|
# Certificate for the real domain, which is now the only one served.
|
||||||
|
# nip.io could never have had one.
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- host: "vault.infra.deployshed.com"
|
||||||
|
paths: []
|
||||||
|
tls:
|
||||||
|
- secretName: vault-tls
|
||||||
|
hosts:
|
||||||
|
- vault.infra.deployshed.com
|
||||||
|
|
||||||
|
ui:
|
||||||
|
enabled: true
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
victoria-metrics-single:
|
||||||
|
server:
|
||||||
|
# 3 days rather than the chart's month: this cluster exists to prove a
|
||||||
|
# pipeline, and every extra day is disk against the project's 250GB SSD
|
||||||
|
# quota, which every standard-rwo volume in the cluster shares. Three
|
||||||
|
# days still spans a weekend, which is the window that matters for
|
||||||
|
# working out what happened to something overnight.
|
||||||
|
#
|
||||||
|
# Down from 7d. Note what this does and does not do: it reclaims disk as
|
||||||
|
# old partitions are dropped, and shrinks the index a little, but it
|
||||||
|
# does NOT reduce the memory this needs to run. That tracks active time
|
||||||
|
# series and cache size, neither of which depends on how long data is
|
||||||
|
# kept — which is why the limit above had to be raised rather than this
|
||||||
|
# lowered when it started OOM-killing on restart. The lever for memory
|
||||||
|
# is scrape cardinality: several targets here carry more than forty
|
||||||
|
# labels per series (see the maxLabelsPerTimeseries warnings in its
|
||||||
|
# log), and dropping labels there would cut series count directly.
|
||||||
|
retentionPeriod: "3d"
|
||||||
|
|
||||||
|
persistentVolume:
|
||||||
|
storageClassName: standard-rwo
|
||||||
|
# VictoriaMetrics' compression is why it replaced Prometheus here;
|
||||||
|
# this cluster's metric volume at 7 days fits well inside 3Gi. Unlike
|
||||||
|
# the homelab's local-path, this class can be expanded later.
|
||||||
|
size: 3Gi
|
||||||
|
|
||||||
|
# Raised from 128Mi/512Mi, which this no longer fits inside.
|
||||||
|
#
|
||||||
|
# The pod ran for weeks at the old limit and then OOM-killed in a loop
|
||||||
|
# the first time it was restarted — exit 137 roughly fifty seconds after
|
||||||
|
# a clean start, every time. Nothing had changed about its configuration;
|
||||||
|
# the dataset had simply grown into 3.14 billion rows, and the memory a
|
||||||
|
# restart needs to resume ingestion no longer fit. A long-lived pod can
|
||||||
|
# sit well past the limit it would need to start again, so the failure
|
||||||
|
# only appears the next time something restarts it.
|
||||||
|
#
|
||||||
|
# Memory here tracks active time series rather than disk, which is why
|
||||||
|
# shortening retentionPeriod above would not have helped: the scrape
|
||||||
|
# targets are the same either way, and several of them carry 40+ labels
|
||||||
|
# (see the maxLabelsPerTimeseries warnings in its log).
|
||||||
|
#
|
||||||
|
# Affordable: memory requests across the three nodes sit at 62%, 18% and
|
||||||
|
# 47%, so there is room. CPU is the constrained resource on this cluster,
|
||||||
|
# and this costs none.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
# vmui, VictoriaMetrics' built-in query UI, on the same pod and port —
|
||||||
|
# ad-hoc PromQL only, no saved dashboards; Grafana is the real UI. Free
|
||||||
|
# to expose, since it is not a separate component.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: contour
|
||||||
|
annotations:
|
||||||
|
# Certificate for the real domain, now the only one served. nip.io
|
||||||
|
# could never have had one.
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- name: vm.infra.deployshed.com
|
||||||
|
path: ["/"]
|
||||||
|
port: http
|
||||||
|
tls:
|
||||||
|
- secretName: vm-tls
|
||||||
|
hosts:
|
||||||
|
- vm.infra.deployshed.com
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
victoria-metrics-agent:
|
||||||
|
# Unchanged from the homelab's, deliberately: everything here is
|
||||||
|
# addressed by cluster-internal Service DNS and namespace, none of which
|
||||||
|
# differs on GKE.
|
||||||
|
#
|
||||||
|
# The write path is what wires the two components together; the chart
|
||||||
|
# names do not imply it on their own.
|
||||||
|
remoteWrite:
|
||||||
|
- url: http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428/api/v1/write
|
||||||
|
|
||||||
|
# config.scrape_configs stays at the chart's default, which already
|
||||||
|
# covers kubelet's cAdvisor endpoint and the prometheus.io/scrape
|
||||||
|
# annotation convention. extraScrapeConfigs is concatenated onto it
|
||||||
|
# rather than replacing it.
|
||||||
|
#
|
||||||
|
# Both jobs below exist because annotation-based discovery did not reach
|
||||||
|
# these targets in the homelab. Contour's Envoy carries no scrape
|
||||||
|
# annotation at all, and node-exporter's annotation sits on its Service,
|
||||||
|
# where the endpointslice discovery path found nothing. Targeting each by
|
||||||
|
# its fixed container port sidesteps both problems and is no less
|
||||||
|
# correct. Worth re-checking on this cluster rather than assuming the
|
||||||
|
# same gaps: if the defaults do find them here, these jobs are harmless
|
||||||
|
# duplicates, not errors.
|
||||||
|
extraScrapeConfigs:
|
||||||
|
- job_name: contour-envoy
|
||||||
|
kubernetes_sd_configs:
|
||||||
|
- role: pod
|
||||||
|
namespaces:
|
||||||
|
names: ["projectcontour"]
|
||||||
|
relabel_configs:
|
||||||
|
# 8002 is the official Contour chart's fixed metrics port for
|
||||||
|
# Envoy. /stats/prometheus is Envoy's own admin endpoint, not
|
||||||
|
# anything Contour-specific.
|
||||||
|
- action: keep
|
||||||
|
source_labels: [__meta_kubernetes_pod_container_port_number]
|
||||||
|
regex: "8002"
|
||||||
|
- target_label: __metrics_path__
|
||||||
|
replacement: /stats/prometheus
|
||||||
|
- action: labelmap
|
||||||
|
regex: __meta_kubernetes_pod_label_(.+)
|
||||||
|
- source_labels: [__meta_kubernetes_pod_name]
|
||||||
|
target_label: pod
|
||||||
|
- source_labels: [__meta_kubernetes_namespace]
|
||||||
|
target_label: namespace
|
||||||
|
- source_labels: [__meta_kubernetes_pod_node_name]
|
||||||
|
target_label: node
|
||||||
|
- job_name: node-exporter
|
||||||
|
kubernetes_sd_configs:
|
||||||
|
- role: pod
|
||||||
|
namespaces:
|
||||||
|
names: ["monitoring"]
|
||||||
|
relabel_configs:
|
||||||
|
- action: keep
|
||||||
|
source_labels: [__meta_kubernetes_pod_container_port_number]
|
||||||
|
regex: "9100"
|
||||||
|
- action: labelmap
|
||||||
|
regex: __meta_kubernetes_pod_label_(.+)
|
||||||
|
- source_labels: [__meta_kubernetes_pod_name]
|
||||||
|
target_label: pod
|
||||||
|
- source_labels: [__meta_kubernetes_namespace]
|
||||||
|
target_label: namespace
|
||||||
|
- source_labels: [__meta_kubernetes_pod_node_name]
|
||||||
|
target_label: node
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 192Mi
|
||||||
@@ -108,9 +108,17 @@ argo-cd:
|
|||||||
# role:admins / role:backend / GitHub-team policy.csv and real teammate
|
# role:admins / role:backend / GitHub-team policy.csv and real teammate
|
||||||
# emails from the source cluster are dropped here.
|
# emails from the source cluster are dropped here.
|
||||||
rbac:
|
rbac:
|
||||||
|
# Scoped to the whole webapp project, not one app name — this is
|
||||||
|
# exactly what that AppProject exists for (projects/webapp.yaml in
|
||||||
|
# devops-argo-config). Any future app onboarded into it (project:
|
||||||
|
# webapp in its Application manifest) is automatically covered by
|
||||||
|
# jenkins-ci's sync/get access with zero RBAC changes needed here.
|
||||||
|
# Platform-level apps (argocd, gitea, vault, contour,
|
||||||
|
# external-secrets, jenkins, harbor) stay on the default project,
|
||||||
|
# untouched by this policy.
|
||||||
policy.csv: |
|
policy.csv: |
|
||||||
p, jenkins-ci, applications, sync, webapp/demo-go-app, allow
|
p, jenkins-ci, applications, sync, webapp/*, allow
|
||||||
p, jenkins-ci, applications, get, webapp/demo-go-app, allow
|
p, jenkins-ci, applications, get, webapp/*, allow
|
||||||
repositories:
|
repositories:
|
||||||
devops-infra-helm-charts:
|
devops-infra-helm-charts:
|
||||||
url: http://gitea.192.168.1.7.nip.io/mukul/devops-infra-helm-charts.git
|
url: http://gitea.192.168.1.7.nip.io/mukul/devops-infra-helm-charts.git
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
|||||||
|
prometheus-node-exporter:
|
||||||
|
# Same resource trim this ran with as a subchart of the (now removed)
|
||||||
|
# prometheus server chart. One DaemonSet pod, hostNetwork, light enough
|
||||||
|
# that this is the whole footprint regardless of which TSDB scrapes it.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
# rbac.pspEnabled defaults false already (no PodSecurityPolicy on this
|
||||||
|
# cluster) — nothing to override here. The chart's own Service carries
|
||||||
|
# `prometheus.io/scrape: true` by default, which is what vmagent's
|
||||||
|
# already-enabled kubernetes-service-endpoints job picks up — no
|
||||||
|
# separate scrape config needed on either side.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# PostgreSQL for toolshed's control plane.
|
||||||
|
#
|
||||||
|
# Deployed as shared infrastructure in its own namespace rather than inside
|
||||||
|
# the toolshed namespace, so it is addressed over cluster DNS like any other
|
||||||
|
# platform component and its lifecycle is independent of the application
|
||||||
|
# that happens to be its first consumer:
|
||||||
|
#
|
||||||
|
# postgresql.postgres.svc.cluster.local:5432
|
||||||
|
#
|
||||||
|
# Credentials come from Vault through External Secrets — see
|
||||||
|
# devops-infra-argo-config/secretstores/toolshed-postgres-credentials.yaml.
|
||||||
|
# The Secret must exist before this pod can start; a missing Secret leaves it
|
||||||
|
# in CreateContainerConfigError rather than failing in a way that explains
|
||||||
|
# itself.
|
||||||
|
|
||||||
|
fullnameOverride: postgresql
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
tag: "16-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
existingSecret: postgresql-credentials
|
||||||
|
database: toolshed
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
# local-path-provisioner, this cluster's default StorageClass — installed
|
||||||
|
# right after Cilium precisely because kubeadm ships no default (unlike
|
||||||
|
# k3s). 5Gi is generous for control-plane metadata; the volume is not
|
||||||
|
# resizable in place with this provisioner, so it is sized up front.
|
||||||
|
storageClass: local-path
|
||||||
|
size: 5Gi
|
||||||
|
|
||||||
|
config:
|
||||||
|
# Deliberately far below PostgreSQL's 128MB default. The node has 8GB and
|
||||||
|
# was already at its ceiling before this; the demo apps were scaled to zero
|
||||||
|
# to make room. Revisit only if query performance actually suffers, which
|
||||||
|
# for a handful of control-plane tables it will not.
|
||||||
|
sharedBuffers: 32MB
|
||||||
|
maxConnections: "50"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# Redis backing toolshed's managed cache add-on.
|
||||||
|
#
|
||||||
|
# Deployed as shared infrastructure in its own namespace rather than inside
|
||||||
|
# the toolshed namespace, so it is addressed over cluster DNS like any other
|
||||||
|
# platform component and its lifecycle is independent of the application
|
||||||
|
# that happens to be its first consumer:
|
||||||
|
#
|
||||||
|
# redis.redis.svc.cluster.local:6379
|
||||||
|
#
|
||||||
|
# The admin password comes from Vault through External Secrets — see
|
||||||
|
# devops-infra-argo-config/secretstores/toolshed-redis-credentials.yaml. The
|
||||||
|
# Secret must exist before this pod can start; a missing Secret leaves the
|
||||||
|
# init container in CreateContainerConfigError rather than failing in a way
|
||||||
|
# that explains itself.
|
||||||
|
#
|
||||||
|
# Read values.yaml's `config` block before changing anything about
|
||||||
|
# authentication here. The absence of `requirepass` is deliberate and
|
||||||
|
# security-relevant, not an oversight.
|
||||||
|
|
||||||
|
fullnameOverride: redis
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: redis
|
||||||
|
tag: "7-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
existingSecret: redis-credentials
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: local-path
|
||||||
|
# Holds the ACL file and nothing else worth keeping — snapshotting is off
|
||||||
|
# (see config.save). 1Gi is already far more than needed; local-path
|
||||||
|
# cannot resize in place, so it is sized up front rather than tightly.
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
config:
|
||||||
|
# The node has 8GB and was at its ceiling before Postgres was added; the
|
||||||
|
# demo apps were scaled to zero to make room for that. 48mb is a real
|
||||||
|
# cache for a handful of small internal tools and costs little.
|
||||||
|
maxmemory: 48mb
|
||||||
|
maxmemoryPolicy: allkeys-lru
|
||||||
|
save: ""
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 96Mi
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
victoria-metrics-single:
|
||||||
|
server:
|
||||||
|
# 7 days, not the chart's month-long default — a homelab whose entire
|
||||||
|
# purpose is proving a CI/CD pipeline has no use for that much
|
||||||
|
# history, and every extra day is disk this node does not have spare.
|
||||||
|
retentionPeriod: "7d"
|
||||||
|
|
||||||
|
persistentVolume:
|
||||||
|
# local-path-provisioner, this cluster's default StorageClass —
|
||||||
|
# installed right after Cilium precisely because kubeadm ships no
|
||||||
|
# default (unlike k3s). 3Gi, not the chart's 16Gi default: VM's own
|
||||||
|
# compression is the whole reason it replaced Prometheus here, and
|
||||||
|
# this cluster's metric volume at a 7-day retention comfortably
|
||||||
|
# fits well inside that. Not resizable in place with this
|
||||||
|
# provisioner, so sized deliberately rather than grown later.
|
||||||
|
storageClassName: local-path
|
||||||
|
size: 3Gi
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# vmui — VictoriaMetrics' own built-in UI, served at /vmui/ on the
|
||||||
|
# same server. Ad-hoc PromQL queries and graphs only, no saved
|
||||||
|
# dashboards; Grafana (separate release) is what those need. Exposed
|
||||||
|
# anyway since it costs nothing extra to run — it's the same
|
||||||
|
# pod/port, not a new component — and is useful on its own for
|
||||||
|
# poking at a metric without opening Grafana.
|
||||||
|
#
|
||||||
|
# Dual LAN + Tailscale hostnames, same convention as every other
|
||||||
|
# externally-reachable service in this homelab.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: contour
|
||||||
|
hosts:
|
||||||
|
- name: vm.192.168.1.7.nip.io
|
||||||
|
path: ["/"]
|
||||||
|
port: http
|
||||||
|
- name: vm.100.90.248.118.nip.io
|
||||||
|
path: ["/"]
|
||||||
|
port: http
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
victoria-metrics-agent:
|
||||||
|
# Ships to victoria-metrics-single. The write path is /api/v1/write,
|
||||||
|
# the same endpoint any Prometheus remote_write client uses — this is
|
||||||
|
# the one config line that actually wires the two components together;
|
||||||
|
# the chart names don't imply it on their own.
|
||||||
|
#
|
||||||
|
# Cluster-internal Service DNS: this call happens from a pod, so
|
||||||
|
# CoreDNS resolves it. Same reasoning as everywhere else in this
|
||||||
|
# project that a Service name (not an Ingress hostname) is correct
|
||||||
|
# here — see claude.md's registry-hostname convention for the one case
|
||||||
|
# where cluster DNS specifically does NOT work (a node-level pull),
|
||||||
|
# which does not apply to this pod-to-pod write.
|
||||||
|
remoteWrite:
|
||||||
|
- url: http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428/api/v1/write
|
||||||
|
|
||||||
|
# config.scrape_configs is left at the chart's own default — it already
|
||||||
|
# includes kubernetes-nodes-cadvisor (kubelet's cAdvisor endpoint,
|
||||||
|
# comment literally says "COPY from Prometheus helm chart") and
|
||||||
|
# kubernetes-service-endpoints (the prometheus.io/scrape annotation
|
||||||
|
# convention node-exporter's Service carries). Nothing here needs a
|
||||||
|
# scrape target the chart doesn't already define out of the box —
|
||||||
|
# except Contour's own Envoy, added below via extraScrapeConfigs (the
|
||||||
|
# chart concatenates this onto config.scrape_configs rather than
|
||||||
|
# replacing it, so the defaults above are unaffected).
|
||||||
|
#
|
||||||
|
# Confirmed live, not assumed: Cilium's own embedded Envoy (a separate
|
||||||
|
# thing — its L7 policy proxy, kube-system namespace) was already being
|
||||||
|
# scraped via the annotation-based kubernetes-pods job, which is what
|
||||||
|
# first showed envoy_* metrics existed at all in this cluster. Contour's
|
||||||
|
# ingress Envoy (projectcontour namespace — the actual data plane for
|
||||||
|
# everything routed through this homelab's Ingress, hostPort 80/443)
|
||||||
|
# carries no such annotation, confirmed by its total absence from
|
||||||
|
# `envoy_http_downstream_rq_total{namespace="projectcontour"}` before
|
||||||
|
# this job existed — so it needs its own explicit target.
|
||||||
|
#
|
||||||
|
# Filtered by container port number (8002, the official Contour
|
||||||
|
# chart's fixed metrics port for Envoy — projectcontour/values or
|
||||||
|
# equivalent) rather than by pod label: this cluster's Contour install
|
||||||
|
# auto-detected object names after install rather than assuming the
|
||||||
|
# chart's defaults (see claude.md's Contour install history), so a
|
||||||
|
# label guess is less trustworthy here than the one thing that has to
|
||||||
|
# be true for Envoy's own metrics port to exist at all.
|
||||||
|
#
|
||||||
|
# /stats/prometheus is Envoy's own built-in admin endpoint format, not
|
||||||
|
# a Contour-specific path — this is how any Envoy exposes Prometheus
|
||||||
|
# metrics once a metrics listener is configured, independent of chart.
|
||||||
|
#
|
||||||
|
# node-exporter needed the same treatment, for a different reason:
|
||||||
|
# confirmed live that kubernetes-service-endpoints (role: endpointslice,
|
||||||
|
# keyed on the *Service's* prometheus.io/scrape annotation — where the
|
||||||
|
# node-exporter chart actually puts it, not on the pod) finds nothing
|
||||||
|
# at all in this cluster — not "down", entirely absent from `up`, no
|
||||||
|
# `kubernetes-service-endpoints`/`kubernetes-services` job present
|
||||||
|
# whatsoever. Rather than chase why that discovery path is empty here,
|
||||||
|
# targeting node-exporter's pod directly by its declared container port
|
||||||
|
# (9100, the chart's fixed default) sidesteps it the same way the
|
||||||
|
# Envoy job above does, and is no less correct for not depending on
|
||||||
|
# whichever annotation-propagation mechanism isn't working.
|
||||||
|
extraScrapeConfigs:
|
||||||
|
- job_name: contour-envoy
|
||||||
|
kubernetes_sd_configs:
|
||||||
|
- role: pod
|
||||||
|
namespaces:
|
||||||
|
names: ["projectcontour"]
|
||||||
|
relabel_configs:
|
||||||
|
- action: keep
|
||||||
|
source_labels: [__meta_kubernetes_pod_container_port_number]
|
||||||
|
regex: "8002"
|
||||||
|
- target_label: __metrics_path__
|
||||||
|
replacement: /stats/prometheus
|
||||||
|
- action: labelmap
|
||||||
|
regex: __meta_kubernetes_pod_label_(.+)
|
||||||
|
- source_labels: [__meta_kubernetes_pod_name]
|
||||||
|
target_label: pod
|
||||||
|
- source_labels: [__meta_kubernetes_namespace]
|
||||||
|
target_label: namespace
|
||||||
|
- source_labels: [__meta_kubernetes_pod_node_name]
|
||||||
|
target_label: node
|
||||||
|
- job_name: node-exporter
|
||||||
|
kubernetes_sd_configs:
|
||||||
|
- role: pod
|
||||||
|
namespaces:
|
||||||
|
names: ["monitoring"]
|
||||||
|
relabel_configs:
|
||||||
|
- action: keep
|
||||||
|
source_labels: [__meta_kubernetes_pod_container_port_number]
|
||||||
|
regex: "9100"
|
||||||
|
- action: labelmap
|
||||||
|
regex: __meta_kubernetes_pod_label_(.+)
|
||||||
|
- source_labels: [__meta_kubernetes_pod_name]
|
||||||
|
target_label: pod
|
||||||
|
- source_labels: [__meta_kubernetes_namespace]
|
||||||
|
target_label: namespace
|
||||||
|
- source_labels: [__meta_kubernetes_pod_node_name]
|
||||||
|
target_label: node
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 192Mi
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
- name: argo-cd
|
- name: argo-cd
|
||||||
repository: https://argoproj.github.io/argo-helm
|
repository: https://argoproj.github.io/argo-helm
|
||||||
version: 7.7.23
|
version: 10.8.4
|
||||||
digest: sha256:5d5bb5374bd6a589b5a070a2e48bb1dd211e3871c31af9700297575c84e6f70e
|
digest: sha256:bf31d2cce073a775bf05ec90b74ae45625df5fb6774323a9139d4f8a1be2440a
|
||||||
generated: "2026-08-31T06:40:31.347755+05:30"
|
generated: "2026-09-12T15:22:56.688354+05:30"
|
||||||
|
|||||||
@@ -3,5 +3,14 @@ name: argocd
|
|||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: argo-cd
|
- name: argo-cd
|
||||||
version: 7.7.23
|
# Argo CD v3.5.2. Bumped from 7.7.23 (v2.13.8), which was older than
|
||||||
|
# this cluster: it diffs against a Kubernetes schema compiled into its
|
||||||
|
# own binary, and GKE 1.35 has fields that schema predates
|
||||||
|
# (status.terminatingReplicas, beta since 1.33), which aborted the diff
|
||||||
|
# on every server-side-apply app. ServerSideDiff works around that; this
|
||||||
|
# removes the cause.
|
||||||
|
#
|
||||||
|
# Not a drop-in: see the 2.x -> 3.0 notes in this cluster's
|
||||||
|
# argocd-admin-prd/custom-values.yaml for what changed in behaviour.
|
||||||
|
version: 10.8.4
|
||||||
repository: https://argoproj.github.io/argo-helm
|
repository: https://argoproj.github.io/argo-helm
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,23 +0,0 @@
|
|||||||
# 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
|
|
||||||
*~
|
|
||||||
# Various IDEs
|
|
||||||
.vscode
|
|
||||||
.project
|
|
||||||
.idea/
|
|
||||||
*.tmproj
|
|
||||||
OWNERS
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- name: grafana
|
||||||
|
repository: https://grafana.github.io/helm-charts
|
||||||
|
version: 10.5.15
|
||||||
|
digest: sha256:3fd0080197abb0a1968d174ead7180f962c939cab8037f1b8ead6dd3adfa7490
|
||||||
|
generated: "2026-09-06T08:54:21.395461+05:30"
|
||||||
@@ -1,33 +1,20 @@
|
|||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
name: grafana
|
name: grafana
|
||||||
version: 6.58.7
|
version: 1.0.0
|
||||||
appVersion: 10.0.3
|
dependencies:
|
||||||
kubeVersion: "^1.8.0-0"
|
- name: grafana
|
||||||
description: The leading tool for querying and visualizing time series and metrics.
|
# Pinned to the latest stable at the time this was vendored (2026-09).
|
||||||
home: https://grafana.net
|
# Bump deliberately later, with a changelog read first, same as any
|
||||||
icon: https://raw.githubusercontent.com/grafana/grafana/master/public/img/logo_transparent_400x.png
|
# other chart bump in this repo.
|
||||||
sources:
|
#
|
||||||
- https://github.com/grafana/grafana
|
# This directory already held a fully-vendored copy of an old Grafana
|
||||||
- https://github.com/grafana/helm-charts
|
# chart (v6.58.7, appVersion 10.0.3) from the original Meesho monorepo
|
||||||
annotations:
|
# import (commit b8575bb) — generic production config
|
||||||
"artifacthub.io/license": AGPL-3.0-only
|
# (fullnameOverride: grafana-infra-prd, GKE-shaped RBAC/PSP defaults),
|
||||||
"artifacthub.io/links": |
|
# not anything built for this homelab. Removed and re-vendored fresh
|
||||||
- name: Chart Source
|
# as a thin wrapper, matching the pattern every other official-chart
|
||||||
url: https://github.com/grafana/helm-charts
|
# component in this repo now uses (vault, victoria-metrics-single,
|
||||||
- name: Upstream Project
|
# vmagent, node-exporter) — a Chart.yaml dependency plus a committed
|
||||||
url: https://github.com/grafana/grafana
|
# .tgz, no local templates to silently drift from upstream.
|
||||||
maintainers:
|
version: 10.5.15
|
||||||
- name: zanhsieh
|
repository: https://grafana.github.io/helm-charts
|
||||||
email: zanhsieh@gmail.com
|
|
||||||
- name: rtluckie
|
|
||||||
email: rluckie@cisco.com
|
|
||||||
- name: maorfr
|
|
||||||
email: maor.friedman@redhat.com
|
|
||||||
- name: Xtigyro
|
|
||||||
email: miroslav.hadzhiev@gmail.com
|
|
||||||
- name: torstenwalter
|
|
||||||
email: mail@torstenwalter.de
|
|
||||||
type: application
|
|
||||||
keywords:
|
|
||||||
- monitoring
|
|
||||||
- metric
|
|
||||||
|
|||||||
@@ -1,686 +0,0 @@
|
|||||||
# Grafana Helm Chart
|
|
||||||
|
|
||||||
* Installs the web dashboarding system [Grafana](http://grafana.org/)
|
|
||||||
|
|
||||||
## Get Repo Info
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm repo add grafana https://grafana.github.io/helm-charts
|
|
||||||
helm repo update
|
|
||||||
```
|
|
||||||
|
|
||||||
_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
|
|
||||||
|
|
||||||
## Installing the Chart
|
|
||||||
|
|
||||||
To install the chart with the release name `my-release`:
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm install my-release grafana/grafana
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstalling the Chart
|
|
||||||
|
|
||||||
To uninstall/delete the my-release deployment:
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm delete my-release
|
|
||||||
```
|
|
||||||
|
|
||||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
|
||||||
|
|
||||||
## Upgrading an existing Release to a new major version
|
|
||||||
|
|
||||||
A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an
|
|
||||||
incompatible breaking change needing manual actions.
|
|
||||||
|
|
||||||
### To 4.0.0 (And 3.12.1)
|
|
||||||
|
|
||||||
This version requires Helm >= 2.12.0.
|
|
||||||
|
|
||||||
### To 5.0.0
|
|
||||||
|
|
||||||
You have to add --force to your helm upgrade command as the labels of the chart have changed.
|
|
||||||
|
|
||||||
### To 6.0.0
|
|
||||||
|
|
||||||
This version requires Helm >= 3.1.0.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
| Parameter | Description | Default |
|
|
||||||
|-------------------------------------------|-----------------------------------------------|---------------------------------------------------------|
|
|
||||||
| `replicas` | Number of nodes | `1` |
|
|
||||||
| `podDisruptionBudget.minAvailable` | Pod disruption minimum available | `nil` |
|
|
||||||
| `podDisruptionBudget.maxUnavailable` | Pod disruption maximum unavailable | `nil` |
|
|
||||||
| `deploymentStrategy` | Deployment strategy | `{ "type": "RollingUpdate" }` |
|
|
||||||
| `livenessProbe` | Liveness Probe settings | `{ "httpGet": { "path": "/api/health", "port": 3000 } "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10 }` |
|
|
||||||
| `readinessProbe` | Readiness Probe settings | `{ "httpGet": { "path": "/api/health", "port": 3000 } }`|
|
|
||||||
| `securityContext` | Deployment securityContext | `{"runAsUser": 472, "runAsGroup": 472, "fsGroup": 472}` |
|
|
||||||
| `priorityClassName` | Name of Priority Class to assign pods | `nil` |
|
|
||||||
| `image.repository` | Image repository | `grafana/grafana` |
|
|
||||||
| `image.tag` | Overrides the Grafana image tag whose default is the chart appVersion (`Must be >= 5.0.0`) | `` |
|
|
||||||
| `image.sha` | Image sha (optional) | `` |
|
|
||||||
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
|
|
||||||
| `image.pullSecrets` | Image pull secrets (can be templated) | `[]` |
|
|
||||||
| `service.enabled` | Enable grafana service | `true` |
|
|
||||||
| `service.type` | Kubernetes service type | `ClusterIP` |
|
|
||||||
| `service.port` | Kubernetes port where service is exposed | `80` |
|
|
||||||
| `service.portName` | Name of the port on the service | `service` |
|
|
||||||
| `service.appProtocol` | Adds the appProtocol field to the service | `` |
|
|
||||||
| `service.targetPort` | Internal service is port | `3000` |
|
|
||||||
| `service.nodePort` | Kubernetes service nodePort | `nil` |
|
|
||||||
| `service.annotations` | Service annotations (can be templated) | `{}` |
|
|
||||||
| `service.labels` | Custom labels | `{}` |
|
|
||||||
| `service.clusterIP` | internal cluster service IP | `nil` |
|
|
||||||
| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `nil` |
|
|
||||||
| `service.loadBalancerSourceRanges` | list of IP CIDRs allowed access to lb (if supported) | `[]` |
|
|
||||||
| `service.externalIPs` | service external IP addresses | `[]` |
|
|
||||||
| `headlessService` | Create a headless service | `false` |
|
|
||||||
| `extraExposePorts` | Additional service ports for sidecar containers| `[]` |
|
|
||||||
| `hostAliases` | adds rules to the pod's /etc/hosts | `[]` |
|
|
||||||
| `ingress.enabled` | Enables Ingress | `false` |
|
|
||||||
| `ingress.annotations` | Ingress annotations (values are templated) | `{}` |
|
|
||||||
| `ingress.labels` | Custom labels | `{}` |
|
|
||||||
| `ingress.path` | Ingress accepted path | `/` |
|
|
||||||
| `ingress.pathType` | Ingress type of path | `Prefix` |
|
|
||||||
| `ingress.hosts` | Ingress accepted hostnames | `["chart-example.local"]` |
|
|
||||||
| `ingress.extraPaths` | Ingress extra paths to prepend to every host configuration. Useful when configuring [custom actions with AWS ALB Ingress Controller](https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/ingress/annotation/#actions). Requires `ingress.hosts` to have one or more host entries. | `[]` |
|
|
||||||
| `ingress.tls` | Ingress TLS configuration | `[]` |
|
|
||||||
| `ingress.ingressClassName` | Ingress Class Name. MAY be required for Kubernetes versions >= 1.18 | `""` |
|
|
||||||
| `resources` | CPU/Memory resource requests/limits | `{}` |
|
|
||||||
| `nodeSelector` | Node labels for pod assignment | `{}` |
|
|
||||||
| `tolerations` | Toleration labels for pod assignment | `[]` |
|
|
||||||
| `affinity` | Affinity settings for pod assignment | `{}` |
|
|
||||||
| `extraInitContainers` | Init containers to add to the grafana pod | `{}` |
|
|
||||||
| `extraContainers` | Sidecar containers to add to the grafana pod | `""` |
|
|
||||||
| `extraContainerVolumes` | Volumes that can be mounted in sidecar containers | `[]` |
|
|
||||||
| `extraLabels` | Custom labels for all manifests | `{}` |
|
|
||||||
| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` |
|
|
||||||
| `persistence.enabled` | Use persistent volume to store data | `false` |
|
|
||||||
| `persistence.type` | Type of persistence (`pvc` or `statefulset`) | `pvc` |
|
|
||||||
| `persistence.size` | Size of persistent volume claim | `10Gi` |
|
|
||||||
| `persistence.existingClaim` | Use an existing PVC to persist data (can be templated) | `nil` |
|
|
||||||
| `persistence.storageClassName` | Type of persistent volume claim | `nil` |
|
|
||||||
| `persistence.accessModes` | Persistence access modes | `[ReadWriteOnce]` |
|
|
||||||
| `persistence.annotations` | PersistentVolumeClaim annotations | `{}` |
|
|
||||||
| `persistence.finalizers` | PersistentVolumeClaim finalizers | `[ "kubernetes.io/pvc-protection" ]` |
|
|
||||||
| `persistence.extraPvcLabels` | Extra labels to apply to a PVC. | `{}` |
|
|
||||||
| `persistence.subPath` | Mount a sub dir of the persistent volume (can be templated) | `nil` |
|
|
||||||
| `persistence.inMemory.enabled` | If persistence is not enabled, whether to mount the local storage in-memory to improve performance | `false` |
|
|
||||||
| `persistence.inMemory.sizeLimit` | SizeLimit for the in-memory local storage | `nil` |
|
|
||||||
| `initChownData.enabled` | If false, don't reset data ownership at startup | true |
|
|
||||||
| `initChownData.image.repository` | init-chown-data container image repository | `busybox` |
|
|
||||||
| `initChownData.image.tag` | init-chown-data container image tag | `1.31.1` |
|
|
||||||
| `initChownData.image.sha` | init-chown-data container image sha (optional)| `""` |
|
|
||||||
| `initChownData.image.pullPolicy` | init-chown-data container image pull policy | `IfNotPresent` |
|
|
||||||
| `initChownData.resources` | init-chown-data pod resource requests & limits | `{}` |
|
|
||||||
| `schedulerName` | Alternate scheduler name | `nil` |
|
|
||||||
| `env` | Extra environment variables passed to pods | `{}` |
|
|
||||||
| `envValueFrom` | Environment variables from alternate sources. See the API docs on [EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core) for format details. Can be templated | `{}` |
|
|
||||||
| `envFromSecret` | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` |
|
|
||||||
| `envFromSecrets` | List of Kubernetes secrets (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `[]` |
|
|
||||||
| `envFromConfigMaps` | List of Kubernetes ConfigMaps (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `[]` |
|
|
||||||
| `envRenderSecret` | Sensible environment variables passed to pods and stored as secret. (passed through [tpl](https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-tpl-function)) | `{}` |
|
|
||||||
| `enableServiceLinks` | Inject Kubernetes services as environment variables. | `true` |
|
|
||||||
| `extraSecretMounts` | Additional grafana server secret mounts | `[]` |
|
|
||||||
| `extraVolumeMounts` | Additional grafana server volume mounts | `[]` |
|
|
||||||
| `createConfigmap` | Enable creating the grafana configmap | `true` |
|
|
||||||
| `extraConfigmapMounts` | Additional grafana server configMap volume mounts (values are templated) | `[]` |
|
|
||||||
| `extraEmptyDirMounts` | Additional grafana server emptyDir volume mounts | `[]` |
|
|
||||||
| `plugins` | Plugins to be loaded along with Grafana | `[]` |
|
|
||||||
| `datasources` | Configure grafana datasources (passed through tpl) | `{}` |
|
|
||||||
| `alerting` | Configure grafana alerting (passed through tpl) | `{}` |
|
|
||||||
| `notifiers` | Configure grafana notifiers | `{}` |
|
|
||||||
| `dashboardProviders` | Configure grafana dashboard providers | `{}` |
|
|
||||||
| `dashboards` | Dashboards to import | `{}` |
|
|
||||||
| `dashboardsConfigMaps` | ConfigMaps reference that contains dashboards | `{}` |
|
|
||||||
| `grafana.ini` | Grafana's primary configuration | `{}` |
|
|
||||||
| `global.imagePullSecrets` | Global image pull secrets (can be templated). Allows either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). | `[]` |
|
|
||||||
| `ldap.enabled` | Enable LDAP authentication | `false` |
|
|
||||||
| `ldap.existingSecret` | The name of an existing secret containing the `ldap.toml` file, this must have the key `ldap-toml`. | `""` |
|
|
||||||
| `ldap.config` | Grafana's LDAP configuration | `""` |
|
|
||||||
| `annotations` | Deployment annotations | `{}` |
|
|
||||||
| `labels` | Deployment labels | `{}` |
|
|
||||||
| `podAnnotations` | Pod annotations | `{}` |
|
|
||||||
| `podLabels` | Pod labels | `{}` |
|
|
||||||
| `podPortName` | Name of the grafana port on the pod | `grafana` |
|
|
||||||
| `lifecycleHooks` | Lifecycle hooks for podStart and preStop [Example](https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/#define-poststart-and-prestop-handlers) | `{}` |
|
|
||||||
| `sidecar.image.repository` | Sidecar image repository | `quay.io/kiwigrid/k8s-sidecar` |
|
|
||||||
| `sidecar.image.tag` | Sidecar image tag | `1.24.6` |
|
|
||||||
| `sidecar.image.sha` | Sidecar image sha (optional) | `""` |
|
|
||||||
| `sidecar.imagePullPolicy` | Sidecar image pull policy | `IfNotPresent` |
|
|
||||||
| `sidecar.resources` | Sidecar resources | `{}` |
|
|
||||||
| `sidecar.securityContext` | Sidecar securityContext | `{}` |
|
|
||||||
| `sidecar.enableUniqueFilenames` | Sets the kiwigrid/k8s-sidecar UNIQUE_FILENAMES environment variable. If set to `true` the sidecar will create unique filenames where duplicate data keys exist between ConfigMaps and/or Secrets within the same or multiple Namespaces. | `false` |
|
|
||||||
| `sidecar.alerts.enabled` | Enables the cluster wide search for alerts and adds/updates/deletes them in grafana |`false` |
|
|
||||||
| `sidecar.alerts.label` | Label that config maps with alerts should have to be added | `grafana_alert` |
|
|
||||||
| `sidecar.alerts.labelValue` | Label value that config maps with alerts should have to be added | `""` |
|
|
||||||
| `sidecar.alerts.searchNamespace` | Namespaces list. If specified, the sidecar will search for alerts config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
|
|
||||||
| `sidecar.alerts.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
|
|
||||||
| `sidecar.alerts.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
|
|
||||||
| `sidecar.alerts.reloadURL` | Full url of datasource configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/alerting/reload"` |
|
|
||||||
| `sidecar.alerts.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` |
|
|
||||||
| `sidecar.alerts.initDatasources` | Set to true to deploy the datasource sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any alerts defined at startup time. | `false` |
|
|
||||||
| `sidecar.alerts.extraMounts` | Additional alerts sidecar volume mounts. | `[]` |
|
|
||||||
| `sidecar.dashboards.enabled` | Enables the cluster wide search for dashboards and adds/updates/deletes them in grafana | `false` |
|
|
||||||
| `sidecar.dashboards.SCProvider` | Enables creation of sidecar provider | `true` |
|
|
||||||
| `sidecar.dashboards.provider.name` | Unique name of the grafana provider | `sidecarProvider` |
|
|
||||||
| `sidecar.dashboards.provider.orgid` | Id of the organisation, to which the dashboards should be added | `1` |
|
|
||||||
| `sidecar.dashboards.provider.folder` | Logical folder in which grafana groups dashboards | `""` |
|
|
||||||
| `sidecar.dashboards.provider.disableDelete` | Activate to avoid the deletion of imported dashboards | `false` |
|
|
||||||
| `sidecar.dashboards.provider.allowUiUpdates` | Allow updating provisioned dashboards from the UI | `false` |
|
|
||||||
| `sidecar.dashboards.provider.type` | Provider type | `file` |
|
|
||||||
| `sidecar.dashboards.provider.foldersFromFilesStructure` | Allow Grafana to replicate dashboard structure from filesystem. | `false` |
|
|
||||||
| `sidecar.dashboards.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
|
|
||||||
| `sidecar.skipTlsVerify` | Set to true to skip tls verification for kube api calls | `nil` |
|
|
||||||
| `sidecar.dashboards.label` | Label that config maps with dashboards should have to be added | `grafana_dashboard` |
|
|
||||||
| `sidecar.dashboards.labelValue` | Label value that config maps with dashboards should have to be added | `""` |
|
|
||||||
| `sidecar.dashboards.folder` | Folder in the pod that should hold the collected dashboards (unless `sidecar.dashboards.defaultFolderName` is set). This path will be mounted. | `/tmp/dashboards` |
|
|
||||||
| `sidecar.dashboards.folderAnnotation` | The annotation the sidecar will look for in configmaps to override the destination folder for files | `nil` |
|
|
||||||
| `sidecar.dashboards.defaultFolderName` | The default folder name, it will create a subfolder under the `sidecar.dashboards.folder` and put dashboards in there instead | `nil` |
|
|
||||||
| `sidecar.dashboards.searchNamespace` | Namespaces list. If specified, the sidecar will search for dashboards config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
|
|
||||||
| `sidecar.dashboards.script` | Absolute path to shell script to execute after a configmap got reloaded. | `nil` |
|
|
||||||
| `sidecar.dashboards.reloadURL` | Full url of dashboards configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/dashboards/reload"` |
|
|
||||||
| `sidecar.dashboards.skipReload` | Enabling this omits defining the REQ_USERNAME, REQ_PASSWORD, REQ_URL and REQ_METHOD environment variables | `false` |
|
|
||||||
| `sidecar.dashboards.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
|
|
||||||
| `sidecar.dashboards.extraMounts` | Additional dashboard sidecar volume mounts. | `[]` |
|
|
||||||
| `sidecar.datasources.enabled` | Enables the cluster wide search for datasources and adds/updates/deletes them in grafana |`false` |
|
|
||||||
| `sidecar.datasources.label` | Label that config maps with datasources should have to be added | `grafana_datasource` |
|
|
||||||
| `sidecar.datasources.labelValue` | Label value that config maps with datasources should have to be added | `""` |
|
|
||||||
| `sidecar.datasources.searchNamespace` | Namespaces list. If specified, the sidecar will search for datasources config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
|
|
||||||
| `sidecar.datasources.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
|
|
||||||
| `sidecar.datasources.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
|
|
||||||
| `sidecar.datasources.reloadURL` | Full url of datasource configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/datasources/reload"` |
|
|
||||||
| `sidecar.datasources.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` |
|
|
||||||
| `sidecar.datasources.initDatasources` | Set to true to deploy the datasource sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any datasources defined at startup time. | `false` |
|
|
||||||
| `sidecar.notifiers.enabled` | Enables the cluster wide search for notifiers and adds/updates/deletes them in grafana | `false` |
|
|
||||||
| `sidecar.notifiers.label` | Label that config maps with notifiers should have to be added | `grafana_notifier` |
|
|
||||||
| `sidecar.notifiers.labelValue` | Label value that config maps with notifiers should have to be added | `""` |
|
|
||||||
| `sidecar.notifiers.searchNamespace` | Namespaces list. If specified, the sidecar will search for notifiers config-maps (or secrets) inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
|
|
||||||
| `sidecar.notifiers.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
|
|
||||||
| `sidecar.notifiers.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
|
|
||||||
| `sidecar.notifiers.reloadURL` | Full url of notifier configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/notifications/reload"` |
|
|
||||||
| `sidecar.notifiers.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` |
|
|
||||||
| `sidecar.notifiers.initNotifiers` | Set to true to deploy the notifier sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any notifiers defined at startup time. | `false` |
|
|
||||||
| `smtp.existingSecret` | The name of an existing secret containing the SMTP credentials. | `""` |
|
|
||||||
| `smtp.userKey` | The key in the existing SMTP secret containing the username. | `"user"` |
|
|
||||||
| `smtp.passwordKey` | The key in the existing SMTP secret containing the password. | `"password"` |
|
|
||||||
| `admin.existingSecret` | The name of an existing secret containing the admin credentials (can be templated). | `""` |
|
|
||||||
| `admin.userKey` | The key in the existing admin secret containing the username. | `"admin-user"` |
|
|
||||||
| `admin.passwordKey` | The key in the existing admin secret containing the password. | `"admin-password"` |
|
|
||||||
| `serviceAccount.autoMount` | Automount the service account token in the pod| `true` |
|
|
||||||
| `serviceAccount.annotations` | ServiceAccount annotations | |
|
|
||||||
| `serviceAccount.create` | Create service account | `true` |
|
|
||||||
| `serviceAccount.labels` | ServiceAccount labels | `{}` |
|
|
||||||
| `serviceAccount.name` | Service account name to use, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `` |
|
|
||||||
| `serviceAccount.nameTest` | Service account name to use for test, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `nil` |
|
|
||||||
| `rbac.create` | Create and use RBAC resources | `true` |
|
|
||||||
| `rbac.namespaced` | Creates Role and Rolebinding instead of the default ClusterRole and ClusteRoleBindings for the grafana instance | `false` |
|
|
||||||
| `rbac.useExistingRole` | Set to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to the rolename set here. | `nil` |
|
|
||||||
| `rbac.pspEnabled` | Create PodSecurityPolicy (with `rbac.create`, grant roles permissions as well) | `false` |
|
|
||||||
| `rbac.pspUseAppArmor` | Enforce AppArmor in created PodSecurityPolicy (requires `rbac.pspEnabled`) | `false` |
|
|
||||||
| `rbac.extraRoleRules` | Additional rules to add to the Role | [] |
|
|
||||||
| `rbac.extraClusterRoleRules` | Additional rules to add to the ClusterRole | [] |
|
|
||||||
| `command` | Define command to be executed by grafana container at startup | `nil` |
|
|
||||||
| `args` | Define additional args if command is used | `nil` |
|
|
||||||
| `testFramework.enabled` | Whether to create test-related resources | `true` |
|
|
||||||
| `testFramework.image` | `test-framework` image repository. | `bats/bats` |
|
|
||||||
| `testFramework.tag` | `test-framework` image tag. | `v1.4.1` |
|
|
||||||
| `testFramework.imagePullPolicy` | `test-framework` image pull policy. | `IfNotPresent` |
|
|
||||||
| `testFramework.securityContext` | `test-framework` securityContext | `{}` |
|
|
||||||
| `downloadDashboards.env` | Environment variables to be passed to the `download-dashboards` container | `{}` |
|
|
||||||
| `downloadDashboards.envFromSecret` | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` |
|
|
||||||
| `downloadDashboards.resources` | Resources of `download-dashboards` container | `{}` |
|
|
||||||
| `downloadDashboardsImage.repository` | Curl docker image repo | `curlimages/curl` |
|
|
||||||
| `downloadDashboardsImage.tag` | Curl docker image tag | `7.73.0` |
|
|
||||||
| `downloadDashboardsImage.sha` | Curl docker image sha (optional) | `""` |
|
|
||||||
| `downloadDashboardsImage.pullPolicy` | Curl docker image pull policy | `IfNotPresent` |
|
|
||||||
| `namespaceOverride` | Override the deployment namespace | `""` (`Release.Namespace`) |
|
|
||||||
| `serviceMonitor.enabled` | Use servicemonitor from prometheus operator | `false` |
|
|
||||||
| `serviceMonitor.namespace` | Namespace this servicemonitor is installed in | |
|
|
||||||
| `serviceMonitor.interval` | How frequently Prometheus should scrape | `1m` |
|
|
||||||
| `serviceMonitor.path` | Path to scrape | `/metrics` |
|
|
||||||
| `serviceMonitor.scheme` | Scheme to use for metrics scraping | `http` |
|
|
||||||
| `serviceMonitor.tlsConfig` | TLS configuration block for the endpoint | `{}` |
|
|
||||||
| `serviceMonitor.labels` | Labels for the servicemonitor passed to Prometheus Operator | `{}` |
|
|
||||||
| `serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `30s` |
|
|
||||||
| `serviceMonitor.relabelings` | MetricRelabelConfigs to apply to samples before ingestion. | `[]` |
|
|
||||||
| `revisionHistoryLimit` | Number of old ReplicaSets to retain | `10` |
|
|
||||||
| `imageRenderer.enabled` | Enable the image-renderer deployment & service | `false` |
|
|
||||||
| `imageRenderer.image.repository` | image-renderer Image repository | `grafana/grafana-image-renderer` |
|
|
||||||
| `imageRenderer.image.tag` | image-renderer Image tag | `latest` |
|
|
||||||
| `imageRenderer.image.sha` | image-renderer Image sha (optional) | `""` |
|
|
||||||
| `imageRenderer.image.pullPolicy` | image-renderer ImagePullPolicy | `Always` |
|
|
||||||
| `imageRenderer.env` | extra env-vars for image-renderer | `{}` |
|
|
||||||
| `imageRenderer.envValueFrom` | Environment variables for image-renderer from alternate sources. See the API docs on [EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core) for format details. Can be templated | `{}` |
|
|
||||||
| `imageRenderer.serviceAccountName` | image-renderer deployment serviceAccountName | `""` |
|
|
||||||
| `imageRenderer.securityContext` | image-renderer deployment securityContext | `{}` |
|
|
||||||
| `imageRenderer.hostAliases` | image-renderer deployment Host Aliases | `[]` |
|
|
||||||
| `imageRenderer.priorityClassName` | image-renderer deployment priority class | `''` |
|
|
||||||
| `imageRenderer.service.enabled` | Enable the image-renderer service | `true` |
|
|
||||||
| `imageRenderer.service.portName` | image-renderer service port name | `http` |
|
|
||||||
| `imageRenderer.service.port` | image-renderer port used by deployment | `8081` |
|
|
||||||
| `imageRenderer.service.targetPort` | image-renderer service port used by service | `8081` |
|
|
||||||
| `imageRenderer.appProtocol` | Adds the appProtocol field to the service | `` |
|
|
||||||
| `imageRenderer.grafanaSubPath` | Grafana sub path to use for image renderer callback url | `''` |
|
|
||||||
| `imageRenderer.podPortName` | name of the image-renderer port on the pod | `http` |
|
|
||||||
| `imageRenderer.revisionHistoryLimit` | number of image-renderer replica sets to keep | `10` |
|
|
||||||
| `imageRenderer.networkPolicy.limitIngress` | Enable a NetworkPolicy to limit inbound traffic from only the created grafana pods | `true` |
|
|
||||||
| `imageRenderer.networkPolicy.limitEgress` | Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods | `false` |
|
|
||||||
| `imageRenderer.resources` | Set resource limits for image-renderer pods | `{}` |
|
|
||||||
| `imageRenderer.nodeSelector` | Node labels for pod assignment | `{}` |
|
|
||||||
| `imageRenderer.tolerations` | Toleration labels for pod assignment | `[]` |
|
|
||||||
| `imageRenderer.affinity` | Affinity settings for pod assignment | `{}` |
|
|
||||||
| `networkPolicy.enabled` | Enable creation of NetworkPolicy resources. | `false` |
|
|
||||||
| `networkPolicy.allowExternal` | Don't require client label for connections | `true` |
|
|
||||||
| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed | `{}` |
|
|
||||||
| `networkPolicy.ingress` | Enable the creation of an ingress network policy | `true` |
|
|
||||||
| `networkPolicy.egress.enabled` | Enable the creation of an egress network policy | `false` |
|
|
||||||
| `networkPolicy.egress.ports` | An array of ports to allow for the egress | `[]` |
|
|
||||||
| `enableKubeBackwardCompatibility` | Enable backward compatibility of kubernetes where pod's defintion version below 1.13 doesn't have the enableServiceLinks option | `false` |
|
|
||||||
|
|
||||||
### Example ingress with path
|
|
||||||
|
|
||||||
With grafana 6.3 and above
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
grafana.ini:
|
|
||||||
server:
|
|
||||||
domain: monitoring.example.com
|
|
||||||
root_url: "%(protocol)s://%(domain)s/grafana"
|
|
||||||
serve_from_sub_path: true
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
hosts:
|
|
||||||
- "monitoring.example.com"
|
|
||||||
path: "/grafana"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example of extraVolumeMounts
|
|
||||||
|
|
||||||
Volume can be type persistentVolumeClaim or hostPath but not both at same time.
|
|
||||||
If neither existingClaim or hostPath argument is given then type is emptyDir.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- extraVolumeMounts:
|
|
||||||
- name: plugins
|
|
||||||
mountPath: /var/lib/grafana/plugins
|
|
||||||
subPath: configs/grafana/plugins
|
|
||||||
existingClaim: existing-grafana-claim
|
|
||||||
readOnly: false
|
|
||||||
- name: dashboards
|
|
||||||
mountPath: /var/lib/grafana/dashboards
|
|
||||||
hostPath: /usr/shared/grafana/dashboards
|
|
||||||
readOnly: false
|
|
||||||
```
|
|
||||||
|
|
||||||
## Import dashboards
|
|
||||||
|
|
||||||
There are a few methods to import dashboards to Grafana. Below are some examples and explanations as to how to use each method:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
dashboards:
|
|
||||||
default:
|
|
||||||
some-dashboard:
|
|
||||||
json: |
|
|
||||||
{
|
|
||||||
"annotations":
|
|
||||||
|
|
||||||
...
|
|
||||||
# Complete json file here
|
|
||||||
...
|
|
||||||
|
|
||||||
"title": "Some Dashboard",
|
|
||||||
"uid": "abcd1234",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
custom-dashboard:
|
|
||||||
# This is a path to a file inside the dashboards directory inside the chart directory
|
|
||||||
file: dashboards/custom-dashboard.json
|
|
||||||
prometheus-stats:
|
|
||||||
# Ref: https://grafana.com/dashboards/2
|
|
||||||
gnetId: 2
|
|
||||||
revision: 2
|
|
||||||
datasource: Prometheus
|
|
||||||
loki-dashboard-quick-search:
|
|
||||||
gnetId: 12019
|
|
||||||
revision: 2
|
|
||||||
datasource:
|
|
||||||
- name: DS_PROMETHEUS
|
|
||||||
value: Prometheus
|
|
||||||
- name: DS_LOKI
|
|
||||||
value: Loki
|
|
||||||
local-dashboard:
|
|
||||||
url: https://raw.githubusercontent.com/user/repository/master/dashboards/dashboard.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## BASE64 dashboards
|
|
||||||
|
|
||||||
Dashboards could be stored on a server that does not return JSON directly and instead of it returns a Base64 encoded file (e.g. Gerrit)
|
|
||||||
A new parameter has been added to the url use case so if you specify a b64content value equals to true after the url entry a Base64 decoding is applied before save the file to disk.
|
|
||||||
If this entry is not set or is equals to false not decoding is applied to the file before saving it to disk.
|
|
||||||
|
|
||||||
### Gerrit use case
|
|
||||||
|
|
||||||
Gerrit API for download files has the following schema: <https://yourgerritserver/a/{project-name}/branches/{branch-id}/files/{file-id}/content> where {project-name} and
|
|
||||||
{file-id} usually has '/' in their values and so they MUST be replaced by %2F so if project-name is user/repo, branch-id is master and file-id is equals to dir1/dir2/dashboard
|
|
||||||
the url value is <https://yourgerritserver/a/user%2Frepo/branches/master/files/dir1%2Fdir2%2Fdashboard/content>
|
|
||||||
|
|
||||||
## Sidecar for dashboards
|
|
||||||
|
|
||||||
If the parameter `sidecar.dashboards.enabled` is set, a sidecar container is deployed in the grafana
|
|
||||||
pod. This container watches all configmaps (or secrets) in the cluster and filters out the ones with
|
|
||||||
a label as defined in `sidecar.dashboards.label`. The files defined in those configmaps are written
|
|
||||||
to a folder and accessed by grafana. Changes to the configmaps are monitored and the imported
|
|
||||||
dashboards are deleted/updated.
|
|
||||||
|
|
||||||
A recommendation is to use one configmap per dashboard, as a reduction of multiple dashboards inside
|
|
||||||
one configmap is currently not properly mirrored in grafana.
|
|
||||||
|
|
||||||
Example dashboard config:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: sample-grafana-dashboard
|
|
||||||
labels:
|
|
||||||
grafana_dashboard: "1"
|
|
||||||
data:
|
|
||||||
k8s-dashboard.json: |-
|
|
||||||
[...]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sidecar for datasources
|
|
||||||
|
|
||||||
If the parameter `sidecar.datasources.enabled` is set, an init container is deployed in the grafana
|
|
||||||
pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and
|
|
||||||
filters out the ones with a label as defined in `sidecar.datasources.label`. The files defined in
|
|
||||||
those secrets are written to a folder and accessed by grafana on startup. Using these yaml files,
|
|
||||||
the data sources in grafana can be imported.
|
|
||||||
|
|
||||||
Should you aim for reloading datasources in Grafana each time the config is changed, set `sidecar.datasources.skipReload: false` and adjust `sidecar.datasources.reloadURL` to `http://<svc-name>.<namespace>.svc.cluster.local/api/admin/provisioning/datasources/reload`.
|
|
||||||
|
|
||||||
Secrets are recommended over configmaps for this usecase because datasources usually contain private
|
|
||||||
data like usernames and passwords. Secrets are the more appropriate cluster resource to manage those.
|
|
||||||
|
|
||||||
Example values to add a postgres datasource as a kubernetes secret:
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: grafana-datasources
|
|
||||||
labels:
|
|
||||||
grafana_datasource: 'true' # default value for: sidecar.datasources.label
|
|
||||||
stringData:
|
|
||||||
pg-db.yaml: |-
|
|
||||||
apiVersion: 1
|
|
||||||
datasources:
|
|
||||||
- name: My pg db datasource
|
|
||||||
type: postgres
|
|
||||||
url: my-postgresql-db:5432
|
|
||||||
user: db-readonly-user
|
|
||||||
secureJsonData:
|
|
||||||
password: 'SUperSEcretPa$$word'
|
|
||||||
jsonData:
|
|
||||||
database: my_datase
|
|
||||||
sslmode: 'disable' # disable/require/verify-ca/verify-full
|
|
||||||
maxOpenConns: 0 # Grafana v5.4+
|
|
||||||
maxIdleConns: 2 # Grafana v5.4+
|
|
||||||
connMaxLifetime: 14400 # Grafana v5.4+
|
|
||||||
postgresVersion: 1000 # 903=9.3, 904=9.4, 905=9.5, 906=9.6, 1000=10
|
|
||||||
timescaledb: false
|
|
||||||
# <bool> allow users to edit datasources from the UI.
|
|
||||||
editable: false
|
|
||||||
```
|
|
||||||
|
|
||||||
Example values to add a datasource adapted from [Grafana](http://docs.grafana.org/administration/provisioning/#example-datasource-config-file):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
datasources:
|
|
||||||
datasources.yaml:
|
|
||||||
apiVersion: 1
|
|
||||||
datasources:
|
|
||||||
# <string, required> name of the datasource. Required
|
|
||||||
- name: Graphite
|
|
||||||
# <string, required> datasource type. Required
|
|
||||||
type: graphite
|
|
||||||
# <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
|
|
||||||
access: proxy
|
|
||||||
# <int> org id. will default to orgId 1 if not specified
|
|
||||||
orgId: 1
|
|
||||||
# <string> url
|
|
||||||
url: http://localhost:8080
|
|
||||||
# <string> database password, if used
|
|
||||||
password:
|
|
||||||
# <string> database user, if used
|
|
||||||
user:
|
|
||||||
# <string> database name, if used
|
|
||||||
database:
|
|
||||||
# <bool> enable/disable basic auth
|
|
||||||
basicAuth:
|
|
||||||
# <string> basic auth username
|
|
||||||
basicAuthUser:
|
|
||||||
# <string> basic auth password
|
|
||||||
basicAuthPassword:
|
|
||||||
# <bool> enable/disable with credentials headers
|
|
||||||
withCredentials:
|
|
||||||
# <bool> mark as default datasource. Max one per org
|
|
||||||
isDefault:
|
|
||||||
# <map> fields that will be converted to json and stored in json_data
|
|
||||||
jsonData:
|
|
||||||
graphiteVersion: "1.1"
|
|
||||||
tlsAuth: true
|
|
||||||
tlsAuthWithCACert: true
|
|
||||||
# <string> json object of data that will be encrypted.
|
|
||||||
secureJsonData:
|
|
||||||
tlsCACert: "..."
|
|
||||||
tlsClientCert: "..."
|
|
||||||
tlsClientKey: "..."
|
|
||||||
version: 1
|
|
||||||
# <bool> allow users to edit datasources from the UI.
|
|
||||||
editable: false
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sidecar for notifiers
|
|
||||||
|
|
||||||
If the parameter `sidecar.notifiers.enabled` is set, an init container is deployed in the grafana
|
|
||||||
pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and
|
|
||||||
filters out the ones with a label as defined in `sidecar.notifiers.label`. The files defined in
|
|
||||||
those secrets are written to a folder and accessed by grafana on startup. Using these yaml files,
|
|
||||||
the notification channels in grafana can be imported. The secrets must be created before
|
|
||||||
`helm install` so that the notifiers init container can list the secrets.
|
|
||||||
|
|
||||||
Secrets are recommended over configmaps for this usecase because alert notification channels usually contain
|
|
||||||
private data like SMTP usernames and passwords. Secrets are the more appropriate cluster resource to manage those.
|
|
||||||
|
|
||||||
Example datasource config adapted from [Grafana](https://grafana.com/docs/grafana/latest/administration/provisioning/#alert-notification-channels):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
notifiers:
|
|
||||||
- name: notification-channel-1
|
|
||||||
type: slack
|
|
||||||
uid: notifier1
|
|
||||||
# either
|
|
||||||
org_id: 2
|
|
||||||
# or
|
|
||||||
org_name: Main Org.
|
|
||||||
is_default: true
|
|
||||||
send_reminder: true
|
|
||||||
frequency: 1h
|
|
||||||
disable_resolve_message: false
|
|
||||||
# See `Supported Settings` section for settings supporter for each
|
|
||||||
# alert notification type.
|
|
||||||
settings:
|
|
||||||
recipient: 'XXX'
|
|
||||||
token: 'xoxb'
|
|
||||||
uploadImage: true
|
|
||||||
url: https://slack.com
|
|
||||||
|
|
||||||
delete_notifiers:
|
|
||||||
- name: notification-channel-1
|
|
||||||
uid: notifier1
|
|
||||||
org_id: 2
|
|
||||||
- name: notification-channel-2
|
|
||||||
# default org_id: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Provision alert rules, contact points, notification policies and notification templates
|
|
||||||
|
|
||||||
There are two methods to provision alerting configuration in Grafana. Below are some examples and explanations as to how to use each method:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
alerting:
|
|
||||||
team1-alert-rules.yaml:
|
|
||||||
file: alerting/team1/rules.yaml
|
|
||||||
team2-alert-rules.yaml:
|
|
||||||
file: alerting/team2/rules.yaml
|
|
||||||
team3-alert-rules.yaml:
|
|
||||||
file: alerting/team3/rules.yaml
|
|
||||||
notification-policies.yaml:
|
|
||||||
file: alerting/shared/notification-policies.yaml
|
|
||||||
notification-templates.yaml:
|
|
||||||
file: alerting/shared/notification-templates.yaml
|
|
||||||
contactpoints.yaml:
|
|
||||||
apiVersion: 1
|
|
||||||
contactPoints:
|
|
||||||
- orgId: 1
|
|
||||||
name: Slack channel
|
|
||||||
receivers:
|
|
||||||
- uid: default-receiver
|
|
||||||
type: slack
|
|
||||||
settings:
|
|
||||||
# Webhook URL to be filled in
|
|
||||||
url: ""
|
|
||||||
# We need to escape double curly braces for the tpl function.
|
|
||||||
text: '{{ `{{ template "default.message" . }}` }}'
|
|
||||||
title: '{{ `{{ template "default.title" . }}` }}'
|
|
||||||
```
|
|
||||||
|
|
||||||
There are two possibilities:
|
|
||||||
|
|
||||||
* Inlining the file contents as described in the example `values.yaml` and the official [Grafana documentation](https://grafana.com/docs/grafana/next/alerting/set-up/provision-alerting-resources/file-provisioning/).
|
|
||||||
* Importing a file using a relative path starting from the chart root directory.
|
|
||||||
|
|
||||||
### Important notes on file provisioning
|
|
||||||
|
|
||||||
* The chart supports importing YAML and JSON files.
|
|
||||||
* The filename must be unique, otherwise one volume mount will overwrite the other.
|
|
||||||
* In case of inlining, double curly braces that arise from the Grafana configuration format and are not intended as templates for the chart must be escaped.
|
|
||||||
* The number of total files under `alerting:` is not limited. Each file will end up as a volume mount in the corresponding provisioning folder of the deployed Grafana instance.
|
|
||||||
* The file size for each import is limited by what the function `.Files.Get` can handle, which suffices for most cases.
|
|
||||||
|
|
||||||
## How to serve Grafana with a path prefix (/grafana)
|
|
||||||
|
|
||||||
In order to serve Grafana with a prefix (e.g., <http://example.com/grafana>), add the following to your values.yaml.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
annotations:
|
|
||||||
kubernetes.io/ingress.class: "nginx"
|
|
||||||
nginx.ingress.kubernetes.io/rewrite-target: /$1
|
|
||||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
|
||||||
|
|
||||||
path: /grafana/?(.*)
|
|
||||||
hosts:
|
|
||||||
- k8s.example.dev
|
|
||||||
|
|
||||||
grafana.ini:
|
|
||||||
server:
|
|
||||||
root_url: http://localhost:3000/grafana # this host can be localhost
|
|
||||||
```
|
|
||||||
|
|
||||||
## How to securely reference secrets in grafana.ini
|
|
||||||
|
|
||||||
This example uses Grafana [file providers](https://grafana.com/docs/grafana/latest/administration/configuration/#file-provider) for secret values and the `extraSecretMounts` configuration flag (Additional grafana server secret mounts) to mount the secrets.
|
|
||||||
|
|
||||||
In grafana.ini:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
grafana.ini:
|
|
||||||
[auth.generic_oauth]
|
|
||||||
enabled = true
|
|
||||||
client_id = $__file{/etc/secrets/auth_generic_oauth/client_id}
|
|
||||||
client_secret = $__file{/etc/secrets/auth_generic_oauth/client_secret}
|
|
||||||
```
|
|
||||||
|
|
||||||
Existing secret, or created along with helm:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: auth-generic-oauth-secret
|
|
||||||
type: Opaque
|
|
||||||
stringData:
|
|
||||||
client_id: <value>
|
|
||||||
client_secret: <value>
|
|
||||||
```
|
|
||||||
|
|
||||||
Include in the `extraSecretMounts` configuration flag:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- extraSecretMounts:
|
|
||||||
- name: auth-generic-oauth-secret-mount
|
|
||||||
secretName: auth-generic-oauth-secret
|
|
||||||
defaultMode: 0440
|
|
||||||
mountPath: /etc/secrets/auth_generic_oauth
|
|
||||||
readOnly: true
|
|
||||||
```
|
|
||||||
|
|
||||||
### extraSecretMounts using a Container Storage Interface (CSI) provider
|
|
||||||
|
|
||||||
This example uses a CSI driver e.g. retrieving secrets using [Azure Key Vault Provider](https://github.com/Azure/secrets-store-csi-driver-provider-azure)
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- extraSecretMounts:
|
|
||||||
- name: secrets-store-inline
|
|
||||||
mountPath: /run/secrets
|
|
||||||
readOnly: true
|
|
||||||
csi:
|
|
||||||
driver: secrets-store.csi.k8s.io
|
|
||||||
readOnly: true
|
|
||||||
volumeAttributes:
|
|
||||||
secretProviderClass: "my-provider"
|
|
||||||
nodePublishSecretRef:
|
|
||||||
name: akv-creds
|
|
||||||
```
|
|
||||||
|
|
||||||
## Image Renderer Plug-In
|
|
||||||
|
|
||||||
This chart supports enabling [remote image rendering](https://github.com/grafana/grafana-image-renderer/blob/master/README.md#run-in-docker)
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
imageRenderer:
|
|
||||||
enabled: true
|
|
||||||
```
|
|
||||||
|
|
||||||
### Image Renderer NetworkPolicy
|
|
||||||
|
|
||||||
By default the image-renderer pods will have a network policy which only allows ingress traffic from the created grafana instance
|
|
||||||
|
|
||||||
### High Availability for unified alerting
|
|
||||||
|
|
||||||
If you want to run Grafana in a high availability cluster you need to enable
|
|
||||||
the headless service by setting `headlessService: true` in your `values.yaml`
|
|
||||||
file.
|
|
||||||
|
|
||||||
As next step you have to setup the `grafana.ini` in your `values.yaml` in a way
|
|
||||||
that it will make use of the headless service to obtain all the IPs of the
|
|
||||||
cluster. You should replace ``{{ Name }}`` with the name of your helm deployment.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
grafana.ini:
|
|
||||||
...
|
|
||||||
unified_alerting:
|
|
||||||
enabled: true
|
|
||||||
ha_peers: {{ Name }}-headless:9094
|
|
||||||
ha_listen_address: ${POD_IP}:9094
|
|
||||||
ha_advertise_address: ${POD_IP}:9094
|
|
||||||
|
|
||||||
alerting:
|
|
||||||
enabled: false
|
|
||||||
```
|
|
||||||
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
affinity:
|
|
||||||
podAntiAffinity:
|
|
||||||
preferredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
- podAffinityTerm:
|
|
||||||
labelSelector:
|
|
||||||
matchLabels:
|
|
||||||
app.kubernetes.io/instance: grafana-test
|
|
||||||
app.kubernetes.io/name: grafana
|
|
||||||
topologyKey: failure-domain.beta.kubernetes.io/zone
|
|
||||||
weight: 100
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
- labelSelector:
|
|
||||||
matchLabels:
|
|
||||||
app.kubernetes.io/instance: grafana-test
|
|
||||||
app.kubernetes.io/name: grafana
|
|
||||||
topologyKey: kubernetes.io/hostname
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
dashboards:
|
|
||||||
my-provider:
|
|
||||||
my-awesome-dashboard:
|
|
||||||
# An empty but valid dashboard
|
|
||||||
json: |
|
|
||||||
{
|
|
||||||
"__inputs": [],
|
|
||||||
"__requires": [
|
|
||||||
{
|
|
||||||
"type": "grafana",
|
|
||||||
"id": "grafana",
|
|
||||||
"name": "Grafana",
|
|
||||||
"version": "6.3.5"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"annotations": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"builtIn": 1,
|
|
||||||
"datasource": "-- Grafana --",
|
|
||||||
"enable": true,
|
|
||||||
"hide": true,
|
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
|
||||||
"name": "Annotations & Alerts",
|
|
||||||
"type": "dashboard"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"editable": true,
|
|
||||||
"gnetId": null,
|
|
||||||
"graphTooltip": 0,
|
|
||||||
"id": null,
|
|
||||||
"links": [],
|
|
||||||
"panels": [],
|
|
||||||
"schemaVersion": 19,
|
|
||||||
"style": "dark",
|
|
||||||
"tags": [],
|
|
||||||
"templating": {
|
|
||||||
"list": []
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"from": "now-6h",
|
|
||||||
"to": "now"
|
|
||||||
},
|
|
||||||
"timepicker": {
|
|
||||||
"refresh_intervals": ["5s"]
|
|
||||||
},
|
|
||||||
"timezone": "",
|
|
||||||
"title": "Dummy Dashboard",
|
|
||||||
"uid": "IdcYQooWk",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
datasource: Prometheus
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
dashboards:
|
|
||||||
my-provider:
|
|
||||||
my-awesome-dashboard:
|
|
||||||
gnetId: 10000
|
|
||||||
revision: 1
|
|
||||||
datasource: Prometheus
|
|
||||||
dashboardProviders:
|
|
||||||
dashboardproviders.yaml:
|
|
||||||
apiVersion: 1
|
|
||||||
providers:
|
|
||||||
- name: 'my-provider'
|
|
||||||
orgId: 1
|
|
||||||
folder: ''
|
|
||||||
type: file
|
|
||||||
updateIntervalSeconds: 10
|
|
||||||
disableDeletion: true
|
|
||||||
editable: true
|
|
||||||
options:
|
|
||||||
path: /var/lib/grafana/dashboards/my-provider
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
extraConfigmapMounts:
|
|
||||||
- name: '{{ include "grafana.fullname" . }}'
|
|
||||||
configMap: '{{ include "grafana.fullname" . }}'
|
|
||||||
mountPath: /var/lib/grafana/dashboards/test-dashboard.json
|
|
||||||
# This is not a realistic test, but for this we only care about extraConfigmapMounts not being empty and pointing to an existing ConfigMap
|
|
||||||
subPath: grafana.ini
|
|
||||||
readOnly: true
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
podLabels:
|
|
||||||
customLableA: Aaaaa
|
|
||||||
imageRenderer:
|
|
||||||
enabled: true
|
|
||||||
env:
|
|
||||||
RENDERING_ARGS: --disable-gpu,--window-size=1280x758
|
|
||||||
RENDERING_MODE: clustered
|
|
||||||
podLabels:
|
|
||||||
customLableB: Bbbbb
|
|
||||||
networkPolicy:
|
|
||||||
limitIngress: true
|
|
||||||
limitEgress: true
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpu: 1000m
|
|
||||||
memory: 1000Mi
|
|
||||||
requests:
|
|
||||||
cpu: 500m
|
|
||||||
memory: 50Mi
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
persistence:
|
|
||||||
type: pvc
|
|
||||||
enabled: true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
1. Get your '{{ .Values.adminUser }}' user password by running:
|
|
||||||
|
|
||||||
kubectl get secret --namespace {{ include "grafana.namespace" . }} {{ .Values.admin.existingSecret | default (include "grafana.fullname" .) }} -o jsonpath="{.data.{{ .Values.admin.passwordKey | default "admin-password" }}}" | base64 --decode ; echo
|
|
||||||
|
|
||||||
|
|
||||||
2. The Grafana server can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster:
|
|
||||||
|
|
||||||
{{ include "grafana.fullname" . }}.{{ include "grafana.namespace" . }}.svc.cluster.local
|
|
||||||
{{ if .Values.ingress.enabled }}
|
|
||||||
If you bind grafana to 80, please update values in values.yaml and reinstall:
|
|
||||||
```
|
|
||||||
securityContext:
|
|
||||||
runAsUser: 0
|
|
||||||
runAsGroup: 0
|
|
||||||
fsGroup: 0
|
|
||||||
|
|
||||||
command:
|
|
||||||
- "setcap"
|
|
||||||
- "'cap_net_bind_service=+ep'"
|
|
||||||
- "/usr/sbin/grafana-server &&"
|
|
||||||
- "sh"
|
|
||||||
- "/run.sh"
|
|
||||||
```
|
|
||||||
Details refer to https://grafana.com/docs/installation/configuration/#http-port.
|
|
||||||
Or grafana would always crash.
|
|
||||||
|
|
||||||
From outside the cluster, the server URL(s) are:
|
|
||||||
{{- range .Values.ingress.hosts }}
|
|
||||||
http://{{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
Get the Grafana URL to visit by running these commands in the same shell:
|
|
||||||
{{- if contains "NodePort" .Values.service.type }}
|
|
||||||
export NODE_PORT=$(kubectl get --namespace {{ include "grafana.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "grafana.fullname" . }})
|
|
||||||
export NODE_IP=$(kubectl get nodes --namespace {{ include "grafana.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
|
||||||
echo http://$NODE_IP:$NODE_PORT
|
|
||||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
|
||||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
|
||||||
You can watch the status of by running 'kubectl get svc --namespace {{ include "grafana.namespace" . }} -w {{ include "grafana.fullname" . }}'
|
|
||||||
export SERVICE_IP=$(kubectl get svc --namespace {{ include "grafana.namespace" . }} {{ include "grafana.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
|
||||||
http://$SERVICE_IP:{{ .Values.service.port -}}
|
|
||||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
|
||||||
export POD_NAME=$(kubectl get pods --namespace {{ include "grafana.namespace" . }} -l "app.kubernetes.io/name={{ include "grafana.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
|
||||||
kubectl --namespace {{ include "grafana.namespace" . }} port-forward $POD_NAME 3000
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
3. Login with the password from step 1 and the username: {{ .Values.adminUser }}
|
|
||||||
|
|
||||||
{{- if not .Values.persistence.enabled }}
|
|
||||||
#################################################################################
|
|
||||||
###### WARNING: Persistence is disabled!!! You will lose your data when #####
|
|
||||||
###### the Grafana pod is terminated. #####
|
|
||||||
#################################################################################
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
{{/* vim: set filetype=mustache: */}}
|
|
||||||
{{/*
|
|
||||||
Expand the name of the chart.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.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 "grafana.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 }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Maintainer - Akshay Gupta
|
|
||||||
Tolerations and nodeSelector via Resources Requests.
|
|
||||||
*/}}
|
|
||||||
{{- define "meesho.grafana.getCpu" -}}
|
|
||||||
{{- $cpu := toString .Values.resources.requests.cpu -}}
|
|
||||||
{{- if contains "m" $cpu -}}
|
|
||||||
{{- $cpu := trimAll "m" $cpu | float64 -}}
|
|
||||||
{{- $cpu := $cpu | float64 -}}
|
|
||||||
{{- printf "%f" $cpu -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $cpu := mulf $cpu 1000.000 -}}
|
|
||||||
{{- printf "%f" $cpu -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "meesho.grafana.getMem" -}}
|
|
||||||
{{- $mem := toString .Values.resources.requests.memory -}}
|
|
||||||
{{- if contains "Mi" $mem -}}
|
|
||||||
{{- $mem := trimAll "Mi" $mem | float64 -}}
|
|
||||||
{{- printf "%f" $mem -}}
|
|
||||||
{{- else if contains "Gi" $mem -}}
|
|
||||||
{{- $mem := trimAll "Gi" $mem | float64 -}}
|
|
||||||
{{- $mem := mulf $mem 1024.000 -}}
|
|
||||||
{{- printf "%f" $mem -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "meesho.grafana.getRatio" -}}
|
|
||||||
{{- $cpu := (include "meesho.grafana.getCpu" .) -}}
|
|
||||||
{{- $mem := (include "meesho.grafana.getMem" .) -}}
|
|
||||||
{{- $ratio := divf $mem $cpu -}}
|
|
||||||
{{- if gt $ratio 4.00 -}}
|
|
||||||
{{- printf "1to8" -}}
|
|
||||||
{{- else if gt $ratio 2.00 -}}
|
|
||||||
{{- printf "1to4" -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "1to2" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "meesho.grafana.dedicatedValue" -}}
|
|
||||||
{{- if (index .Values.extraLabels "arch") -}}
|
|
||||||
{{- if (index .Values.extraLabels "runpod") -}}
|
|
||||||
{{- $cpu := (include "meesho.grafana.getCpu" .) -}}
|
|
||||||
{{- $mem := (include "meesho.grafana.getMem" .) -}}
|
|
||||||
{{- $ratio := (include "meesho.grafana.getRatio" .) -}}
|
|
||||||
{{- $arch := .Values.extraLabels.arch -}}
|
|
||||||
{{- $runPod := .Values.extraLabels.runpod -}}
|
|
||||||
{{- printf "%s-%s-%s" $ratio $arch $runPod -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "missing-runpod-label" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "missing-arch-label" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create chart name and version as used by the chart label.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create the name of the service account
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.serviceAccountName" -}}
|
|
||||||
{{- if .Values.serviceAccount.create }}
|
|
||||||
{{- default (include "grafana.fullname" .) .Values.serviceAccount.name }}
|
|
||||||
{{- else }}
|
|
||||||
{{- default "default" .Values.serviceAccount.name }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "grafana.serviceAccountNameTest" -}}
|
|
||||||
{{- if .Values.serviceAccount.create }}
|
|
||||||
{{- default (print (include "grafana.fullname" .) "-test") .Values.serviceAccount.nameTest }}
|
|
||||||
{{- else }}
|
|
||||||
{{- default "default" .Values.serviceAccount.nameTest }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Allow the release namespace to be overridden for multi-namespace deployments in combined charts
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.namespace" -}}
|
|
||||||
{{- if .Values.namespaceOverride }}
|
|
||||||
{{- .Values.namespaceOverride }}
|
|
||||||
{{- else }}
|
|
||||||
{{- .Release.Namespace }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Common labels
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.labels" -}}
|
|
||||||
helm.sh/chart: {{ include "grafana.chart" . }}
|
|
||||||
{{ include "grafana.selectorLabels" . }}
|
|
||||||
{{- if or .Chart.AppVersion .Values.image.tag }}
|
|
||||||
app.kubernetes.io/version: {{ mustRegexReplaceAllLiteral "@sha.*" .Values.image.tag "" | default .Chart.AppVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
||||||
{{- with .Values.extraLabels }}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Selector labels
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ include "grafana.name" . }}
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Common labels
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.imageRenderer.labels" -}}
|
|
||||||
helm.sh/chart: {{ include "grafana.chart" . }}
|
|
||||||
{{ include "grafana.imageRenderer.selectorLabels" . }}
|
|
||||||
{{- if or .Chart.AppVersion .Values.image.tag }}
|
|
||||||
app.kubernetes.io/version: {{ mustRegexReplaceAllLiteral "@sha.*" .Values.image.tag "" | default .Chart.AppVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Selector labels ImageRenderer
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.imageRenderer.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ include "grafana.name" . }}-image-renderer
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Looks if there's an existing secret and reuse its password. If not it generates
|
|
||||||
new password and use it.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.password" -}}
|
|
||||||
{{- $secret := (lookup "v1" "Secret" (include "grafana.namespace" .) (include "grafana.fullname" .) ) }}
|
|
||||||
{{- if $secret }}
|
|
||||||
{{- index $secret "data" "admin-password" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- (randAlphaNum 40) | b64enc | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return the appropriate apiVersion for rbac.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.rbac.apiVersion" -}}
|
|
||||||
{{- if $.Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" }}
|
|
||||||
{{- print "rbac.authorization.k8s.io/v1" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- print "rbac.authorization.k8s.io/v1beta1" }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return the appropriate apiVersion for ingress.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.ingress.apiVersion" -}}
|
|
||||||
{{- if and ($.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" .Capabilities.KubeVersion.Version) }}
|
|
||||||
{{- print "networking.k8s.io/v1" }}
|
|
||||||
{{- else if $.Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
|
|
||||||
{{- print "networking.k8s.io/v1beta1" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- print "extensions/v1beta1" }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return the appropriate apiVersion for Horizontal Pod Autoscaler.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.hpa.apiVersion" -}}
|
|
||||||
{{- if $.Capabilities.APIVersions.Has "autoscaling/v2/HorizontalPodAutoscaler" }}
|
|
||||||
{{- print "autoscaling/v2" }}
|
|
||||||
{{- else if $.Capabilities.APIVersions.Has "autoscaling/v2beta2/HorizontalPodAutoscaler" }}
|
|
||||||
{{- print "autoscaling/v2beta2" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- print "autoscaling/v2beta1" }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return the appropriate apiVersion for podDisruptionBudget.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.podDisruptionBudget.apiVersion" -}}
|
|
||||||
{{- if $.Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }}
|
|
||||||
{{- print "policy/v1" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- print "policy/v1beta1" }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return if ingress is stable.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.ingress.isStable" -}}
|
|
||||||
{{- eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return if ingress supports ingressClassName.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.ingress.supportsIngressClassName" -}}
|
|
||||||
{{- or (eq (include "grafana.ingress.isStable" .) "true") (and (eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return if ingress supports pathType.
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.ingress.supportsPathType" -}}
|
|
||||||
{{- or (eq (include "grafana.ingress.isStable" .) "true") (and (eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Formats imagePullSecrets. Input is (dict "root" . "imagePullSecrets" .{specific imagePullSecrets})
|
|
||||||
*/}}
|
|
||||||
{{- define "grafana.imagePullSecrets" -}}
|
|
||||||
{{- $root := .root }}
|
|
||||||
{{- range (concat .root.Values.global.imagePullSecrets .imagePullSecrets) }}
|
|
||||||
{{- if eq (typeOf .) "map[string]interface {}" }}
|
|
||||||
- {{ toYaml (dict "name" (tpl .name $root)) | trim }}
|
|
||||||
{{- else }}
|
|
||||||
- name: {{ tpl . $root }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
{{- if and .Values.rbac.create (or (not .Values.rbac.namespaced) .Values.rbac.extraClusterRoleRules) (not .Values.rbac.useExistingRole) }}
|
|
||||||
kind: ClusterRole
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
name: {{ include "grafana.fullname" . }}-clusterrole
|
|
||||||
{{- if or .Values.sidecar.dashboards.enabled .Values.rbac.extraClusterRoleRules .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled .Values.sidecar.alerts.enabled }}
|
|
||||||
rules:
|
|
||||||
{{- if or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled .Values.sidecar.alerts.enabled }}
|
|
||||||
- apiGroups: [""] # "" indicates the core API group
|
|
||||||
resources: ["configmaps", "secrets"]
|
|
||||||
verbs: ["get", "watch", "list"]
|
|
||||||
{{- end}}
|
|
||||||
{{- with .Values.rbac.extraClusterRoleRules }}
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end}}
|
|
||||||
{{- else }}
|
|
||||||
rules: []
|
|
||||||
{{- end}}
|
|
||||||
{{- end}}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{{- if and .Values.rbac.create (or (not .Values.rbac.namespaced) .Values.rbac.extraClusterRoleRules) }}
|
|
||||||
kind: ClusterRoleBinding
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-clusterrolebinding
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: {{ include "grafana.serviceAccountName" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
roleRef:
|
|
||||||
kind: ClusterRole
|
|
||||||
{{- if .Values.rbac.useExistingRole }}
|
|
||||||
name: {{ .Values.rbac.useExistingRole }}
|
|
||||||
{{- else }}
|
|
||||||
name: {{ include "grafana.fullname" . }}-clusterrole
|
|
||||||
{{- end }}
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{{- if and .Values.sidecar.dashboards.enabled .Values.sidecar.dashboards.SCProvider }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
name: {{ include "grafana.fullname" . }}-config-dashboards
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
data:
|
|
||||||
provider.yaml: |-
|
|
||||||
apiVersion: 1
|
|
||||||
providers:
|
|
||||||
- name: '{{ .Values.sidecar.dashboards.provider.name }}'
|
|
||||||
orgId: {{ .Values.sidecar.dashboards.provider.orgid }}
|
|
||||||
{{- if not .Values.sidecar.dashboards.provider.foldersFromFilesStructure }}
|
|
||||||
folder: '{{ .Values.sidecar.dashboards.provider.folder }}'
|
|
||||||
{{- end }}
|
|
||||||
type: {{ .Values.sidecar.dashboards.provider.type }}
|
|
||||||
disableDeletion: {{ .Values.sidecar.dashboards.provider.disableDelete }}
|
|
||||||
allowUiUpdates: {{ .Values.sidecar.dashboards.provider.allowUiUpdates }}
|
|
||||||
updateIntervalSeconds: {{ .Values.sidecar.dashboards.provider.updateIntervalSeconds | default 30 }}
|
|
||||||
options:
|
|
||||||
foldersFromFilesStructure: {{ .Values.sidecar.dashboards.provider.foldersFromFilesStructure }}
|
|
||||||
path: {{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
{{- if .Values.createConfigmap }}
|
|
||||||
{{- $files := .Files }}
|
|
||||||
{{- $root := . -}}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
data:
|
|
||||||
{{- with .Values.plugins }}
|
|
||||||
plugins: {{ join "," . }}
|
|
||||||
{{- end }}
|
|
||||||
grafana.ini: |
|
|
||||||
{{- range $elem, $elemVal := index .Values "grafana.ini" }}
|
|
||||||
{{- if not (kindIs "map" $elemVal) }}
|
|
||||||
{{- if kindIs "invalid" $elemVal }}
|
|
||||||
{{ $elem }} =
|
|
||||||
{{- else if kindIs "string" $elemVal }}
|
|
||||||
{{ $elem }} = {{ tpl $elemVal $ }}
|
|
||||||
{{- else }}
|
|
||||||
{{ $elem }} = {{ $elemVal }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $key, $value := index .Values "grafana.ini" }}
|
|
||||||
{{- if kindIs "map" $value }}
|
|
||||||
[{{ $key }}]
|
|
||||||
{{- range $elem, $elemVal := $value }}
|
|
||||||
{{- if kindIs "invalid" $elemVal }}
|
|
||||||
{{ $elem }} =
|
|
||||||
{{- else if kindIs "string" $elemVal }}
|
|
||||||
{{ $elem }} = {{ tpl $elemVal $ }}
|
|
||||||
{{- else }}
|
|
||||||
{{ $elem }} = {{ $elemVal }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- range $key, $value := .Values.datasources }}
|
|
||||||
{{- $key | nindent 2 }}: |
|
|
||||||
{{- tpl (toYaml $value | nindent 4) $root }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- range $key, $value := .Values.notifiers }}
|
|
||||||
{{- $key | nindent 2 }}: |
|
|
||||||
{{- toYaml $value | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- range $key, $value := .Values.alerting }}
|
|
||||||
{{- if (hasKey $value "file") }}
|
|
||||||
{{- $key | nindent 2 }}:
|
|
||||||
{{- toYaml ( $files.Get $value.file ) | nindent 4}}
|
|
||||||
{{- else }}
|
|
||||||
{{- $key | nindent 2 }}: |
|
|
||||||
{{- tpl (toYaml $value | nindent 4) $root }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- range $key, $value := .Values.dashboardProviders }}
|
|
||||||
{{- $key | nindent 2 }}: |
|
|
||||||
{{- toYaml $value | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- if .Values.dashboards }}
|
|
||||||
download_dashboards.sh: |
|
|
||||||
#!/usr/bin/env sh
|
|
||||||
set -euf
|
|
||||||
{{- if .Values.dashboardProviders }}
|
|
||||||
{{- range $key, $value := .Values.dashboardProviders }}
|
|
||||||
{{- range $value.providers }}
|
|
||||||
mkdir -p {{ .options.path }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{ $dashboardProviders := .Values.dashboardProviders }}
|
|
||||||
{{- range $provider, $dashboards := .Values.dashboards }}
|
|
||||||
{{- range $key, $value := $dashboards }}
|
|
||||||
{{- if (or (hasKey $value "gnetId") (hasKey $value "url")) }}
|
|
||||||
curl -skf \
|
|
||||||
--connect-timeout 60 \
|
|
||||||
--max-time 60 \
|
|
||||||
{{- if not $value.b64content }}
|
|
||||||
{{- if not $value.acceptHeader }}
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
{{- else }}
|
|
||||||
-H "Accept: {{ $value.acceptHeader }}" \
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.token }}
|
|
||||||
-H "Authorization: token {{ $value.token }}" \
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.bearerToken }}
|
|
||||||
-H "Authorization: Bearer {{ $value.bearerToken }}" \
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.basic }}
|
|
||||||
-H "Authorization: Basic {{ $value.basic }}" \
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.gitlabToken }}
|
|
||||||
-H "PRIVATE-TOKEN: {{ $value.gitlabToken }}" \
|
|
||||||
{{- end }}
|
|
||||||
-H "Content-Type: application/json;charset=UTF-8" \
|
|
||||||
{{- end }}
|
|
||||||
{{- $dpPath := "" -}}
|
|
||||||
{{- range $kd := (index $dashboardProviders "dashboardproviders.yaml").providers }}
|
|
||||||
{{- if eq $kd.name $provider }}
|
|
||||||
{{- $dpPath = $kd.options.path }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.url }}
|
|
||||||
"{{ $value.url }}" \
|
|
||||||
{{- else }}
|
|
||||||
"https://grafana.com/api/dashboards/{{ $value.gnetId }}/revisions/{{- if $value.revision -}}{{ $value.revision }}{{- else -}}1{{- end -}}/download" \
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.datasource }}
|
|
||||||
{{- if kindIs "string" $value.datasource }}
|
|
||||||
| sed '/-- .* --/! s/"datasource":.*,/"datasource": "{{ $value.datasource }}",/g' \
|
|
||||||
{{- end }}
|
|
||||||
{{- if kindIs "slice" $value.datasource }}
|
|
||||||
{{- range $value.datasource }}
|
|
||||||
| sed '/-- .* --/! s/${{"{"}}{{ .name }}}/{{ .value }}/g' \
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if $value.b64content }}
|
|
||||||
| base64 -d \
|
|
||||||
{{- end }}
|
|
||||||
> "{{- if $dpPath -}}{{ $dpPath }}{{- else -}}/var/lib/grafana/dashboards/{{ $provider }}{{- end -}}/{{ $key }}.json"
|
|
||||||
{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{{- if .Values.dashboards }}
|
|
||||||
{{ $files := .Files }}
|
|
||||||
{{- range $provider, $dashboards := .Values.dashboards }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" $ }}-dashboards-{{ $provider }}
|
|
||||||
namespace: {{ include "grafana.namespace" $ }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" $ | nindent 4 }}
|
|
||||||
dashboard-provider: {{ $provider }}
|
|
||||||
{{- if $dashboards }}
|
|
||||||
data:
|
|
||||||
{{- $dashboardFound := false }}
|
|
||||||
{{- range $key, $value := $dashboards }}
|
|
||||||
{{- if (or (hasKey $value "json") (hasKey $value "file")) }}
|
|
||||||
{{- $dashboardFound = true }}
|
|
||||||
{{- print $key | nindent 2 }}.json:
|
|
||||||
{{- if hasKey $value "json" }}
|
|
||||||
|-
|
|
||||||
{{- $value.json | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if hasKey $value "file" }}
|
|
||||||
{{- toYaml ( $files.Get $value.file ) | nindent 4}}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not $dashboardFound }}
|
|
||||||
{}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
{{- if (and (not .Values.useStatefulSet) (or (not .Values.persistence.enabled) (eq .Values.persistence.type "pvc"))) }}
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if and (not .Values.autoscaling.enabled) (.Values.replicas) }}
|
|
||||||
replicas: {{ .Values.replicas }}
|
|
||||||
{{- end }}
|
|
||||||
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 6 }}
|
|
||||||
{{- with .Values.deploymentStrategy }}
|
|
||||||
strategy:
|
|
||||||
{{- toYaml . | trim | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 8 }}
|
|
||||||
{{- with .Values.podLabels }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
annotations:
|
|
||||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
|
||||||
checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }}
|
|
||||||
checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }}
|
|
||||||
{{- if and (or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret))) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
|
|
||||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.envRenderSecret }}
|
|
||||||
checksum/secret-env: {{ include (print $.Template.BasePath "/secret-env.yaml") . | sha256sum }}
|
|
||||||
{{- end }}
|
|
||||||
kubectl.kubernetes.io/default-container: {{ .Chart.Name }}
|
|
||||||
{{- with .Values.podAnnotations }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- include "grafana.pod" . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{{- if .Values.externalSecrets -}}
|
|
||||||
apiVersion: external-secrets.io/v1beta1
|
|
||||||
kind: ExternalSecret
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-secret
|
|
||||||
namespace: "{{ include "grafana.namespace" . }}"
|
|
||||||
spec:
|
|
||||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval }}
|
|
||||||
secretStoreRef:
|
|
||||||
name: {{ .Values.externalSecrets.secretStoreRef.name }}
|
|
||||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind }}
|
|
||||||
target:
|
|
||||||
creationPolicy: Owner
|
|
||||||
deletionPolicy: Retain
|
|
||||||
name: {{ include "grafana.fullname" . }}-secret
|
|
||||||
dataFrom:
|
|
||||||
- extract:
|
|
||||||
conversionStrategy: Default
|
|
||||||
key: {{ .Values.externalSecrets.dataFrom.secretKey }}
|
|
||||||
{{- end -}}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{{ range .Values.extraObjects }}
|
|
||||||
---
|
|
||||||
{{ tpl (toYaml .) $ }}
|
|
||||||
{{ end }}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{{- $sts := list "sts" "StatefulSet" "statefulset" -}}
|
|
||||||
{{- if or .Values.headlessService (and .Values.persistence.enabled (not .Values.persistence.existingClaim) (has .Values.persistence.type $sts)) }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-headless
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
clusterIP: None
|
|
||||||
selector:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 4 }}
|
|
||||||
type: ClusterIP
|
|
||||||
ports:
|
|
||||||
- name: {{ .Values.gossipPortName }}-tcp
|
|
||||||
port: 9094
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{{- $sts := list "sts" "StatefulSet" "statefulset" -}}
|
|
||||||
{{- if .Values.autoscaling.enabled }}
|
|
||||||
apiVersion: {{ include "grafana.hpa.apiVersion" . }}
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/name: {{ include "grafana.name" . }}
|
|
||||||
helm.sh/chart: {{ include "grafana.chart" . }}
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
{{- if has .Values.persistence.type $sts }}
|
|
||||||
kind: StatefulSet
|
|
||||||
{{- else }}
|
|
||||||
kind: Deployment
|
|
||||||
{{- end }}
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
|
||||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
|
||||||
metrics:
|
|
||||||
{{- if .Values.autoscaling.targetMemory }}
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: memory
|
|
||||||
{{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }}
|
|
||||||
targetAverageUtilization: {{ .Values.autoscaling.targetMemory }}
|
|
||||||
{{- else }}
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .Values.autoscaling.targetMemory }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.autoscaling.targetCPU }}
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
{{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }}
|
|
||||||
targetAverageUtilization: {{ .Values.autoscaling.targetCPU }}
|
|
||||||
{{- else }}
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .Values.autoscaling.targetCPU }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.autoscaling.behavior }}
|
|
||||||
behavior: {{ toYaml .Values.autoscaling.behavior | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
{{ if .Values.imageRenderer.enabled }}
|
|
||||||
{{- $root := . -}}
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.imageRenderer.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.imageRenderer.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if and (not .Values.imageRenderer.autoscaling.enabled) (.Values.imageRenderer.replicas) }}
|
|
||||||
replicas: {{ .Values.imageRenderer.replicas }}
|
|
||||||
{{- end }}
|
|
||||||
revisionHistoryLimit: {{ .Values.imageRenderer.revisionHistoryLimit }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
|
|
||||||
|
|
||||||
{{- with .Values.imageRenderer.deploymentStrategy }}
|
|
||||||
strategy:
|
|
||||||
{{- toYaml . | trim | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.imageRenderer.selectorLabels" . | nindent 8 }}
|
|
||||||
{{- with .Values.imageRenderer.podLabels }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
annotations:
|
|
||||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
|
||||||
{{- with .Values.imageRenderer.podAnnotations }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- with .Values.imageRenderer.schedulerName }}
|
|
||||||
schedulerName: "{{ . }}"
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.serviceAccountName }}
|
|
||||||
serviceAccountName: "{{ . }}"
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.securityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.hostAliases }}
|
|
||||||
hostAliases:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.priorityClassName }}
|
|
||||||
priorityClassName: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.image.pullSecrets }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- range . }}
|
|
||||||
- name: {{ tpl . $root }}
|
|
||||||
{{- end}}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ .Chart.Name }}-image-renderer
|
|
||||||
{{- if .Values.imageRenderer.image.sha }}
|
|
||||||
image: "{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}@sha256:{{ .Values.imageRenderer.image.sha }}"
|
|
||||||
{{- else }}
|
|
||||||
image: "{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}"
|
|
||||||
{{- end }}
|
|
||||||
imagePullPolicy: {{ .Values.imageRenderer.image.pullPolicy }}
|
|
||||||
{{- if .Values.imageRenderer.command }}
|
|
||||||
command:
|
|
||||||
{{- range .Values.imageRenderer.command }}
|
|
||||||
- {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end}}
|
|
||||||
ports:
|
|
||||||
- name: {{ .Values.imageRenderer.service.portName }}
|
|
||||||
containerPort: {{ .Values.imageRenderer.service.targetPort }}
|
|
||||||
protocol: TCP
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /
|
|
||||||
port: {{ .Values.imageRenderer.service.portName }}
|
|
||||||
env:
|
|
||||||
- name: HTTP_PORT
|
|
||||||
value: {{ .Values.imageRenderer.service.targetPort | quote }}
|
|
||||||
{{- if .Values.imageRenderer.serviceMonitor.enabled }}
|
|
||||||
- name: ENABLE_METRICS
|
|
||||||
value: "true"
|
|
||||||
{{- end }}
|
|
||||||
{{- range $key, $value := .Values.imageRenderer.envValueFrom }}
|
|
||||||
- name: {{ $key | quote }}
|
|
||||||
valueFrom:
|
|
||||||
{{- tpl (toYaml $value) $ | nindent 16 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $key, $value := .Values.imageRenderer.env }}
|
|
||||||
- name: {{ $key | quote }}
|
|
||||||
value: {{ $value | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.containerSecurityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /tmp
|
|
||||||
name: image-renderer-tmpfs
|
|
||||||
{{- with .Values.imageRenderer.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.nodeSelector }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.affinity }}
|
|
||||||
affinity:
|
|
||||||
{{- tpl (toYaml .) $root | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.tolerations }}
|
|
||||||
tolerations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
volumes:
|
|
||||||
- name: image-renderer-tmpfs
|
|
||||||
emptyDir: {}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.autoscaling.enabled }}
|
|
||||||
apiVersion: {{ include "grafana.hpa.apiVersion" . }}
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/name: {{ include "grafana.name" . }}-image-renderer
|
|
||||||
helm.sh/chart: {{ include "grafana.chart" . }}
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer
|
|
||||||
minReplicas: {{ .Values.imageRenderer.autoscaling.minReplicas }}
|
|
||||||
maxReplicas: {{ .Values.imageRenderer.autoscaling.maxReplicas }}
|
|
||||||
metrics:
|
|
||||||
{{- if .Values.imageRenderer.autoscaling.targetMemory }}
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: memory
|
|
||||||
{{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }}
|
|
||||||
targetAverageUtilization: {{ .Values.imageRenderer.autoscaling.targetMemory }}
|
|
||||||
{{- else }}
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .Values.imageRenderer.autoscaling.targetMemory }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.imageRenderer.autoscaling.targetCPU }}
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
{{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }}
|
|
||||||
targetAverageUtilization: {{ .Values.imageRenderer.autoscaling.targetCPU }}
|
|
||||||
{{- else }}
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .Values.imageRenderer.autoscaling.targetCPU }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.imageRenderer.autoscaling.behavior }}
|
|
||||||
behavior: {{ toYaml .Values.imageRenderer.autoscaling.behavior | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.networkPolicy.limitIngress }}
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer-ingress
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
annotations:
|
|
||||||
comment: Limit image-renderer ingress traffic from grafana
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
|
|
||||||
{{- with .Values.imageRenderer.podLabels }}
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
policyTypes:
|
|
||||||
- Ingress
|
|
||||||
ingress:
|
|
||||||
- ports:
|
|
||||||
- port: {{ .Values.imageRenderer.service.targetPort }}
|
|
||||||
protocol: TCP
|
|
||||||
from:
|
|
||||||
- namespaceSelector:
|
|
||||||
matchLabels:
|
|
||||||
kubernetes.io/metadata.name: {{ include "grafana.namespace" . }}
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 14 }}
|
|
||||||
{{- with .Values.podLabels }}
|
|
||||||
{{- toYaml . | nindent 14 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.networkPolicy.extraIngressSelectors -}}
|
|
||||||
{{ toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.networkPolicy.limitEgress }}
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer-egress
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
annotations:
|
|
||||||
comment: Limit image-renderer egress traffic to grafana
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
|
|
||||||
{{- with .Values.imageRenderer.podLabels }}
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
policyTypes:
|
|
||||||
- Egress
|
|
||||||
egress:
|
|
||||||
# allow dns resolution
|
|
||||||
- ports:
|
|
||||||
- port: 53
|
|
||||||
protocol: UDP
|
|
||||||
- port: 53
|
|
||||||
protocol: TCP
|
|
||||||
# talk only to grafana
|
|
||||||
- ports:
|
|
||||||
- port: {{ .Values.service.targetPort }}
|
|
||||||
protocol: TCP
|
|
||||||
to:
|
|
||||||
- namespaceSelector:
|
|
||||||
matchLabels:
|
|
||||||
name: {{ include "grafana.namespace" . }}
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 14 }}
|
|
||||||
{{- with .Values.podLabels }}
|
|
||||||
{{- toYaml . | nindent 14 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.service.enabled }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.imageRenderer.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.imageRenderer.service.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.service.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
{{- with .Values.imageRenderer.service.clusterIP }}
|
|
||||||
clusterIP: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: {{ .Values.imageRenderer.service.portName }}
|
|
||||||
port: {{ .Values.imageRenderer.service.port }}
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: {{ .Values.imageRenderer.service.targetPort }}
|
|
||||||
{{- with .Values.imageRenderer.appProtocol }}
|
|
||||||
appProtocol: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
{{- include "grafana.imageRenderer.selectorLabels" . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{{- if .Values.imageRenderer.serviceMonitor.enabled }}
|
|
||||||
---
|
|
||||||
apiVersion: monitoring.coreos.com/v1
|
|
||||||
kind: ServiceMonitor
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-image-renderer
|
|
||||||
{{- if .Values.imageRenderer.serviceMonitor.namespace }}
|
|
||||||
namespace: {{ tpl .Values.imageRenderer.serviceMonitor.namespace . }}
|
|
||||||
{{- else }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
{{- end }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.imageRenderer.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.imageRenderer.serviceMonitor.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
endpoints:
|
|
||||||
- port: {{ .Values.imageRenderer.service.portName }}
|
|
||||||
{{- with .Values.imageRenderer.serviceMonitor.interval }}
|
|
||||||
interval: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.serviceMonitor.scrapeTimeout }}
|
|
||||||
scrapeTimeout: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
honorLabels: true
|
|
||||||
path: {{ .Values.imageRenderer.serviceMonitor.path }}
|
|
||||||
scheme: {{ .Values.imageRenderer.serviceMonitor.scheme }}
|
|
||||||
{{- with .Values.imageRenderer.serviceMonitor.tlsConfig }}
|
|
||||||
tlsConfig:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.imageRenderer.serviceMonitor.relabelings }}
|
|
||||||
relabelings:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
jobLabel: "{{ .Release.Name }}-image-renderer"
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
|
|
||||||
namespaceSelector:
|
|
||||||
matchNames:
|
|
||||||
- {{ include "grafana.namespace" . }}
|
|
||||||
{{- with .Values.imageRenderer.serviceMonitor.targetLabels }}
|
|
||||||
targetLabels:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
{{- if .Values.ingress.enabled -}}
|
|
||||||
{{- $ingressApiIsStable := eq (include "grafana.ingress.isStable" .) "true" -}}
|
|
||||||
{{- $ingressSupportsIngressClassName := eq (include "grafana.ingress.supportsIngressClassName" .) "true" -}}
|
|
||||||
{{- $ingressSupportsPathType := eq (include "grafana.ingress.supportsPathType" .) "true" -}}
|
|
||||||
{{- $fullName := include "grafana.fullname" . -}}
|
|
||||||
{{- $servicePort := .Values.service.port -}}
|
|
||||||
{{- $ingressPath := .Values.ingress.path -}}
|
|
||||||
{{- $ingressPathType := .Values.ingress.pathType -}}
|
|
||||||
{{- $extraPaths := .Values.ingress.extraPaths -}}
|
|
||||||
apiVersion: {{ include "grafana.ingress.apiVersion" . }}
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: {{ $fullName }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.ingress.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.ingress.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- range $key, $value := . }}
|
|
||||||
{{ $key }}: {{ tpl $value $ | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if and $ingressSupportsIngressClassName .Values.ingress.ingressClassName }}
|
|
||||||
ingressClassName: {{ .Values.ingress.ingressClassName }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- with .Values.ingress.tls }}
|
|
||||||
tls:
|
|
||||||
{{- tpl (toYaml .) $ | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
{{- if .Values.ingress.hosts }}
|
|
||||||
{{- range .Values.ingress.hosts }}
|
|
||||||
- host: {{ tpl . $ }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
{{- with $extraPaths }}
|
|
||||||
{{- toYaml . | nindent 10 }}
|
|
||||||
{{- end }}
|
|
||||||
- path: {{ $ingressPath }}
|
|
||||||
{{- if $ingressSupportsPathType }}
|
|
||||||
pathType: {{ $ingressPathType }}
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if $ingressApiIsStable }}
|
|
||||||
service:
|
|
||||||
name: {{ $fullName }}
|
|
||||||
port:
|
|
||||||
number: {{ $servicePort }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ $fullName }}
|
|
||||||
servicePort: {{ $servicePort }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
- http:
|
|
||||||
paths:
|
|
||||||
- backend:
|
|
||||||
{{- if $ingressApiIsStable }}
|
|
||||||
service:
|
|
||||||
name: {{ $fullName }}
|
|
||||||
port:
|
|
||||||
number: {{ $servicePort }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ $fullName }}
|
|
||||||
servicePort: {{ $servicePort }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $ingressPath }}
|
|
||||||
path: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if $ingressSupportsPathType }}
|
|
||||||
pathType: {{ $ingressPathType }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{{- if .Values.networkPolicy.enabled }}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
policyTypes:
|
|
||||||
{{- if .Values.networkPolicy.ingress }}
|
|
||||||
- Ingress
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.networkPolicy.egress.enabled }}
|
|
||||||
- Egress
|
|
||||||
{{- end }}
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 6 }}
|
|
||||||
|
|
||||||
{{- if .Values.networkPolicy.egress.enabled }}
|
|
||||||
egress:
|
|
||||||
- ports:
|
|
||||||
{{ .Values.networkPolicy.egress.ports | toJson }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.networkPolicy.ingress }}
|
|
||||||
ingress:
|
|
||||||
- ports:
|
|
||||||
- port: {{ .Values.service.targetPort }}
|
|
||||||
{{- if not .Values.networkPolicy.allowExternal }}
|
|
||||||
from:
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{ include "grafana.fullname" . }}-client: "true"
|
|
||||||
{{- with .Values.networkPolicy.explicitNamespacesSelector }}
|
|
||||||
- namespaceSelector:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.labels" . | nindent 14 }}
|
|
||||||
role: read
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{{- if .Values.podDisruptionBudget }}
|
|
||||||
apiVersion: {{ include "grafana.podDisruptionBudget.apiVersion" . }}
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- with .Values.podDisruptionBudget.minAvailable }}
|
|
||||||
minAvailable: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.podDisruptionBudget.maxUnavailable }}
|
|
||||||
maxUnavailable: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
{{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }}
|
|
||||||
apiVersion: policy/v1beta1
|
|
||||||
kind: PodSecurityPolicy
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
annotations:
|
|
||||||
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
|
|
||||||
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
|
|
||||||
{{- if .Values.rbac.pspUseAppArmor }}
|
|
||||||
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
|
|
||||||
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
privileged: false
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
requiredDropCapabilities:
|
|
||||||
# Default set from Docker, with DAC_OVERRIDE and CHOWN
|
|
||||||
- ALL
|
|
||||||
volumes:
|
|
||||||
- 'configMap'
|
|
||||||
- 'emptyDir'
|
|
||||||
- 'projected'
|
|
||||||
- 'csi'
|
|
||||||
- 'secret'
|
|
||||||
- 'downwardAPI'
|
|
||||||
- 'persistentVolumeClaim'
|
|
||||||
hostNetwork: false
|
|
||||||
hostIPC: false
|
|
||||||
hostPID: false
|
|
||||||
runAsUser:
|
|
||||||
rule: 'RunAsAny'
|
|
||||||
seLinux:
|
|
||||||
rule: 'RunAsAny'
|
|
||||||
supplementalGroups:
|
|
||||||
rule: 'MustRunAs'
|
|
||||||
ranges:
|
|
||||||
# Forbid adding the root group.
|
|
||||||
- min: 1
|
|
||||||
max: 65535
|
|
||||||
fsGroup:
|
|
||||||
rule: 'MustRunAs'
|
|
||||||
ranges:
|
|
||||||
# Forbid adding the root group.
|
|
||||||
- min: 1
|
|
||||||
max: 65535
|
|
||||||
readOnlyRootFilesystem: false
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "pvc")}}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.persistence.extraPvcLabels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.persistence.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.persistence.finalizers }}
|
|
||||||
finalizers:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
{{- range .Values.persistence.accessModes }}
|
|
||||||
- {{ . | quote }}
|
|
||||||
{{- end }}
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: {{ .Values.persistence.size | quote }}
|
|
||||||
{{- with .Values.persistence.storageClassName }}
|
|
||||||
storageClassName: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.persistence.selectorLabels }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{{- if and .Values.rbac.create (not .Values.rbac.useExistingRole) -}}
|
|
||||||
apiVersion: {{ include "grafana.rbac.apiVersion" . }}
|
|
||||||
kind: Role
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if or .Values.rbac.pspEnabled (and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled .Values.rbac.extraRoleRules)) }}
|
|
||||||
rules:
|
|
||||||
{{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }}
|
|
||||||
- apiGroups: ['extensions']
|
|
||||||
resources: ['podsecuritypolicies']
|
|
||||||
verbs: ['use']
|
|
||||||
resourceNames: [{{ include "grafana.fullname" . }}]
|
|
||||||
{{- end }}
|
|
||||||
{{- if and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled) }}
|
|
||||||
- apiGroups: [""] # "" indicates the core API group
|
|
||||||
resources: ["configmaps", "secrets"]
|
|
||||||
verbs: ["get", "watch", "list"]
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.rbac.extraRoleRules }}
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end}}
|
|
||||||
{{- else }}
|
|
||||||
rules: []
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
{{- if .Values.rbac.create }}
|
|
||||||
apiVersion: {{ include "grafana.rbac.apiVersion" . }}
|
|
||||||
kind: RoleBinding
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
roleRef:
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
kind: Role
|
|
||||||
{{- if .Values.rbac.useExistingRole }}
|
|
||||||
name: {{ .Values.rbac.useExistingRole }}
|
|
||||||
{{- else }}
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
{{- end }}
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: {{ include "grafana.serviceAccountName" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{{- if .Values.envRenderSecret }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-env
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
type: Opaque
|
|
||||||
data:
|
|
||||||
{{- range $key, $val := .Values.envRenderSecret }}
|
|
||||||
{{ $key }}: {{ tpl ($val | toString) $ | b64enc | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{{- if or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret)) }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
type: Opaque
|
|
||||||
data:
|
|
||||||
{{- if and (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) }}
|
|
||||||
admin-user: {{ .Values.adminUser | b64enc | quote }}
|
|
||||||
{{- if .Values.adminPassword }}
|
|
||||||
admin-password: {{ .Values.adminPassword | b64enc | quote }}
|
|
||||||
{{- else }}
|
|
||||||
admin-password: {{ include "grafana.password" . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not .Values.ldap.existingSecret }}
|
|
||||||
ldap-toml: {{ tpl .Values.ldap.config $ | b64enc | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
{{- if .Values.service.enabled }}
|
|
||||||
{{- $root := . }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.service.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.service.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- tpl (toYaml . | nindent 4) $root }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if (or (eq .Values.service.type "ClusterIP") (empty .Values.service.type)) }}
|
|
||||||
type: ClusterIP
|
|
||||||
{{- with .Values.service.clusterIP }}
|
|
||||||
clusterIP: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- else if eq .Values.service.type "LoadBalancer" }}
|
|
||||||
type: {{ .Values.service.type }}
|
|
||||||
{{- with .Values.service.loadBalancerIP }}
|
|
||||||
loadBalancerIP: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.service.loadBalancerSourceRanges }}
|
|
||||||
loadBalancerSourceRanges:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
type: {{ .Values.service.type }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.service.externalIPs }}
|
|
||||||
externalIPs:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: {{ .Values.service.portName }}
|
|
||||||
port: {{ .Values.service.port }}
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: {{ .Values.service.targetPort }}
|
|
||||||
{{- with .Values.service.appProtocol }}
|
|
||||||
appProtocol: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
|
|
||||||
nodePort: {{ .Values.service.nodePort }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.extraExposePorts }}
|
|
||||||
{{- tpl (toYaml . | nindent 4) $root }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{{- if .Values.serviceAccount.create }}
|
|
||||||
{{- $root := . -}}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.serviceAccount.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.serviceAccount.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- tpl (toYaml . | nindent 4) $root }}
|
|
||||||
{{- end }}
|
|
||||||
name: {{ include "grafana.serviceAccountName" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{{- if .Values.serviceMonitor.enabled }}
|
|
||||||
---
|
|
||||||
apiVersion: monitoring.coreos.com/v1
|
|
||||||
kind: ServiceMonitor
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
{{- if .Values.serviceMonitor.namespace }}
|
|
||||||
namespace: {{ tpl .Values.serviceMonitor.namespace . }}
|
|
||||||
{{- else }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
{{- end }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.serviceMonitor.labels }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
endpoints:
|
|
||||||
- port: {{ .Values.service.portName }}
|
|
||||||
{{- with .Values.serviceMonitor.interval }}
|
|
||||||
interval: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.serviceMonitor.scrapeTimeout }}
|
|
||||||
scrapeTimeout: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
honorLabels: true
|
|
||||||
path: {{ .Values.serviceMonitor.path }}
|
|
||||||
scheme: {{ .Values.serviceMonitor.scheme }}
|
|
||||||
{{- with .Values.serviceMonitor.tlsConfig }}
|
|
||||||
tlsConfig:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.serviceMonitor.relabelings }}
|
|
||||||
relabelings:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
jobLabel: "{{ .Release.Name }}"
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 6 }}
|
|
||||||
namespaceSelector:
|
|
||||||
matchNames:
|
|
||||||
- {{ include "grafana.namespace" . }}
|
|
||||||
{{- with .Values.serviceMonitor.targetLabels }}
|
|
||||||
targetLabels:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{{- $sts := list "sts" "StatefulSet" "statefulset" -}}
|
|
||||||
{{- if (or (.Values.useStatefulSet) (and .Values.persistence.enabled (not .Values.persistence.existingClaim) (has .Values.persistence.type $sts)))}}
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
replicas: {{ .Values.replicas }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 6 }}
|
|
||||||
serviceName: {{ include "grafana.fullname" . }}-headless
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.selectorLabels" . | nindent 8 }}
|
|
||||||
{{- with .Values.podLabels }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
annotations:
|
|
||||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
|
||||||
checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }}
|
|
||||||
checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }}
|
|
||||||
{{- if and (or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret))) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
|
|
||||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
|
||||||
{{- end }}
|
|
||||||
kubectl.kubernetes.io/default-container: {{ .Chart.Name }}
|
|
||||||
{{- with .Values.podAnnotations }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- include "grafana.pod" . | nindent 6 }}
|
|
||||||
{{- if .Values.persistence.enabled}}
|
|
||||||
volumeClaimTemplates:
|
|
||||||
- metadata:
|
|
||||||
name: storage
|
|
||||||
spec:
|
|
||||||
accessModes: {{ .Values.persistence.accessModes }}
|
|
||||||
storageClassName: {{ .Values.persistence.storageClassName }}
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: {{ .Values.persistence.size }}
|
|
||||||
{{- with .Values.persistence.selectorLabels }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- toYaml . | nindent 10 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{{- if .Values.testFramework.enabled }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test-success
|
|
||||||
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
data:
|
|
||||||
run.sh: |-
|
|
||||||
@test "Test Health" {
|
|
||||||
url="http://{{ include "grafana.fullname" . }}/api/health"
|
|
||||||
|
|
||||||
code=$(wget --server-response --spider --timeout 90 --tries 10 ${url} 2>&1 | awk '/^ HTTP/{print $2}')
|
|
||||||
[ "$code" == "200" ]
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.testFramework.enabled .Values.rbac.pspEnabled }}
|
|
||||||
apiVersion: policy/v1beta1
|
|
||||||
kind: PodSecurityPolicy
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test-success
|
|
||||||
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
allowPrivilegeEscalation: true
|
|
||||||
privileged: false
|
|
||||||
hostNetwork: false
|
|
||||||
hostIPC: false
|
|
||||||
hostPID: false
|
|
||||||
fsGroup:
|
|
||||||
rule: RunAsAny
|
|
||||||
seLinux:
|
|
||||||
rule: RunAsAny
|
|
||||||
supplementalGroups:
|
|
||||||
rule: RunAsAny
|
|
||||||
runAsUser:
|
|
||||||
rule: RunAsAny
|
|
||||||
volumes:
|
|
||||||
- configMap
|
|
||||||
- downwardAPI
|
|
||||||
- emptyDir
|
|
||||||
- projected
|
|
||||||
- csi
|
|
||||||
- secret
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.testFramework.enabled .Values.rbac.pspEnabled }}
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: Role
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test-success
|
|
||||||
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
rules:
|
|
||||||
- apiGroups: ['policy']
|
|
||||||
resources: ['podsecuritypolicies']
|
|
||||||
verbs: ['use']
|
|
||||||
resourceNames: [{{ include "grafana.fullname" . }}-test]
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.testFramework.enabled .Values.rbac.pspEnabled }}
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: RoleBinding
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test-success
|
|
||||||
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
roleRef:
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
kind: Role
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: {{ include "grafana.serviceAccountNameTest" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{{- if and .Values.testFramework.enabled .Values.serviceAccount.create }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
name: {{ include "grafana.serviceAccountNameTest" . }}
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test-success
|
|
||||||
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
{{- if .Values.testFramework.enabled }}
|
|
||||||
{{- $root := . }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
labels:
|
|
||||||
{{- include "grafana.labels" . | nindent 4 }}
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test-success
|
|
||||||
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
|
|
||||||
namespace: {{ include "grafana.namespace" . }}
|
|
||||||
spec:
|
|
||||||
serviceAccountName: {{ include "grafana.serviceAccountNameTest" . }}
|
|
||||||
{{- with .Values.testFramework.securityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if or .Values.image.pullSecrets .Values.global.imagePullSecrets }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- include "grafana.imagePullSecrets" (dict "root" $root "imagePullSecrets" .Values.image.pullSecrets) | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.nodeSelector }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.affinity }}
|
|
||||||
affinity:
|
|
||||||
{{- tpl (toYaml .) $root | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.tolerations }}
|
|
||||||
tolerations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ .Release.Name }}-test
|
|
||||||
image: "{{ .Values.testFramework.image}}:{{ .Values.testFramework.tag }}"
|
|
||||||
imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}"
|
|
||||||
command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"]
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /tests
|
|
||||||
name: tests
|
|
||||||
readOnly: true
|
|
||||||
volumes:
|
|
||||||
- name: tests
|
|
||||||
configMap:
|
|
||||||
name: {{ include "grafana.fullname" . }}-test
|
|
||||||
restartPolicy: Never
|
|
||||||
{{- end }}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- name: prometheus-node-exporter
|
||||||
|
repository: https://prometheus-community.github.io/helm-charts
|
||||||
|
version: 4.56.3
|
||||||
|
digest: sha256:d82c5d706aab138aaf362814f8bc6f49baf3b8d7b1df751f152902a6940258fd
|
||||||
|
generated: "2026-09-06T08:31:01.815023+05:30"
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: node-exporter
|
||||||
|
version: 1.0.0
|
||||||
|
dependencies:
|
||||||
|
- name: prometheus-node-exporter
|
||||||
|
# Same official chart this ran as a subchart of the (now removed)
|
||||||
|
# prometheus server chart — vendored standalone here since it exposes
|
||||||
|
# host metrics over HTTP for any scraper to pull, independent of
|
||||||
|
# which TSDB stores them. vmagent scrapes it via the
|
||||||
|
# prometheus.io/scrape annotation this chart's Service carries,
|
||||||
|
# exactly as the Prometheus server used to.
|
||||||
|
version: 4.56.3
|
||||||
|
repository: https://prometheus-community.github.io/helm-charts
|
||||||
Binary file not shown.
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: postgresql
|
||||||
|
description: |
|
||||||
|
Single-instance PostgreSQL for this homelab.
|
||||||
|
|
||||||
|
Hand-written rather than vendoring Bitnami's chart: Broadcom has been
|
||||||
|
retiring and freezing images behind that repo (see claude.md infra issue
|
||||||
|
#4, where it broke Contour twice), and PostgreSQL publishes no official
|
||||||
|
Helm chart of its own. A single StatefulSet with one PVC is small enough
|
||||||
|
that owning it outright costs less than depending on an unstable
|
||||||
|
repackage.
|
||||||
|
|
||||||
|
Not highly available and not intended to be. One replica, one PVC, no
|
||||||
|
replication, no connection pooler. Adding any of those to a single-node
|
||||||
|
cluster would be theatre.
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "16"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{{- $name := .Values.fullnameOverride | default "postgresql" -}}
|
||||||
|
# ClusterIP only. Nothing outside the cluster should reach the database, and
|
||||||
|
# there is no Ingress here on purpose — Contour terminates HTTP, and exposing
|
||||||
|
# PostgreSQL's wire protocol through it is neither possible nor wanted.
|
||||||
|
#
|
||||||
|
# Consumers address this as:
|
||||||
|
# {{ $name }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ $name }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ $name }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: {{ $name }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: {{ .Values.service.port }}
|
||||||
|
targetPort: postgres
|
||||||
|
protocol: TCP
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
{{- $name := .Values.fullnameOverride | default "postgresql" -}}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ $name }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ $name }}
|
||||||
|
spec:
|
||||||
|
serviceName: {{ $name }}
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ $name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ $name }}
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
# The official image starts as root, initialises the data directory,
|
||||||
|
# then drops to the postgres user (uid 70 on the Alpine variant).
|
||||||
|
# fsGroup makes the provisioned volume group-writable so that drop
|
||||||
|
# still leaves the data directory usable.
|
||||||
|
fsGroup: 70
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- shared_buffers={{ .Values.config.sharedBuffers }}
|
||||||
|
- -c
|
||||||
|
- max_connections={{ .Values.config.maxConnections }}
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.existingSecret }}
|
||||||
|
key: {{ .Values.secretKeys.username }}
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.existingSecret }}
|
||||||
|
key: {{ .Values.secretKeys.password }}
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: {{ .Values.database | quote }}
|
||||||
|
# PGDATA must be a SUBDIRECTORY of the mount, not the mount
|
||||||
|
# itself: initdb refuses to run in a directory that already has
|
||||||
|
# contents, and a freshly provisioned volume is not always empty.
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: 5432
|
||||||
|
protocol: TCP
|
||||||
|
# Run through a shell so the environment expands — Kubernetes does
|
||||||
|
# not substitute $(VAR) inside exec probe commands.
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" -h 127.0.0.1']
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" -h 127.0.0.1']
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 20
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: {{ .Values.persistence.storageClass | quote }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size | quote }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# Chart defaults. Real configuration lives in
|
||||||
|
# helm-overrides/k8s-admin-prd-ase1/postgresql/custom-values.yaml.
|
||||||
|
|
||||||
|
fullnameOverride: postgresql
|
||||||
|
|
||||||
|
image:
|
||||||
|
# Pulled from Docker Hub, like every other infra component here (gitea,
|
||||||
|
# vault, harbor). The base-images mirror in Harbor exists to remove
|
||||||
|
# Docker Hub from the *application build* path and to minimise shipped
|
||||||
|
# app images — it is not in play for platform components.
|
||||||
|
repository: postgres
|
||||||
|
tag: "16-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Name of the Secret holding username/password. Created by External
|
||||||
|
# Secrets from Vault, not by this chart — a chart that generates its own
|
||||||
|
# database password regenerates it on every render, which silently locks
|
||||||
|
# you out of an existing volume.
|
||||||
|
existingSecret: postgresql-credentials
|
||||||
|
secretKeys:
|
||||||
|
username: username
|
||||||
|
password: password
|
||||||
|
|
||||||
|
database: toolshed
|
||||||
|
|
||||||
|
service:
|
||||||
|
port: 5432
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: local-path
|
||||||
|
size: 5Gi
|
||||||
|
|
||||||
|
# Tuned down hard. The box has 8GB total and is at its ceiling; PostgreSQL's
|
||||||
|
# default shared_buffers of 128MB is most of this pod's budget on its own.
|
||||||
|
config:
|
||||||
|
sharedBuffers: 32MB
|
||||||
|
maxConnections: "50"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: redis
|
||||||
|
description: |
|
||||||
|
Single-instance Redis for this homelab, backing toolshed's managed cache
|
||||||
|
add-on (internal/dbprovision) — toolshed provisions a per-app ACL user
|
||||||
|
scoped to its own key prefix on request.
|
||||||
|
|
||||||
|
Hand-written rather than vendoring Bitnami's chart, for the same reason
|
||||||
|
the sibling postgresql chart is: Broadcom has been retiring and freezing
|
||||||
|
images behind that repo (claude.md infra issue #4, where it broke Contour
|
||||||
|
twice), and Redis publishes no official Helm chart of its own.
|
||||||
|
|
||||||
|
Authentication is defined entirely by the ACL file, with no requirepass.
|
||||||
|
That is not a style choice — see values.yaml, where the reasoning is
|
||||||
|
recorded alongside the setting it explains. Getting it wrong leaves the
|
||||||
|
server open to unauthenticated access after its first restart.
|
||||||
|
|
||||||
|
Not highly available and not intended to be. One replica, one PVC, no
|
||||||
|
replication, no sentinel. On a single-node cluster those would be
|
||||||
|
theatre.
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "7"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{{- $name := .Values.fullnameOverride | default "redis" -}}
|
||||||
|
# ClusterIP only. Nothing outside the cluster should reach Redis, and there
|
||||||
|
# is no Ingress here on purpose — Contour terminates HTTP, and exposing
|
||||||
|
# Redis's wire protocol through it is neither possible nor wanted.
|
||||||
|
#
|
||||||
|
# Consumers address this as:
|
||||||
|
# {{ $name }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ $name }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ $name }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: {{ $name }}
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
port: {{ .Values.service.port }}
|
||||||
|
targetPort: redis
|
||||||
|
protocol: TCP
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
{{- $name := .Values.fullnameOverride | default "redis" -}}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ $name }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
app: {{ $name }}
|
||||||
|
spec:
|
||||||
|
serviceName: {{ $name }}
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ $name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ $name }}
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
# The official image runs as the redis user (uid 999 on the Alpine
|
||||||
|
# variant). fsGroup makes the provisioned volume group-writable so
|
||||||
|
# Redis can write the ACL file it is given — without it ACL SAVE
|
||||||
|
# fails at provisioning time with a permission error.
|
||||||
|
fsGroup: 999
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
|
initContainers:
|
||||||
|
# Seeds the ACL file with the default (admin) user on first boot
|
||||||
|
# only. Redis will not start with an --aclfile that does not exist,
|
||||||
|
# and the default user has to be defined there rather than by
|
||||||
|
# requirepass — see the long note in values.yaml for why that
|
||||||
|
# distinction is a security property and not a preference.
|
||||||
|
#
|
||||||
|
# Never overwrites an existing file. That file is rewritten by ACL
|
||||||
|
# SAVE every time toolshed provisions an app user, so recreating it
|
||||||
|
# on every pod start would silently delete every provisioned user
|
||||||
|
# and lock those apps out — the exact failure this whole design
|
||||||
|
# exists to prevent, reintroduced from the other end.
|
||||||
|
#
|
||||||
|
# Consequence worth knowing: rotating the admin password in Vault
|
||||||
|
# does NOT propagate here, because this only ever runs against a
|
||||||
|
# missing file. Rotating means `ACL SETUSER default >newpassword`
|
||||||
|
# followed by `ACL SAVE` against the running server.
|
||||||
|
- name: seed-acl
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
- name: REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.existingSecret }}
|
||||||
|
key: {{ .Values.secretKeys.password }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
if [ -f /data/users.acl ]; then
|
||||||
|
echo "ACL file already present; leaving it alone."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "user default on >$REDIS_PASSWORD ~* &* +@all" > /data/users.acl
|
||||||
|
chmod 600 /data/users.acl
|
||||||
|
echo "Seeded ACL file with the default user."
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
- redis-server
|
||||||
|
- --aclfile
|
||||||
|
- /data/users.acl
|
||||||
|
- --maxmemory
|
||||||
|
- {{ .Values.config.maxmemory | quote }}
|
||||||
|
- --maxmemory-policy
|
||||||
|
- {{ .Values.config.maxmemoryPolicy | quote }}
|
||||||
|
- --save
|
||||||
|
- {{ .Values.config.save | quote }}
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
containerPort: 6379
|
||||||
|
protocol: TCP
|
||||||
|
# Authenticated probes: with the ACL file in place an
|
||||||
|
# unauthenticated PING is correctly refused with NOAUTH, so a
|
||||||
|
# bare `redis-cli ping` would mark a perfectly healthy server as
|
||||||
|
# failing. Run through a shell so the environment expands —
|
||||||
|
# Kubernetes does not substitute $(VAR) inside exec probe
|
||||||
|
# commands.
|
||||||
|
env:
|
||||||
|
- name: REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.existingSecret }}
|
||||||
|
key: {{ .Values.secretKeys.password }}
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'redis-cli --no-auth-warning -a "$REDIS_PASSWORD" ping | grep -q PONG']
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'redis-cli --no-auth-warning -a "$REDIS_PASSWORD" ping | grep -q PONG']
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 20
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: {{ .Values.persistence.storageClass | quote }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size | quote }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# Chart defaults. Real configuration lives in
|
||||||
|
# helm-overrides/k8s-admin-prd-ase1/redis/custom-values.yaml.
|
||||||
|
|
||||||
|
fullnameOverride: redis
|
||||||
|
|
||||||
|
image:
|
||||||
|
# Pulled from Docker Hub, like every other infra component here (gitea,
|
||||||
|
# vault, harbor, postgresql). The base-images mirror in Harbor exists to
|
||||||
|
# remove Docker Hub from the *application build* path — it is not in play
|
||||||
|
# for platform components.
|
||||||
|
repository: redis
|
||||||
|
tag: "7-alpine"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Name of the Secret holding the admin password. Created by External
|
||||||
|
# Secrets from Vault, not by this chart — a chart that generates its own
|
||||||
|
# password regenerates it on every render, which would rewrite the ACL file
|
||||||
|
# and lock every already-provisioned app out of its own data.
|
||||||
|
existingSecret: redis-credentials
|
||||||
|
secretKeys:
|
||||||
|
password: password
|
||||||
|
|
||||||
|
service:
|
||||||
|
port: 6379
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
# local-path-provisioner, this cluster's default StorageClass. Small: this
|
||||||
|
# holds the ACL file and (if enabled) an RDB snapshot, not a dataset of
|
||||||
|
# any size — maxmemory below is the real ceiling on what Redis will hold.
|
||||||
|
# The volume is not resizable in place with this provisioner, so it is
|
||||||
|
# sized up front.
|
||||||
|
storageClass: local-path
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
config:
|
||||||
|
# ACL FILE, NOT requirepass. This distinction is load-bearing and easy to
|
||||||
|
# "simplify" into a security hole, so it is written down here rather than
|
||||||
|
# left to be rediscovered:
|
||||||
|
#
|
||||||
|
# toolshed provisions per-app users with ACL SETUSER, and persists them
|
||||||
|
# with ACL SAVE (internal/dbprovision.EnsureRedisUser) — without that
|
||||||
|
# save, every provisioned user is lost on the next restart and every app
|
||||||
|
# using Redis fails to authenticate with credentials that still look
|
||||||
|
# valid. ACL SAVE requires an aclfile; that is why one is configured.
|
||||||
|
#
|
||||||
|
# But ACL SAVE also writes the *default* user's state to that file. With
|
||||||
|
# `requirepass` set and the default user defined only by it, the saved
|
||||||
|
# entry comes back as `user default on nopass ~* &* +@all` — and after
|
||||||
|
# the next restart the ACL file wins, leaving Redis accepting
|
||||||
|
# UNAUTHENTICATED connections with full access. Verified directly, not
|
||||||
|
# inferred: with requirepass the restarted server answered an
|
||||||
|
# unauthenticated PING with PONG and served a key.
|
||||||
|
#
|
||||||
|
# Defining the default user in the ACL file instead (seeded by the init
|
||||||
|
# container, see the StatefulSet) keeps its password across every
|
||||||
|
# subsequent ACL SAVE — the same restart then correctly answers
|
||||||
|
# `NOAUTH Authentication required.`
|
||||||
|
#
|
||||||
|
# If you ever add `requirepass` here, you reintroduce that hole.
|
||||||
|
maxmemory: 48mb
|
||||||
|
# allkeys-lru, because this backs a connection kind literally called
|
||||||
|
# "cache" and eviction under pressure is that contract. An app using
|
||||||
|
# Redis as its only copy of something wants noeviction instead — at
|
||||||
|
# which case writes start failing when full rather than data silently
|
||||||
|
# disappearing. Neither is safe for every use; this one matches the name.
|
||||||
|
maxmemoryPolicy: allkeys-lru
|
||||||
|
# Snapshotting off. What must survive a restart is the ACL file, which is
|
||||||
|
# written by ACL SAVE independently of RDB/AOF. Cached values are by
|
||||||
|
# definition reconstructible, and on a node at its memory ceiling a
|
||||||
|
# background save's copy-on-write spike is a real risk for no benefit.
|
||||||
|
save: ""
|
||||||
|
|
||||||
|
# Tuned for a node with 8GB total that is already near its ceiling. The
|
||||||
|
# request is what the scheduler reserves; the limit is sized above
|
||||||
|
# maxmemory so Redis hits its own eviction policy rather than being
|
||||||
|
# OOM-killed by the kernel, which loses the whole instance instead of the
|
||||||
|
# coldest keys.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 96Mi
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 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
|
|
||||||
*~
|
|
||||||
# Various IDEs
|
|
||||||
.project
|
|
||||||
.idea/
|
|
||||||
*.tmproj
|
|
||||||
.vscode/
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- name: victoria-metrics-single
|
||||||
|
repository: https://victoriametrics.github.io/helm-charts
|
||||||
|
version: 0.45.0
|
||||||
|
digest: sha256:5c84351c76bb8a825b95a11a90cf86f8cd2f2b4565135b1241b35dfa9b4e392e
|
||||||
|
generated: "2026-09-06T08:34:56.682089+05:30"
|
||||||
@@ -1,30 +1,21 @@
|
|||||||
apiVersion: v1
|
apiVersion: v2
|
||||||
appVersion: v1.101.0
|
|
||||||
description: Victoria Metrics Single version - high-performance, cost-effective and scalable TSDB, long-term remote storage for Prometheus
|
|
||||||
name: victoria-metrics-single
|
name: victoria-metrics-single
|
||||||
version: 0.9.24
|
version: 1.0.0
|
||||||
appVersion: v1.101.0
|
dependencies:
|
||||||
sources:
|
- name: victoria-metrics-single
|
||||||
- https://github.com/VictoriaMetrics/helm-charts
|
# Pinned to the latest stable at the time this was vendored (2026-09).
|
||||||
kubeVersion: ">=1.23.0-0"
|
# Bump deliberately later, with a changelog read first, same as any
|
||||||
keywords:
|
# other chart bump in this repo.
|
||||||
- victoriametrics
|
#
|
||||||
- vmsingle
|
# This directory already existed in this repo before this — a
|
||||||
- single
|
# leftover from the original Meesho monorepo import (commit b8575bb),
|
||||||
- monitoring
|
# with its own vendored templates/values.yaml for a different,
|
||||||
- kubernetes
|
# GKE-targeted deployment of this same chart. That entire tree was
|
||||||
- observability
|
# removed rather than adapted (same reasoning as the ~35 charts
|
||||||
- tsdb
|
# removed outright in devops-helm-charts's own prune — see claude.md)
|
||||||
- metrics
|
# and replaced with this thin wrapper, matching every other
|
||||||
- metricsql
|
# official-chart component in this repo (vault, postgresql's sibling
|
||||||
- timeseries
|
# entries, etc.): a Chart.yaml dependency plus a committed .tgz, no
|
||||||
annotations:
|
# local templates of its own.
|
||||||
artifacthub.io/license: Apache-2.0
|
version: 0.45.0
|
||||||
artifacthub.io/category: "monitoring-logging"
|
repository: https://victoriametrics.github.io/helm-charts
|
||||||
artifacthub.io/links: |
|
|
||||||
- name: Sources
|
|
||||||
url: https://github.com/VictoriaMetrics/helm-charts
|
|
||||||
- name: Charts repo
|
|
||||||
url: https://victoriametrics.github.io/helm-charts/
|
|
||||||
- name: Docs
|
|
||||||
url: https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,51 +0,0 @@
|
|||||||
{{- if .Values.printNotes }}
|
|
||||||
{{- if .Values.server.enabled }}
|
|
||||||
The VictoriaMetrics write api can be accessed via port {{ .Values.server.service.servicePort }} on the following DNS name from within your cluster:
|
|
||||||
{{ template "victoria-metrics.server.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local
|
|
||||||
|
|
||||||
|
|
||||||
Metrics Ingestion:
|
|
||||||
Get the Victoria Metrics service URL by running these commands in the same shell:
|
|
||||||
|
|
||||||
{{- if contains "NodePort" .Values.server.service.type }}
|
|
||||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "victoria-metrics.server.fullname" . }})
|
|
||||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
|
||||||
echo http://$NODE_IP:$NODE_PORT
|
|
||||||
{{- else if contains "LoadBalancer" .Values.server.service.type }}
|
|
||||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
|
||||||
You can watch the status of by running 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "victoria-metrics.server.fullname" . }}'
|
|
||||||
|
|
||||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "victoria-metrics.server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
|
||||||
echo http://$SERVICE_IP:{{ .Values.server.service.servicePort }}
|
|
||||||
{{- else if contains "ClusterIP" .Values.server.service.type }}
|
|
||||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ .Values.server.name }}" -o jsonpath="{.items[0].metadata.name}")
|
|
||||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME {{ .Values.server.service.servicePort }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
Write url inside the kubernetes cluster:
|
|
||||||
http://{{ template "victoria-metrics.server.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.server.service.servicePort }}/api/v1/write
|
|
||||||
|
|
||||||
{{- if .Values.server.scrape.enabled }}
|
|
||||||
|
|
||||||
Metrics Scrape:
|
|
||||||
Pull-based scrapes are enabled
|
|
||||||
Scrape config can be displayed by running this command::
|
|
||||||
{{- if eq .Values.server.scrape.configMap "" }}
|
|
||||||
kubectl get cm {{ template "victoria-metrics.server.fullname" . }}-scrapeconfig -n {{ .Release.Namespace }}
|
|
||||||
{{- else }}
|
|
||||||
kubectl get cm .Values.server.scrape.configMap -n {{ .Release.Namespace }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
The target’s information is accessible via api:
|
|
||||||
Inside cluster:
|
|
||||||
http://{{ template "victoria-metrics.server.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.server.service.servicePort }}/targets
|
|
||||||
Outside cluster:
|
|
||||||
You need to port-forward service (see instructions above) and call
|
|
||||||
http://<service-host-port>/targets
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
Read Data:
|
|
||||||
The following url can be used as the datasource url in Grafana::
|
|
||||||
http://{{ template "victoria-metrics.server.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.server.service.servicePort }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
{{/* vim: set filetype=mustache: */}}
|
|
||||||
{{/*
|
|
||||||
Expand the name of the chart.
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.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 "victoria-metrics.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 "victoria-metrics.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create the name of the service account
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.serviceAccountName" -}}
|
|
||||||
{{- if .Values.serviceAccount.create -}}
|
|
||||||
{{ default (include "victoria-metrics.fullname" .) .Values.serviceAccount.name }}
|
|
||||||
{{- else -}}
|
|
||||||
{{ default "default" .Values.serviceAccount.name }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create unified labels for victoria-metrics components
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.common.matchLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ include "victoria-metrics.name" . }}
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "victoria-metrics.common.metaLabels" -}}
|
|
||||||
helm.sh/chart: {{ include "victoria-metrics.chart" . }}
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "victoria-metrics.server.labels" -}}
|
|
||||||
{{ include "victoria-metrics.server.matchLabels" . }}
|
|
||||||
{{ include "victoria-metrics.common.metaLabels" . }}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "victoria-metrics.server.matchLabels" -}}
|
|
||||||
app: {{ .Values.server.name }}
|
|
||||||
{{ include "victoria-metrics.common.matchLabels" . }}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create a fully qualified server name.
|
|
||||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.server.fullname" -}}
|
|
||||||
{{- if .Values.server.fullnameOverride -}}
|
|
||||||
{{- .Values.server.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
|
||||||
{{- if contains $name .Release.Name -}}
|
|
||||||
{{- printf "%s-%s" .Release.Name .Values.server.name | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "%s-%s-%s" .Release.Name $name .Values.server.name | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
|
|
||||||
{{- define "split-host-port" -}}
|
|
||||||
{{- $hp := split ":" . -}}
|
|
||||||
{{- printf "%s" $hp._1 -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Defines the name of scrape configuration map
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.server.scrape.configname" -}}
|
|
||||||
{{- if .Values.server.scrape.configMap -}}
|
|
||||||
{{- .Values.server.scrape.configMap -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- include "victoria-metrics.server.fullname" . -}}-scrapeconfig
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return the appropriate apiVersion for ingress.
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.ingress.apiVersion" -}}
|
|
||||||
{{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") -}}
|
|
||||||
{{- print "networking.k8s.io/v1" -}}
|
|
||||||
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
|
|
||||||
{{- print "networking.k8s.io/v1beta1" -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- print "extensions/v1beta1" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return if ingress is stable.
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.ingress.isStable" -}}
|
|
||||||
{{- eq (include "victoria-metrics.ingress.apiVersion" .) "networking.k8s.io/v1" -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return if ingress supports ingressClassName.
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.ingress.supportsIngressClassName" -}}
|
|
||||||
{{- or (eq (include "victoria-metrics.ingress.isStable" .) "true") (and (eq (include "victoria-metrics.ingress.apiVersion" .) "networking.k8s.io/v1beta1")) -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return if ingress supports pathType.
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.ingress.supportsPathType" -}}
|
|
||||||
{{- or (eq (include "victoria-metrics.ingress.isStable" .) "true") (and (eq (include "victoria-metrics.ingress.apiVersion" .) "networking.k8s.io/v1beta1")) -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "victoria-metrics.hasInitContainer" -}}
|
|
||||||
{{- or (gt (len .Values.server.initContainers) 0) .Values.server.vmbackupmanager.restore.onStart.enabled -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "victoria-metrics.initContiners" -}}
|
|
||||||
{{- if eq (include "victoria-metrics.hasInitContainer" . ) "true" -}}
|
|
||||||
{{- with .Values.server.initContainers -}}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if .Values.server.vmbackupmanager.restore.onStart.enabled }}
|
|
||||||
- name: {{ template "victoria-metrics.name" . }}-vmbackupmanager-restore
|
|
||||||
image: "{{ .Values.server.vmbackupmanager.image.repository }}:{{ .Values.server.vmbackupmanager.image.tag }}"
|
|
||||||
imagePullPolicy: "{{ .Values.server.image.pullPolicy }}"
|
|
||||||
args:
|
|
||||||
- restore
|
|
||||||
- {{ printf "%s=%t" "--eula" .Values.server.vmbackupmanager.eula | quote}}
|
|
||||||
- {{ printf "%s=%s" "--storageDataPath" .Values.server.persistentVolume.mountPath | quote}}
|
|
||||||
{{- range $key, $value := .Values.server.vmbackupmanager.extraArgs }}
|
|
||||||
- --{{ $key }}={{ $value }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.server.securityContext }}
|
|
||||||
securityContext: {{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.server.vmbackupmanager.resources }}
|
|
||||||
resources: {{ toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.server.vmbackupmanager.env }}
|
|
||||||
env: {{ toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: manager-http
|
|
||||||
containerPort: 8300
|
|
||||||
volumeMounts:
|
|
||||||
- name: server-volume
|
|
||||||
mountPath: {{ .Values.server.persistentVolume.mountPath }}
|
|
||||||
subPath: {{ .Values.server.persistentVolume.subPath }}
|
|
||||||
{{- with .Values.server.vmbackupmanager.extraVolumeMounts }}
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- else -}}
|
|
||||||
[]
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return license flag if necessary.
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.license.flag" -}}
|
|
||||||
{{- if .Values.license.key -}}
|
|
||||||
--license={{ .Values.license.key }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if and .Values.license.secret.name .Values.license.secret.key -}}
|
|
||||||
--licenseFile=/etc/vm-license-key/{{ .Values.license.secret.key }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return license volume mount
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.license.volume" -}}
|
|
||||||
{{- if and .Values.license.secret.name .Values.license.secret.key -}}
|
|
||||||
- name: license-key
|
|
||||||
secret:
|
|
||||||
secretName: {{ .Values.license.secret.name }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return license volume mount for container
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.license.mount" -}}
|
|
||||||
{{- if and .Values.license.secret.name .Values.license.secret.key -}}
|
|
||||||
- name: license-key
|
|
||||||
mountPath: /etc/vm-license-key
|
|
||||||
readOnly: true
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Enforce license for vmbackupmanager
|
|
||||||
*/}}
|
|
||||||
{{- define "victoria-metrics.vmbackupmanager.enforce_license" -}}
|
|
||||||
{{ if and .Values.server.vmbackupmanager.enable (not (or .Values.server.vmbackupmanager.eula .Values.license.key .Values.license.secret.name)) }}
|
|
||||||
{{ fail `Pass -eula command-line flag or valid license at .Values.license if you have an enterprise license for running this software.
|
|
||||||
See https://victoriametrics.com/legal/esa/ for details.
|
|
||||||
Documentation - https://docs.victoriametrics.com/enterprise.html
|
|
||||||
for more information, visit https://victoriametrics.com/products/enterprise/
|
|
||||||
To request a trial license, go to https://victoriametrics.com/products/enterprise/trial/`}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Return true if the detected platform is Openshift
|
|
||||||
Usage:
|
|
||||||
{{- include "common.compatibility.isOpenshift" . -}}
|
|
||||||
*/}}
|
|
||||||
{{- define "common.compatibility.isOpenshift" -}}
|
|
||||||
{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}}
|
|
||||||
{{- true -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC
|
|
||||||
Usage:
|
|
||||||
{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}}
|
|
||||||
*/}}
|
|
||||||
{{- define "common.compatibility.renderSecurityContext" -}}
|
|
||||||
{{- $adaptedContext := .secContext -}}
|
|
||||||
{{- if .context.Values.global.compatibility -}}
|
|
||||||
{{- if .context.Values.global.compatibility.openshift -}}
|
|
||||||
{{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}}
|
|
||||||
{{/* Remove incompatible user/group values that do not work in Openshift out of the box */}}
|
|
||||||
{{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}}
|
|
||||||
{{- if not .secContext.seLinuxOptions -}}
|
|
||||||
{{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}}
|
|
||||||
{{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- omit $adaptedContext "enabled" | toYaml -}}
|
|
||||||
{{- end -}}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{{- if and .Values.rbac.create (not .Values.rbac.namespaced) }}
|
|
||||||
kind: ClusterRole
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
metadata:
|
|
||||||
name: {{ template "victoria-metrics.fullname" . }}-clusterrole
|
|
||||||
labels:
|
|
||||||
{{- include "victoria-metrics.common.metaLabels" . | nindent 4 }}
|
|
||||||
{{- if .Values.rbac.extraLabels }}
|
|
||||||
{{ toYaml .Values.rbac.extraLabels | indent 4}}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.rbac.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{ toYaml . | indent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if or .Values.rbac.pspEnabled .Values.server.scrape.enabled }}
|
|
||||||
rules:
|
|
||||||
{{- if .Values.server.scrape.enabled }}
|
|
||||||
- apiGroups:
|
|
||||||
- discovery.k8s.io
|
|
||||||
resources:
|
|
||||||
- endpointslices
|
|
||||||
verbs: ["get", "list", "watch"]
|
|
||||||
- apiGroups: [ "" ]
|
|
||||||
resources:
|
|
||||||
- nodes
|
|
||||||
- nodes/proxy
|
|
||||||
- nodes/metrics
|
|
||||||
- services
|
|
||||||
- endpoints
|
|
||||||
- pods
|
|
||||||
verbs: [ "get", "list", "watch" ]
|
|
||||||
- apiGroups:
|
|
||||||
- extensions
|
|
||||||
- networking.k8s.io
|
|
||||||
resources:
|
|
||||||
- ingresses
|
|
||||||
verbs: [ "get", "list", "watch" ]
|
|
||||||
- nonResourceURLs: [ "/metrics" ]
|
|
||||||
verbs: [ "get" ]
|
|
||||||
{{- end }}
|
|
||||||
{{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }}
|
|
||||||
- apiGroups: ['extensions']
|
|
||||||
resources: ['podsecuritypolicies']
|
|
||||||
verbs: ['use']
|
|
||||||
resourceNames: [{{ template "victoria-metrics.fullname" . }}]
|
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
rules: []
|
|
||||||
{{- end }}
|
|
||||||
{{- end -}}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{{- if and .Values.rbac.create (not .Values.rbac.namespaced) }}
|
|
||||||
kind: ClusterRoleBinding
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
metadata:
|
|
||||||
name: {{ template "victoria-metrics.fullname" . }}-clusterrolebinding
|
|
||||||
labels:
|
|
||||||
{{- include "victoria-metrics.common.metaLabels" . | nindent 4 }}
|
|
||||||
{{- if .Values.rbac.extraLabels }}
|
|
||||||
{{ toYaml .Values.rbac.extraLabels | indent 4}}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.rbac.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{ toYaml . | indent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: {{ template "victoria-metrics.serviceAccountName" . }}
|
|
||||||
namespace: {{ .Release.Namespace }}
|
|
||||||
roleRef:
|
|
||||||
kind: ClusterRole
|
|
||||||
name: {{ template "victoria-metrics.fullname" . }}-clusterrole
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
{{- end -}}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{{ range .Values.extraObjects }}
|
|
||||||
---
|
|
||||||
{{ tpl (toYaml .) $ }}
|
|
||||||
{{ end }}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{{- if .Values.podDisruptionBudget.enabled }}
|
|
||||||
{{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }}
|
|
||||||
apiVersion: policy/v1
|
|
||||||
{{- else -}}
|
|
||||||
apiVersion: policy/v1beta1
|
|
||||||
{{- end }}
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ template "victoria-metrics.fullname" . }}
|
|
||||||
namespace: {{ .Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "victoria-metrics.common.metaLabels" . | nindent 4 }}
|
|
||||||
{{- if .Values.podDisruptionBudget.extraLabels }}
|
|
||||||
{{ toYaml .Values.podDisruptionBudget.extraLabels | indent 4}}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if .Values.podDisruptionBudget.minAvailable }}
|
|
||||||
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.podDisruptionBudget.maxUnavailable }}
|
|
||||||
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "victoria-metrics.server.matchLabels" . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }}
|
|
||||||
apiVersion: policy/v1beta1
|
|
||||||
kind: PodSecurityPolicy
|
|
||||||
metadata:
|
|
||||||
name: {{ template "victoria-metrics.fullname" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "victoria-metrics.common.metaLabels" . | nindent 4 }}
|
|
||||||
{{- if .Values.rbac.extraLabels }}
|
|
||||||
{{ toYaml .Values.rbac.extraLabels | indent 4}}
|
|
||||||
{{- end }}
|
|
||||||
annotations:
|
|
||||||
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
|
|
||||||
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
|
|
||||||
{{- if .Values.rbac.annotations }}
|
|
||||||
{{ toYaml .Values.rbac.annotations | indent 4}}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
privileged: false
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
requiredDropCapabilities:
|
|
||||||
# Default set from Docker, with DAC_OVERRIDE and CHOWN
|
|
||||||
- ALL
|
|
||||||
volumes:
|
|
||||||
- 'configMap'
|
|
||||||
- 'emptyDir'
|
|
||||||
- 'projected'
|
|
||||||
- 'secret'
|
|
||||||
- 'downwardAPI'
|
|
||||||
- 'persistentVolumeClaim'
|
|
||||||
hostNetwork: false
|
|
||||||
hostIPC: false
|
|
||||||
hostPID: false
|
|
||||||
runAsUser:
|
|
||||||
rule: 'RunAsAny'
|
|
||||||
seLinux:
|
|
||||||
rule: 'RunAsAny'
|
|
||||||
supplementalGroups:
|
|
||||||
rule: 'RunAsAny'
|
|
||||||
fsGroup:
|
|
||||||
rule: 'RunAsAny'
|
|
||||||
readOnlyRootFilesystem: false
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }}
|
|
||||||
{{- if .Values.rbac.create -}}
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: Role
|
|
||||||
metadata:
|
|
||||||
name: {{ template "victoria-metrics.fullname" . }}
|
|
||||||
namespace: {{ .Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "victoria-metrics.common.metaLabels" . | nindent 4 }}
|
|
||||||
{{- if .Values.rbac.extraLabels }}
|
|
||||||
{{ toYaml .Values.rbac.extraLabels | indent 4}}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.rbac.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{ toYaml . | indent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
- apiGroups: ['extensions']
|
|
||||||
resources: ['podsecuritypolicies']
|
|
||||||
verbs: ['use']
|
|
||||||
resourceNames: [{{ template "victoria-metrics.fullname" . }}]
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user