env-view: a custom Helm chart for per-environment service dashboards
Published: 2026-03-24
Every Kubernetes environment has a links.{env}.test.antonnovikov.com page — a static dashboard listing every service URL for that environment. It's built from a custom Helm chart called env-view, stored in charts/env-view/ in the infra repo. No external dependencies, no SPAs with build steps — just nginx serving rendered HTML from a ConfigMap.
What it is
A single-page app served by nginx. The chart renders an HTML page with cards for every service: Prometheus, Grafana, Kibana, APISIX admin, Headlamp, Hubble UI, Allure, SonarQube, and more.
Each environment's page shows only the services that exist there. infra shows Vault, Allure, SonarQube, Grafana. dev shows Prometheus, Kibana, Headlamp. The enabled/disabled state is controlled by Helm values.
HelmRelease in base
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: env-view
spec:
interval: 1h
chart:
spec:
chart: ./charts/env-view
version: 25.0.0
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
values:
image:
tag: 2ec9214f
pullPolicy: Always
ingress:
enabled: true
annotations:
description: "Просмотр сервисов и состояния кластера"
environments:
- name: Infra
url: https://links.infra.test.antonnovikov.com
enabled: true
- name: Development
url: https://links.dev.test.antonnovikov.com
enabled: true
- name: Test
url: https://links.test.test.antonnovikov.com
enabled: true
- name: Demo
url: https://links.demo.test.antonnovikov.com
enabled: false
The environments list renders a navigation header — clicking a cluster name jumps to that cluster's env-view page.
Per-environment patch
yaml# projects/dev/kustomization/hub/patches/env-view.yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: env-view
namespace: dev
spec:
values:
ingress:
host: links.dev.test.antonnovikov.com
services:
- name: Prometheus
url: https://prometheus.dev.test.antonnovikov.com
category: monitoring
- name: Elasticsearch
url: https://elasticsearch.dev.test.antonnovikov.com
category: logs
- name: Headlamp
url: https://headlamp.dev.test.antonnovikov.com
category: cluster
- name: Hubble UI
url: https://hubble.dev.test.antonnovikov.com
category: network
Chart structure
charts/env-view/
├── Chart.yaml
├── values.yaml
├── templates/
│ ├── configmap.yaml ← rendered HTML with service cards
│ ├── deployment.yaml ← nginx serving the configmap
│ ├── service.yaml
│ ├── ingress.yaml
│ └── servicemonitor.yaml
templates/configmap.yaml renders the service list into an nginx index.html using Go templates. The deployment mounts the ConfigMap as /usr/share/nginx/html/index.html. No runtime logic — just a static file delivered by nginx.
The ServiceMonitor exposes nginx metrics (connections, request rate) to Prometheus.
Configmap template excerpt
yaml# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: env-view-html
data:
index.html: |
<!DOCTYPE html>
<html>
<head><title>{{ .Values.ingress.host }}</title></head>
<body>
<nav>
{{- range .Values.environments }}
{{- if .enabled }}
<a href="{{ .url }}">{{ .name }}</a>
{{- end }}
{{- end }}
</nav>
<main>
{{- range .Values.services }}
<div class="card category-{{ .category }}">
<a href="{{ .url }}">{{ .name }}</a>
</div>
{{- end }}
</main>
</body>
</html>
Image versioning
The image.tag is a short git SHA: 2ec9214f. The image is built from the chart repo's Dockerfile and pushed to a private registry. Updating the UI means bumping the tag in base/web/env-view/helmrelease.yaml and committing.
With Flux Image Automation, this can be automated — Flux watches the registry tag and opens a PR when a new SHA is pushed.
Why a custom chart instead of a static page
- The service list changes as environments evolve — having it in Helm values means Flux manages it
- The
environmentsnavigation header needs to know about all clusters — defined once in base - The ServiceMonitor is included — nginx availability tracked in Prometheus
- Patching per-environment URLs is clean with Kustomize, no manual file editing