86 comments

[ 3.0 ms ] story [ 88.7 ms ] thread
TIL about limiting logs. Very useful, I had no idea.
I think many of these issues are also solved by Podman and systemd depending on what kind of "production" you're building for. If you're building a linux-y appliance and you need to run a few containers I think Podman is a much better and more ergonomic way of doing so. I think perhaps that's less true for running a web service (where the linux environment is just a means to that end).
I desperately WANT to like podman quadlets and keep trying to find a use case for them. But I always got the impression that the developers who implemented quadlets never actually had to manage multiple containers in a real production environment.

Having your whole application with its containers, volumes, and networks all defined together in one easy-to-read YAML file is a way better experience. Deployment is two steps: 1. `git clone foo` 2. `docker compose up -d`. You can see the state of the application containers with `docker compose ps`. You can run multiple compose applications on the same host and manage them separately by putting them in different directories.

With quadlets, you delegate everything to systemd. You have to break the configuration up into a bunch of tiny unit files and then separately copy them to /etc or a dedicated user's dotfiles. An application with a handful of containers and multiple networks/volumes/etc can spiral into a dozen unit files. Good luck SSH'ing into an unfamiliar system and understanding at a glance what it's doing. It is far more annoying to predictably deploy and tightly couples your application configuration to the host system configuration. (Even moreso if you created dedicated users for each application, which I understand is the recommended solution.)

If I'm just holding it wrong and there exists some better tooling to manage podman in prod that I don't know about, I'm happy to hear about it.

> I think perhaps that's less true for running a web service (where the linux environment is just a means to that end).

If some BSD would support OCI containers, I would run my apps on BSD.

Very cool article. Wish it didn't have silly AI-isms:

> This is the shape Distr lands on

I quite like the “shape” term; every type of (sigh…) stakeholder … understands it, and I don’t need to swap in terms like “interface”, api, contract, architecture, structure, etc - unless I want to talk specifically about that thing. Everyone can fit a triangle and parallelogram in their mind, which is just dandy when I’m just trying to communicate difference.

“Lands on”? I like that less.

Should you have a turkey sandwich for lunch in 2026? I don't know buddy just do whatever. There are ten thousand other sandwiches you could eat surely, but does turkey sound good for you?
Surely we can give more informed answers to questions like this than to compare a technical decision to the craving for a sandwich.

Comments like this are apathetic and reduce the challenges of good software engineering to hopes and random chance.

Caffeine is healthy. Caffeine is unhealthy. Caffeine is healthy again. Eggs are healthy. Eggs are unhealthy. Etc etc etc.

There’s a reason articles like this exist. Things change.

If you already understand it all in-depth, anything becomes "are the benefits worth the trade-offs" but it's useless advice for the people who don't
What does this have to do with the article?
Some people like to hear themselves talk
I don't think you should only let "if it sounds good" determine what you eat
Yes. It's perfectly fine.
My experience with docker-compose is a bit outdated, but my impression some years ago was that it was too sensitive and fragile. I encountered bugs or incompatibilities that broke the docker-compose setup often enough to be forced to pin the specific docker and docker-compose versions.

And the error handling was terrible. Most of these problems resulted in a Python stack trace in some docker-compose internals instead of a readable error message. Googling the stack trace usually lead to a description of the actual problem, but that's really not something that inspires confidence.

That was the old docker compose. Things got a lot better since they rewrote it in Golang and update it again.
Kubernetes sounds like overkill, but I've been running microk8s for few standalone servers. This feels a pretty good match when working with agents. Codex can manage the cluster also over ssh, schedule new pods, check statuses, logs etc.
K3s is also pretty nice for a minimal setup

Haven't used it in a while but this thing is also interesting--it supports a bunch of different ways to spin up k8s https://github.com/tilt-dev/ctlptl

I like running docker compose for my simple needs because it consolidates pretty much all the config in one declarative file, and docker manages 'everything'. By now I know how to handle the handful of caveats listed in this article. Beyond what's listed there, I'd also give a mention to the way port publishing works (the fact that it ignores firewalls), as that's something that still trips people up if they don't know about it.

> docker compose pull && docker compose up -d is a fine command if you are SSH’d into the host. At customer scale—dozens of self-managed environments behind firewalls, each with its own change-control process—that manual process doesn’t scale.

No idea what this 'customer scale' operation is, but it seems like a pretty clear cut candidate for not using docker compose. I also don't think watchtower should be listed there, it's been archived and was never recommended for production usage anyways.

Sounds like they're referring to a dedicated tenancy multi-tenant model
> docker compose pull && docker compose up -d is a fine command if you are SSH’d into the host. At customer scale—dozens of self-managed environments behind firewalls, each with its own change-control process—that manual process doesn’t scale.

We just use ansible for this part.

I really like developing against compose because it's light but gives you that escape hatch of translating to k8s if later circumstances call for it.

Very few separate ecosystem transfers are quite that frictionless.

AI article with 27 occurrences of dashes —
I prefer Portainer to manage my docker composes. It is simple and can do it all instead of using cli. Added benefit if you have multiple hosts and want to manage them from one place. And you can extend the whole setup with git for version control.
Compose is great, but a couple things always created friction for me when using it for non-local setups:

* Lack of a user-friendly way of managing a Docker Compose installation on a remote host. SSH-forwarding the docker socket is an option, but needs wrappers and discipline.

* Growing beyond one host (and not switching to something like Kubernetes) would normally mean migrating to Swarm, which is its own can of worms.

* Boilerplate needed to expose your services with TLS

Uncloud [1] fixed all those issues for me and is (mostly) Compose-compatible.

[1] https://github.com/psviderski/uncloud/

> if you close the operational gaps it leaves: cleanup, healing, image pinning, socket security, and updates.

Ie you need a sysadmin. Oops, you fired them all 10 years ago when the agile devopsing became the best thing after the pumpkin latte.

I really want something that is Docker Compose but for Kubernetes. I mean that I can have a simple way to declaring resources in just like Docker Compose, but I run the environment in Kubernetes so that I can get to test the behaviors when there are multiple copies of the softwares running together. I do rely on Kubernetes heavily for distributed and networked software deployment, so it is even better if we can emulate things like latency or burstable packet loss so that we can do a controlled chaos test for reliability test. I tried Skaffold, Tilt, Devspaces and Devpod/Coder v2, none of them are really simple like Compose.
This is a great idea for some vibe coding tbh and you can customize it to match exactly the resources that you need as everyone has slightly different requirements for their k8s stack.

The simplest way to start probably would just be to create a custom Helm chart and define what you want in `values.yaml`.

Couple of months ago I published the way I use docker compose in production with mushak.sh and it’s really convenient to deploy this way
How do you guys, who run Docker in production deal with managing nftables firewall on hosts running containers? By design docker daemon creates and manages a set of firewall rules to forward traffic between containers and ingress traffic into containers as well as masquarades the outgoing container traffic. That is all well until admin needs to alter hosts firewall to allow and deny other traffic unrelated to docker - and restarting nftables or even applying new nftables rules usually ( flush ruleset in /etc/nftables.conf ) purges all the docker created rules and effectively breaks everything until docker daemon is restarted and rules re-created. I have partially solved this by using nftables filter chains with different names - admin_input/admin_output and using input hook with negative priority - so that traffic I choose to block is evaluated before docker rules are applied - that feels a bit like hack, but so far is the only way I have found. It is good practice in this day and age to run local firewalls on all hosts with policy deny, so that only traffic explicitly allowed can pass, that can severely limit blast radius during compromise.
Somewhat adjacent in how I look at using Docker at all in prod, here's what I always wonder:

Is using Docker/Compose "just" as the layer for installing & managing runtime environment and services correct? Especially for languages like PHP?

I.e. am I holding it wrong if I run my "build" processes (npm, composer, etc) on the server at deploy time same as I would without containers? In that sense Docker Composer becomes more like Ansible for me - the tool I use to build the environment, not the entire app.

For the purpose of my question, let's assume I'm building normal CRUD services that can go a little tall or a little wide on servers without caring about hyper scale.

Docker Compose was production ready in 2015 and it still is today. I've lost track of how many projects I've deployed with it and never really ran into a single issue where Docker Compose was at fault. It's super solid.

Some time ago I've written about my experiences using it in production https://nickjanetakis.com/blog/why-i-like-using-docker-compo.... Not just for my own projects but for $500 million dollar companies and more.

If the project fits on a single server (which it probably can in 2026) docker compose is great.
well written guide.

even their follow up - Docker Compose vs Kubernetes.

Docker compose for me has been great - no complexity.

I am using docker-compose everywhere. I really enjoy using it. I have a single thing that is annoying for normal production deployments, and that is that it isn't super easy to have a rolling deployment, I just need two replicas for zero downtime deployment, and I don't really want docker swarm. I think it is the networking which breaks at that point, and you have to have a more involved setup, and at that point I'd just use kubernetes, as I know how that works.

Could i survive with 10 seconds of downtime, probably, but I'd really like if I could avoid it.

this is a hack I have used and am proud of:

if you use Caddy as your reverse proxy (instead of nginx for example which does not do this), when requests come in and your service is missing because it's being deployed, Caddy waits for a timeout before giving up. this means that visitors during the brief deploy period don't see errors - they just get a slightly longer wait, which often is not obvious depending on how long your service takes to boot.

I really liked the specific actionable steps in the TLDR.