Skip to content

First app (prove the path)

Waves Healthy is not the same as “a browser got a real cert.” This page is one throwaway app in your template copy. Delete it when you are done. Do not add it to the public starter.

Validation

Do not create values/whoami/ until every item is true:

Check Expect
Waves 0–4 in Argo Synced / Healthy
kubectl -n nginx-ingress get svc EXTERNAL-IP = ingress VIP
dig +short dummy.k8s.home.example.com from a laptop that VIP (wildcard is enough)
kubectl get stepclusterissuer Ready
Laptop trust store Step-CA root installed

A missing row is a wave / DNS / Step-CA problem. This page will not fix it.

1. Namespace + whoami

values/whoami/ in your copy:

# values/whoami/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: whoami
resources:
  - ns.yaml
  - deploy.yaml
  - svc.yaml
  - ingress.yaml
# values/whoami/ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: whoami
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted
# values/whoami/deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
spec:
  replicas: 1
  selector:
    matchLabels: { app: whoami }
  template:
    metadata:
      labels: { app: whoami }
    spec:
      containers:
        - name: whoami
          image: traefik/whoami:v1.10
          ports:
            - containerPort: 80
# values/whoami/svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: whoami
spec:
  selector: { app: whoami }
  ports:
    - name: http
      port: 80
      targetPort: 80
# values/whoami/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: whoami
  annotations:
    cert-manager.io/issuer: step-issuer
    cert-manager.io/issuer-kind: StepClusterIssuer
    cert-manager.io/issuer-group: certmanager.step.sm
    nginx.org/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts: ["whoami.k8s.home.example.com"]
      secretName: whoami-tls
  rules:
    - host: whoami.k8s.home.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: whoami
                port:
                  name: http

2. Application

applications/whoami.yaml — manifests only, wave 11. path: values/whoami. Same repoURL as the other Applications. CreateNamespace optional (the Namespace is in the kustomization).

Push. Wait for the Application to go Healthy. Do not open a browser until the ladder below is green.

3. Ladder

kubectl -n whoami get deploy,svc,ingress,certificate
# Certificate Ready=True

dig +short whoami.k8s.home.example.com
# 10.0.0.30

curl -vI https://whoami.k8s.home.example.com
# issuer = Home Lab CA, HTTP 200

Validation

All three of Certificate Ready=True, dig = ingress VIP, and curl issuer = Home Lab CA must pass before you call the platform done. Browser with the root installed: padlock, whoami headers. If any step fails, use the table — do not add Grafana Ingress on top of a broken whoami.

Failure Likely
Certificate Issuing Step-CA annotations / caBundle / Unraid:9005
dig empty Wildcard missing; external-dns TSIG; LAN forward. DNS
curl connection refused Ingress Service has no EXTERNAL-IP. MetalLB pool / L2
Browser warns, curl fine Firefox store, or you typed https://10.0.0.30 (no SAN)
404 on the VIP by IP Expected. SNI needs the hostname

4. Optional: public name

Second Ingress (or a second host on the same one) with cluster-issuer: letsencrypt, http01-edit-in-place, issue-temporary-certificate. Public DNS + WAN 80 to .30. Staging first. If the Application self-heals, ignore that Ingress /spec/rules or Argo strips the ACME path. Day-2.

Validation

Do not switch letsencrypt server to production ACME until: public dig for that hostname returns the WAN address (or the VIP if you 1:1 NAT), curl -sI http://<public-name>/.well-known/acme-challenge/probe hits this nginx (not a node), and a staging Certificate reached Ready. Production rate limits will punish a broken NAT. Same issuer name; only the directory URL changes (wave 4).

5. Tear down

Delete applications/whoami.yaml and values/whoami/, push. Prune removes the namespace if prune: true.