Comment by Lucasoato
4 days ago
> I prefer running services natively when possible, but will containerize complex services or those with many dependencies. Love: a service that’s a single Go binary. A service that only comes as a Docker compose file and wants to run MySQL, Redis, and three other containers? I’m already looking for an alternative.
Ok, I respect your opinion, but remember that there are poor souls like me out there that actually love the opposite.
> Ok, I respect your opinion, but remember that there are poor souls like me out there that actually love the opposite.
All things being equal, why prefer Docker Compose? From my perspective, a single binary strictly dominates any Docker Compose solution.
Isolation from the main system, other services, and other dependencies.
Easy to migrate to new system.
Easy to upgrade and downgrade. When a new version causes an issue just restart it with an older version.
One directory to backup and restore that contains all the services and their settings.
A single binary accomplishes most of those things just fine. Only thing it doesn't get you is isolation, but you can isolate things if you want even then (for example, FreeBSD jails are dead easy to set up).
9 replies →
A single config file in a directory beats all.
All my home server apps are in /apps/app-name/ all have a docker config... All data and configurations are mounts under that directory or to my library. It's really straight forward.
I don't have to hunt for different configuration files, each app has what it needs.
I can spin down, move and get back up in a minute or two. All in a consistent way to the platform.
The overhead for Docker isn't near a full vm, it's maybe 2-3% if that.
>The overhead for Docker isn't near a full vm, it's maybe 2-3% if that.
Interesting, I run audiobookshelf bare metal on my old laptop that only has 8gb of ram. I've considered using a docker container but my experience using rancher for work is that it sits there chewing up 4GB of ram on my company MBP.
Maybe I'm wrong but I've never seen the point in a self hosted app running in a container when it seems much lighter to just run the app?
I don't use Docker but I love reading the compose file when a project has it. It is the quickest way for me to get a high level idea of this project's architecture. It's the best documentation :)
This. Docker compose is so great that you don’t even need to use it, for it to be useful. It can describe so well the dependencies your system needs (alongside proper documentation).
It’s the unified interface for me. Updates, logs, service management, network routing, config and storage mapping are all uniform and I don’t have to wrangle many slightly different implementations of each. Isolation from installed packages is a nice bonus.
I too prefer the Docker compose route. If you give me a single binary, I'll go out of my way to run it inside a compose stack.
I manage my home server with a script that presumes the service is running on a compose stack. So I can run stuff like `stack freshrss restart`. I don't want to touch my scripts, I just add the compose file to some expected path and the script finds it based on naming conventions.
I use Docker Compose so that I don't have to care if the daemon is a single binary or a whole stack: I can use the same setup for everything, and deploying an entire new thing in a maintainable way is quick and easy. Each app's startup/shutdown is managed using the same templated systemd unit, and Traefik handles the routing and Let's Encrypt cert creation and renewal.
Basically I want things reliable and low-maintenance and this setup gives me that.
for long-running services, I've never taken the time to learn something reliable like systemd. with Compose, I can see everything I need to know in one yml file and the commands to go with it. I also don't have to really understand any dependencies or their own configuration and can cleanly remove everything associated with that service with a few commands.
You can use systemd and docker compose together. A systemd service is a single config file that runs the commands you give it, including `docker-compose` commands. Everything else about your service is still orchestrated via docker, and you can still run commands against the running containers just like before.
A big win with very little effort is systemd starting your docker compose service on boot. You have your systemd config file set `ExecStart` to call your docker-compose command, throw the config file into your systemd folder, and tell systemd to enable it. Docker compose handles the rest.
1 reply →
I like to have consistent architecture across all my services, and I like to see and configure everything in (mostly) one place. If you're running a single go binary, sure do whatever, but if you're running a go binary, and a *arr stack, and a bookmarking service, home assistant, frigate, etc, it gets out of hand pretty quickly.
You trade a bit of upfront setup (I mean barely now in the age of LLMs) for easier automation and flexibility down the road. I use docker compose to run my local dev stack and qa envs, but then can do whatever I want with the containers for prod. Google Cloud Run, Amazon, whatever. Right now I do just actually use docker compose behind nginx in prod, but I've used basically the same docker compose setup for all my projects that aren't large distributed systems in the last 10 years. And when the system gets too big, I refactor it into k8s, but k8s is overkill for like 99% of my personal projects and like 75% of my professional projects.
I’ve been a die hard native package or static binary proponent for a long time. I still hold that there are real advantages.
As podman has improved and compose stacks have improved, I’ve conceded that containers simplify deployment and updates and isolation, and at this point I find for me the benefits more than outweigh the hassles.
Instead of crafting a set of ansible plays that do all the manual native installation steps, I have a relatively lightweight ansible rig that reads containers and relationships desired from a manifest in inventory, then builds or modifies compose files, then just deploys. Much less futzing. And I’m more likely to keep things up to date regularly as a result
Or, increasingly, dispatch codex to handle it for me
In this way I update home assistant across multiple instances now like magic. I don’t even dread it a little anymore
Its a single config that lets you run multiple services (and can keep them running), upgrades are just editing an image tag.
Don't have to look at cli docs to figure out how to run it.
Doesn't have access to my file system, logs are easy.
Some isolation is nice. I say some because I’m told it’s security is not to be trusted, but I still like that even a non nefarious binary has ootb boundaries on what state will persist.
docker isolation is nice just as a management boundary. It's nice to be sure applications don't accidently shit all over each other. Like an application that decides to clear /tmp because reasons, or 2 random ones that both store temp state in a /tmp/state.dat for some odd reason.
My favorite is applications that conflict on ports. So you go to change the port an application is listening on, the docs say PORT env var so you set it, but it doesn't work.
You look through the code (and this is before LLMs) but the config is just a labyrinth of values flowing from god knows where. So you search the repo for PORT and eventually find a PR from 2 weeks ago that changes PORT to ENDPOINT, so you set ENDPOINT, but it still doesn't work.
Then you find an issue that was opened last night that the new `ENDPOINT` value doesn't load from env vars because it conflicts with another ENDPOINT_ prefix on another value, instead you need to create a config.toml and set an `endpoint =` in that, so you do that.
Then you realize that creating an empty config.toml has now overridden all the previously defaulted values into nulls or empty strings, instead you need to run `foo config-defaults > config.toml` and go edit the endpoint one.
Only to realize that there is a secret that the tool uses to encrypt an ephemeral session. if you don't specify one, the tool would auto generate one on startup. The only downside is restarting it logs your client out which isn't a big deal. But now that you switched to config.toml you must set some value there and it can't be empty
Then you're just wondering why the hell did I want to change the port?
Docker isolation is likely good enough if you keep your kernel up to date and aren't allowing 3rd parties to run code. If you are running a CI service or something you need micro VMs. But to host your nextcloud server, docker is good enough, it's unlikely someone will both exploit nextcloud and the kernel if you are keeping them up to date.
1 reply →
Not OP, but i prefer a single binary on docker, at least i know it won't fuck up my filesystem when i do something stupid with it.
Or at least i can reinstall any time i want, because i know it won't leave any trash in my filesystem and when reinstalling, it won't reuse those outdated files
A big reason I chose Rust and Sqlite for my project was that end users could just run the small binary and be done with it. https://github.com/sergiotapia/joyscroller
I think you can go very very far with this kind of setup especially if it's just for you.
Agreed and everyone’s talking about Docker Compose while I’m putting everything in k8s.
And I must also add that docker containers are not actually that heavy.
I have a 10 year old, dual core, 8gb DDR3 laptop serving somewhere around 20 dockers for different kinds of services and it runs just fine. Even 2 clients transcoding some media usually works ok.
PS: It is not currently on, more due to it being a clunky machine with structural problems then the hardware itself. I should get it a 3d printed desktop case
Whenever redis, mysql or postgres rear their head it raises all sorts of ugly questions like do you let apps share databases, how do you do backups, etc.
For apps that will have 1-3 users and a few hits a day a sqlite file is far less operational overhead and can be backed up with all of the other files that app has.
I like "a service that's a single Go binary" just like the author does, but deploying that in a FROM scratch docker container is arguabdy the best of both worlds? You get the self contained container, it's not bloated, runs at native speed, works with docker tooling...
I don't hate docker. I just don't like that it seems to keep systems from going into sleep/standby mode, because it keeps writing things from time to time.
I would like to have Debian headless mini servers that consume as less power as possible when nobody needs them, only activate when someone needs them and then drop back to using as less power as possible as fast as possible. I'm not expert enough how to get that done using Docker. Debian just because i have the most experience with that linux OS. Curent pi-hole/samba/navidrome server powers down the 2.5" sata drive and goes to cpu C6/8 state pretty fast, but is avaiable within 2 seconds when needed. Don't have much time to tinker a lot. Sometimes stuff just has to work.
Using Immich without Docker also seems complicated.
Same here, just give me a compose file and lets go!
You're not alone!