Maybe a bit more on the overkill side, but I use Talos Linux (declarative K8s distribution), then Terraform for initial setup and FluxCD for everything else (including VMs via Kubevirt). It's a hell of an initial learning curve, but afterwards I just do my talosctl upgrade and upgrade-k8s from time to time, and don't have to worry about anything else. Upside is, Kubernetes provides a unified, extensible API for everything, for example:
- reverse proxy via Ingress or Gateway-API
- firewall via NetworkPolicy
- even databases like Postgres through an Kubernetes Operator like CNPG, with a similar simplicity as with the big cloud providers (just a single yaml file with the specs like storage capacity, CPU and memory limits, backup target and schedule etc.)
- it is very scriptable (everything is managed via the API)
- automated image updates via either FluxCD itself or just dependabot/RenovateBot creating PRs to your GitOps repo
Downsides:
- you have to figure out persistent storage (CSI), which is slightly more complicated than just a single filesystem and manually specifying volume mounts like with docker, but if done right, you have a simple interface with powerful capabilities via the Kubernetes API
- there are simple CSI implementations that just expose node local disks via LVM or ZFS, so if you just have a single node, or don't care about replication, it's fairly easy to get started
- initial learning curve is quite high, especially if you have no prior experience with container orchestration in general
- definitely overkill if you just want something simple that "just works"