All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 56s
The ingress pointed at scottyah-tls, a secret hand-copied between namespaces and absent from this one, so Traefik fell back to a self-signed certificate. That is invisible behind Cloudflare until the SSL mode is set to Full (strict), which then fails with a 526. Issue into the namespace over DNS-01 instead. Nothing to copy, and the renewal is no longer a thing anyone has to remember. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
164 lines
4.2 KiB
YAML
164 lines
4.2 KiB
YAML
---
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: fit
|
|
|
|
---
|
|
# The whole log is one JSON file, so the "database" is this volume. It is
|
|
# ReadWriteOnce, which is why the deployment below replaces rather than rolls.
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: fit-data-pvc
|
|
namespace: fit
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: fit-svc
|
|
namespace: fit
|
|
spec:
|
|
selector:
|
|
app: fit
|
|
ports:
|
|
- port: 80
|
|
targetPort: 8080
|
|
protocol: TCP
|
|
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: fit-dep
|
|
namespace: fit
|
|
spec:
|
|
replicas: 1
|
|
# Two pods would both hold the file in memory and overwrite each other's
|
|
# writes, and the volume only attaches to one node anyway. Recreate makes the
|
|
# old pod let go before the new one starts.
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app: fit
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: fit
|
|
spec:
|
|
imagePullSecrets:
|
|
- name: harborcred
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 65534
|
|
runAsGroup: 65534
|
|
# Without fsGroup the volume comes up owned by root and nobody cannot
|
|
# write the file it exists to hold.
|
|
fsGroup: 65534
|
|
containers:
|
|
- name: fit
|
|
image: harbor.scottyah.com/scottyah/fit:latest
|
|
imagePullPolicy: Always
|
|
ports:
|
|
- containerPort: 8080
|
|
env:
|
|
- name: ADDR
|
|
value: ":8080"
|
|
- name: BASE_URL
|
|
value: "https://fit.scottyah.com"
|
|
- name: DATA_PATH
|
|
value: "/data/fit.json"
|
|
# Every date in the app is a local date, so this decides when the
|
|
# day rolls over.
|
|
- name: TZ_NAME
|
|
value: "America/Los_Angeles"
|
|
- name: GOMEMLIMIT
|
|
value: "40MiB"
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /data
|
|
resources:
|
|
requests:
|
|
memory: "16Mi"
|
|
cpu: "10m"
|
|
limits:
|
|
memory: "64Mi"
|
|
cpu: "200m"
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /healthz
|
|
port: 8080
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 20
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /healthz
|
|
port: 8080
|
|
initialDelaySeconds: 2
|
|
periodSeconds: 10
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
# /data is the only thing the process writes.
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
volumes:
|
|
- name: data
|
|
persistentVolumeClaim:
|
|
claimName: fit-data-pvc
|
|
|
|
---
|
|
# The app has no login of its own; this is the only thing between the log and
|
|
# the internet, so the Service must not be exposed any other way.
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: Middleware
|
|
metadata:
|
|
name: fit-basic-auth
|
|
namespace: fit
|
|
spec:
|
|
basicAuth:
|
|
secret: fit-basic-auth
|
|
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: fit-ingress
|
|
namespace: fit
|
|
annotations:
|
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
|
traefik.ingress.kubernetes.io/router.middlewares: fit-fit-basic-auth@kubernetescrd
|
|
# cert-manager watches the tls block below and issues into this namespace,
|
|
# over DNS-01 at Cloudflare. A TLS secret cannot be shared across
|
|
# namespaces, and hand-copying one leaves a certificate nothing renews.
|
|
cert-manager.io/cluster-issuer: letsencrypt-prod-cloudflare
|
|
spec:
|
|
ingressClassName: traefik
|
|
tls:
|
|
- hosts:
|
|
- fit.scottyah.com
|
|
# Created and renewed by cert-manager. It does not exist until the
|
|
# first issue succeeds, and the site does not serve a valid cert
|
|
# until then.
|
|
secretName: fit-tls
|
|
rules:
|
|
- host: fit.scottyah.com
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: fit-svc
|
|
port:
|
|
number: 80
|