Portfolio

Case study

Rendered from the project README. Manifests are rendered and validated offline; nothing is deployed to a cluster. Vandelay Industries is fictional, not a client.

KubeHarbor

KubeHarbor is a static portfolio demo. It packages the fictional Vandelay Industries LedgerLite FastAPI API as a Helm chart, Kustomize overlays, and Argo CD application manifests. The manifests are rendered and validated offline. Nothing in this project is deployed to a cluster. kind was not run. There is no live cluster.

Vandelay Industries is fictional. The container image ghcr.io/OWNER/ledgerlite:0.1.0 is a placeholder and is not claimed to be published. The prod digest sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef is a placeholder.

The chart listens on port 8000. Probes use /healthz, /readyz, and a startup probe. The migrate Job runs alembic upgrade head.

What is rendered

Three environments, ledgerlite-dev, ledgerlite-staging, and ledgerlite-prod:

devstagingprod
replicas / HPA1 / off2 / 2–43 / 3–10
API resources50m/64Mi → 250m/256Mi100m/128Mi → 500m/256Mi250m/256Mi → 1/512Mi
PDBnoneminAvailable 1minAvailable 2
Postgresin-cluster StatefulSetexternalexternal
ServiceMonitoroffonon
ClusterIssuerletsencrypt-stagingletsencrypt-stagingletsencrypt-prod
Imagetag 0.1.0tag 0.1.0digest pin

helm template charts/ledgerlite with the default values fails on purpose. The error contains existingSecret. Set existingSecret to a Secret name, or set externalSecrets.enabled=true. The chart does not put a database URL or a password in values.

Extra objects

The minimum file list did not name every object the two renderers have to share. These were added so the Helm and Kustomize output stay in the same set:

The Kustomize migrate Job is a normal Job with argocd.argoproj.io/hook: PreSync. The Helm Job uses helm.sh/hook: pre-install,pre-upgrade. The consistency test ignores only those hook annotations (and the Helm checksum/config annotation).

Layout

Commands

From this directory:

make tools
      make render
      make check
      make showcase
      make test

make tools downloads pinned linux-amd64 binaries into .tools/ (gitignored) and checks the sha256 values hardcoded in scripts/install_tools.sh. Helm cache, config, data, and plugins stay under .tools/helm. checkov is installed into /tmp/kubeharbor-checkov. pytest, PyYAML, and Pygments are installed into .venv.

Pinned tools: helm v3.16.4, kustomize v5.4.3, kubeconform v0.6.7, kube-linter v0.7.6, helm-unittest v0.7.2, checkov 3.2.449.

make check lints the three values files with helm lint --strict, runs helm-unittest, kubeconform, kube-linter, checkov, and pytest, then writes results/checks.json. kubeconform uses -strict and local schemas only. It does not pass -ignore-missing-schemas. kubeconform v0.6.7 rejects the version token 1.30.x, so the command passes -kubernetes-version 1.30.14. The schema files are the v1.30.14-standalone-strict set plus the ServiceMonitor, Certificate, ExternalSecret, Application, and AppProject schemas. Every rendered file, the ExternalSecret render, and gitops/argocd/*.yaml are validated. Skipped resources must be 0.

Checkov runs the Kubernetes framework on rendered/ and gitops/, and the Helm framework on the chart. Skips are listed in policies/checkov-skips.md and policies/checkov.yaml. The page copies the counts from results/checks.json.

Secret names

Create the Secret in the target namespace before install. The value below is a placeholder, not a credential:

kubectl -n ledgerlite-dev create secret generic ledgerlite-dev-db \
        --from-literal=DATABASE_URL='REPLACE_ME' \
        --from-literal=POSTGRES_USER='REPLACE_ME' \
        --from-literal=POSTGRES_PASSWORD='REPLACE_ME' \
        --from-literal=POSTGRES_DB='REPLACE_ME'

Staging and prod only need DATABASE_URL in ledgerlite-staging-db and ledgerlite-prod-db. An ExternalSecret can point at the ClusterSecretStore name in values (vandelay-cluster-store in the defaults). That store is not a real cluster.

GitHub workflow

.github/workflows/k8s.yml would run make tools, make check, and make showcase on ubuntu-latest. This monorepo does not register that file, because GitHub only loads workflows from the repository root. The workflow is not executed here, and it has no secrets.

Installing on kind when Docker is available

These are instructions for a machine that has Docker and kind. They were not run for this demo. The showcase page does not claim that a kind cluster exists.

kind create cluster --name ledgerlite
      kubectl create secret generic ledgerlite-dev-db -n ledgerlite-dev \
        --from-literal=DATABASE_URL='REPLACE_ME' \
        --from-literal=POSTGRES_USER='REPLACE_ME' \
        --from-literal=POSTGRES_PASSWORD='REPLACE_ME' \
        --from-literal=POSTGRES_DB='REPLACE_ME' || true
      helm install ledgerlite charts/ledgerlite \
        --namespace ledgerlite-dev --create-namespace \
        -f charts/ledgerlite/values-dev.yaml
      kubectl apply -k kustomize/overlays/dev
      kubectl apply -f gitops/argocd/project.yaml
      kubectl apply -f gitops/argocd/app-dev.yaml
      kind delete cluster --name ledgerlite

The namespace create and the Secret will race if you paste this as one script. Create the namespace, then the Secret, then install. The image pull will fail until a real image replaces the placeholder.

Showcase

https://3.1.79.63/portfolio/kubeharbor/ is a static page. It has no process and no port. The footer states that the manifests were rendered and validated offline, that nothing was deployed, and that the client is fictional.

Open the live demo