Add reuse service landing page

This commit is contained in:
2026-06-15 15:40:57 +02:00
parent b76cdb53a8
commit b859530fcf
14 changed files with 589 additions and 12 deletions

View File

@@ -17,9 +17,30 @@ app.kubernetes.io/name: {{ include "reuse.fullname" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "reuse.landingFullname" -}}
{{- printf "%s-landing" (include "reuse.fullname" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "reuse.redirectMiddlewareName" -}}
{{- printf "%s-redirect-https" (include "reuse.fullname" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "reuse.landingSelectorLabels" -}}
app.kubernetes.io/name: {{ include "reuse.fullname" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: landing
{{- end -}}
{{- define "reuse.image" -}}
{{- if not .Values.image.tag -}}
{{- fail "image.tag is required - pin it in helm/reuse-surface-values.yaml" -}}
{{- end -}}
{{- printf "%s:%s" .Values.image.repository .Values.image.tag -}}
{{- end -}}
{{- end -}}
{{- define "reuse.landingImage" -}}
{{- if not .Values.landing.image.tag -}}
{{- fail "landing.image.tag is required when landing.enabled=true" -}}
{{- end -}}
{{- printf "%s:%s" .Values.landing.image.repository .Values.landing.image.tag -}}
{{- end -}}

View File

@@ -2,7 +2,9 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "reuse.fullname" . }}
labels: {{- include "reuse.labels" . | nindent 4 }}
labels:
{{- include "reuse.labels" . | nindent 4 }}
app.kubernetes.io/component: api
spec:
replicas: {{ .Values.replicaCount }}
selector:
@@ -14,7 +16,9 @@ spec:
maxUnavailable: 0
template:
metadata:
labels: {{- include "reuse.selectorLabels" . | nindent 8 }}
labels:
{{- include "reuse.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: api
spec:
enableServiceLinks: false
securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }}
@@ -78,4 +82,4 @@ spec:
{{- end }}
{{- with .Values.tolerations }}
tolerations: {{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -18,6 +18,24 @@ spec:
- host: {{ .Values.ingress.host }}
http:
paths:
{{- if .Values.landing.enabled }}
{{- range .Values.ingress.apiPaths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "reuse.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
- path: /
pathType: Prefix
backend:
service:
name: {{ include "reuse.landingFullname" . }}
port:
number: {{ .Values.landing.service.port }}
{{- else }}
- path: /
pathType: Prefix
backend:
@@ -25,4 +43,5 @@ spec:
name: {{ include "reuse.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,135 @@
{{- if .Values.landing.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "reuse.landingFullname" . }}
labels:
{{- include "reuse.labels" . | nindent 4 }}
app.kubernetes.io/component: landing
data:
index.html: |
{{ if .Values.landing.html }}
{{ tpl .Values.landing.html . | nindent 4 }}
{{ else }}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{- if .Values.landing.noindex }}
<meta name="robots" content="noindex,nofollow">
{{- end }}
{{- if and .Values.landing.redirect.enabled .Values.landing.redirect.target }}
<meta http-equiv="refresh" content="{{ .Values.landing.redirect.delaySeconds }}; url={{ .Values.landing.redirect.target }}">
{{- end }}
<title>{{ .Values.landing.title }}</title>
<style>
:root {
color-scheme: light;
--ink: #1d2733;
--muted: #536271;
--line: #d9e0e7;
--paper: #f8fafc;
--accent: #2066a8;
--accent-dark: #164b7e;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: var(--ink);
background: var(--paper);
display: grid;
place-items: center;
padding: 32px 18px;
}
main {
width: min(100%, 720px);
border: 1px solid var(--line);
border-radius: 8px;
background: #ffffff;
padding: clamp(28px, 5vw, 48px);
box-shadow: 0 18px 48px rgba(29, 39, 51, 0.08);
}
.eyebrow {
margin: 0 0 12px;
color: var(--accent-dark);
font-size: 0.86rem;
font-weight: 700;
text-transform: uppercase;
}
h1 {
margin: 0;
font-size: clamp(2rem, 7vw, 3rem);
line-height: 1.05;
}
p {
max-width: 62ch;
margin: 18px 0 0;
color: var(--muted);
font-size: 1rem;
line-height: 1.65;
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 28px;
}
a {
color: var(--accent);
}
.button {
display: inline-flex;
min-height: 44px;
align-items: center;
justify-content: center;
border-radius: 6px;
background: var(--accent);
color: #ffffff;
padding: 0 18px;
font-weight: 700;
text-decoration: none;
}
.button:focus,
.button:hover {
background: var(--accent-dark);
}
.links {
margin-top: 26px;
padding-top: 22px;
border-top: 1px solid var(--line);
display: grid;
gap: 10px;
}
</style>
</head>
<body>
<main>
<p class="eyebrow">{{ .Values.landing.eyebrow }}</p>
<h1>{{ .Values.landing.title }}</h1>
<p>{{ .Values.landing.body }}</p>
{{- $target := .Values.landing.primaryUrl }}
{{- if and .Values.landing.redirect.enabled .Values.landing.redirect.target }}
{{- $target = .Values.landing.redirect.target }}
{{- end }}
{{- if $target }}
<div class="actions">
<a class="button" href="{{ $target }}">{{ .Values.landing.buttonLabel }}</a>
</div>
{{- end }}
{{- if .Values.landing.links }}
<nav class="links" aria-label="Service links">
{{- range .Values.landing.links }}
<a href="{{ .url }}">{{ .label }}</a>
{{- end }}
</nav>
{{- end }}
</main>
</body>
</html>
{{ end }}
{{- end }}

View File

@@ -0,0 +1,59 @@
{{- if .Values.landing.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "reuse.landingFullname" . }}
labels:
{{- include "reuse.labels" . | nindent 4 }}
app.kubernetes.io/component: landing
spec:
replicas: 1
selector:
matchLabels:
{{- include "reuse.landingSelectorLabels" . | nindent 6 }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
{{- include "reuse.landingSelectorLabels" . | nindent 8 }}
spec:
enableServiceLinks: false
containers:
- name: landing
image: {{ include "reuse.landingImage" . | quote }}
imagePullPolicy: {{ .Values.landing.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.landing.service.targetPort }}
protocol: TCP
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 3
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 3
failureThreshold: 3
resources: {{- toYaml .Values.landing.resources | nindent 12 }}
volumeMounts:
- name: landing-page
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
readOnly: true
volumes:
- name: landing-page
configMap:
name: {{ include "reuse.landingFullname" . }}
{{- end }}

View File

@@ -0,0 +1,18 @@
{{- if .Values.landing.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "reuse.landingFullname" . }}
labels:
{{- include "reuse.labels" . | nindent 4 }}
app.kubernetes.io/component: landing
spec:
type: ClusterIP
selector:
{{- include "reuse.landingSelectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.landing.service.port }}
targetPort: http
protocol: TCP
{{- end }}

View File

@@ -0,0 +1,23 @@
{{- if and .Values.ingress.enabled .Values.ingress.redirectHttp.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "reuse.fullname" . }}-http-redirect
labels: {{- include "reuse.labels" . | nindent 4 }}
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.middlewares: {{ printf "%s-%s@kubernetescrd" .Release.Namespace (include "reuse.redirectMiddlewareName" .) | quote }}
spec:
ingressClassName: {{ .Values.ingress.className }}
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "reuse.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}

View File

@@ -0,0 +1,11 @@
{{- if and .Values.ingress.enabled .Values.ingress.redirectHttp.enabled }}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: {{ include "reuse.redirectMiddlewareName" . }}
labels: {{- include "reuse.labels" . | nindent 4 }}
spec:
redirectScheme:
scheme: https
permanent: {{ .Values.ingress.redirectHttp.permanent }}
{{- end }}

View File

@@ -5,9 +5,11 @@ metadata:
labels: {{- include "reuse.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector: {{- include "reuse.selectorLabels" . | nindent 4 }}
selector:
{{- include "reuse.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: api
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
protocol: TCP

View File

@@ -26,11 +26,48 @@ resources:
envSecretName: reuse-surface-env
landing:
enabled: false
image:
repository: nginxinc/nginx-unprivileged
tag: "1.27-alpine"
pullPolicy: IfNotPresent
service:
port: 8080
targetPort: 8080
noindex: true
title: "Railiance service endpoint"
eyebrow: "Railiance S5"
body: "This endpoint is available for automated clients and operators."
buttonLabel: "Continue"
primaryUrl: ""
redirect:
enabled: false
target: ""
delaySeconds: 5
links: []
html: ""
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 50m
memory: 64Mi
ingress:
enabled: true
className: traefik
host: reuse.coulomb.social
tls: true
redirectHttp:
enabled: false
permanent: true
apiPaths:
- path: /health
pathType: Exact
- path: /v1
pathType: Prefix
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
@@ -56,4 +93,4 @@ securityContext: {}
nodeSelector: {}
tolerations: []
affinity: {}
affinity: {}