Skip to content

Deploy to production

For a real install, layer your own kustomize overlay on top of distribution/kubernetes/overlays/standalone/. The standalone overlay provisions everything you need to start:

ComponentRole
backendSpring Boot API
uiAngular web app
init-dbOne-shot schema bootstrap
database *PostgreSQL + nightly backup CronJob
storage *Embedded MinIO (S3-compatible object storage)
ingressHTTP entry point on your chosen domain

* Bundled but optional — bring your own

The bundled database and storage are there so the standalone overlay works out of the box. Both are fully optional:

  • PostgreSQL — point Podcast-Server at any existing PostgreSQL by overriding the database ConfigMap (dns, name, username) and Secret (password). Then drop the bundled database Deployment from your overlay. Managed Postgres (RDS, Cloud SQL, CloudNativePG…) all work.
  • Object storage — any S3-compatible bucket works. Override the storage ConfigMap (url, bucket, username) and Secret (password), then drop the bundled MinIO. Tested against MinIO, but anything implementing the S3 API will do (AWS S3, Backblaze B2, Cloudflare R2, Garage, SeaweedFS…).

Just evaluating or hacking on the code?

Skip the production setup and use the local dev path — a fresh k3d cluster, ready in 5 minutes.

Prerequisites

  • A Kubernetes cluster — k3s, MicroK8s, minikube, Docker Desktop with Kubernetes enabled… Managed distributions (GKE, AKS, EKS) work too but are overkill for a home server.
  • kubectl v1.27+ (built-in kustomize v5+) — or a standalone kustomize v5+.
  • linux/amd64 node(s). arm is not supported.

1. Create your own overlay

Don't apply standalone directly — wrap it so you can keep your customizations in git:

yaml
# my-podcast-server/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: podcast-server

resources:
  # Pin a specific release. See the GitLab tags page for available versions.
  - https://gitlab.com/davinkevin/Podcast-Server.git/distribution/kubernetes/overlays/standalone?ref=v6.x.y

configMapGenerator:
  - name: installation-parameters
    behavior: merge
    literals:
      - location=/opt                     # base host dir for podcast files + DB
      - domain=podcast.mydomain.local     # the Ingress hostname

secretGenerator:
  - name: database
    behavior: merge
    literals:
      - password=<change-me>
  - name: storage
    behavior: merge
    literals:
      - password=<change-me>
  - name: podcast-server
    behavior: merge
    literals:
      - api.youtube=<your YouTube Data API key>
    type: Opaque

Override the default passwords

The standalone overlay ships with publicly-known default passwords for the database and the object storage. You must override them in your overlay before applying.

YouTube API key is optional

Skip the api.youtube literal if you don't plan to consume YouTube podcasts.

2. Create the host directories

The standalone overlay mounts host paths for the podcast files, the database and the database backups. Create them on the node(s) where workloads will be scheduled, using the same base path you set in location:

bash
export PODCAST_SERVER_LOCATION=/opt/podcast-server
mkdir -p \
  $PODCAST_SERVER_LOCATION/files/ \
  $PODCAST_SERVER_LOCATION/database/data \
  $PODCAST_SERVER_LOCATION/database/init \
  $PODCAST_SERVER_LOCATION/database/backup/

3. Apply

bash
kubectl apply -k my-podcast-server/

Image pulls and the init-db initContainer take a few minutes the first time. After that, the app answers on the domain you configured.

Going further

Once standalone is running, real-world deployments usually layer in:

  • Resource requests/limits + JVM tuning (e.g. Shenandoah GC for the backend)
  • ObservabilityServiceMonitor for Prometheus, Grafana dashboards for downloads/updates
  • Secrets out of gitsops or external-secrets for credentials
  • Pinned, rolled releases — pin image tags and add a small CronJob that rolls Deployments when a new tag ships

Each is a small kustomize component, patch, or configMapGenerator merge in your overlay.

Released under the Apache 2.0 License.