Hacker News new | ask | show | jobs
by nickjj 48 days ago
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.

8 comments

I love Docker Compose. It is simple to use, easy to organize and manage, and very robust. Also, our company does not need to "scale" production aggressively. Our production load is very predictable, so Docker Compose fits like a glove.

We have been using it for more than five years now. Before that, we had a legacy deployment model, and I do not remember a single major issue related to Docker Compose.

We use it for both staging and production environments. The same Docker image validated in staging is deployed to production. Never fails!

"It is simple to use, easy to organize and manage, and very robust."

This is why nobody uses it. Cloud stuff has to be as baroque as possible.

To misquote Douglas Adams:

There is a theory which states that if ever anyone discovers exactly what Kubernetes is for and how it works, it will instantly disappear and be replaced by something even more bizarre and inexplicable.

>if ever anyone discovers exactly what Kubernetes is for

This part is easy, Kubernetes is for your CV. /s

It's simple to use only for toy use cases, that's why nobody uses it. The article everyone in this thread seems to like only goes as far as 'I pushed to git so it must be ok' which is laughable and I'm not even DevOps.

What happens if it errored on deployment or after that? you wanna write custom (bash? :D) hooks for that? What about upgrading your 'very vertically scalable' box? What if it doesn't come up after the upgrade? your downtime is suddenly hours, oops.

The k8s denial is strong and now rivals frontend frameworks denial. Never fails to amuse.

Fair points, and yes, failed deploys need to be handled explicitly.

In our case, the answer is not "hope and bash". We deploy versioned images, use health checks, monitor the result, and keep rollback simple: redeploy the previous known-good image/config. Host upgrades are also treated as maintenance events, with backups and a recovery path, not as something Compose magically solves.

But I think there is an opposite mistake too: assuming every production system should be operated like a high-scale tech company.

Many production workloads are boring, predictable, and business-critical. They do not need aggressive autoscaling, multi-node orchestration, or constant traffic-spike handling. They need reliable deploys, backups, monitoring, health checks, and a clear rollback path.

That is where Compose can be a good fit: simple operational model, understood failure modes, low moving parts.

Kubernetes becomes much more compelling when you actually need automated failover, rolling deploys, autoscaling, multi-node scheduling, and stronger deployment primitives.

Not needing Kubernetes is not necessarily denial, it is just choosing the complexity budget that matches the problem.

Definitely not a one-size-fits-all choice, but Kubernetes can be so easy and there are so many benefits that get you from one small app to a medium sized business that it seems like a no-brainer for someone starting out. Spinning up k3s is pretty minimal overhead, but right away you can handle storage and backups very easily, automatic certs for all your apps with cert-manager is pretty much a one-and-done, traffic management for external and internal tools is easy, and even logins for websites is just an annotation in a yaml file. You can spin up and try out any software you want without spending time configuring it or setting up additional servers- and when you do need more hardware, it's one command on a virtual server, and just about as easy with physical hardware.

2-3 miniPCs, cloudflare, tailscale, and k3s can save (possibly tens of) thousands on SaaS products, and would probably scale you to a company of dozens AND host your product.

>2-3 miniPCs, cloudflare, tailscale, and k3s can save (possibly tens of) thousands on SaaS products, and would probably scale you to a company of dozens AND host your product.

outline a simple real world system to illustrate?

I think people are using different meanings of “production environment.”

I agree with gear54us and upvoted their comment, but I also understand what the author of the root comment is saying.

I have also delivered systems using Docker Compose that are actually running in production. The point I want to make is that people may define “production” differently depending on the number of active users, operational requirements, and risk level.

To me, this debate feels similar to the broader monolith vs. microservices debate.

"Not just for my own projects but for $500 million dollar companies and more."

Seems reasonable to assume these are serious production environments, no?!

Not necessarily. When you get to those numbers you're seeing dozens of teams with their own silos and deployment methods. So they might be responsible for the core business that's running 30 nodes and serving 100MM users a day, or they might be working on some internal portal or a WordPress site.
That as well as different definitions of scale. I've done small bits of consulting work for a research company for the past four years, deploying and managing Kubernetes clusters for them as well as helping get some of the main applications up on it. This is all internal tooling, though. Their customer-facing sites are just Drupal instances running on bare EC2.

Internally, though, they wanted to self-host a chat server, Apache airflow, Overleaf for collaborative editing of research proposals, three separate Git servers, a container registry, many other things, all with extremely strict multi-tenancy isolation requirements for storage and networking because they're handling customer data and their own customers audit them for it. That was a hell of a lot easier to do with Kubernetes than trying to figure out some giant universe of barely related technologies with vastly different APIs, having to buy specialized appliances for network and storage that probably also need their own control plane software hosted somewhere else.

But if you just look at "scale" as number of http requests a particular URL gets per some unit of time, the customer-facing sites have far greater scale. If you're trying to attribute revenue, beats me. They wouldn't sell anything without the customer-facing sites, but they wouldn't have anything to sell without the internal tooling. Solo web devs get into this tunnel vision view of ops because, to them, often the web site is the product. That's not the case for most businesses.

And, of course, they'd probably just use someone else's SaaS for tooling. But if you're in a heavily regulated space where that isn't possible and you have to self-host most of your business systems, then what?

The post receive hook provides you real-time feedback as it runs in the terminal where you did the git push. If something broke during the deployment you'd get notified by looking at the output. If it's running in CI, you'd see a CI failure and get notified using whatever existing mechanisms you have in place to get notified of deployment pipeline failures.

Zero downtime server upgrades are easy. You could make a new server, ensure it's working in private and then adjust DNS or your floating IP address to point to the new server when you're happy. I've done this pattern hundreds of times over the years for doing system upgrades without interruption and safely. The only requirement is your servers are stateless but that's a good pattern in general.

Define production. Docker compose is fine for running a small internal service in production for dozens of users (i.e. not for developing said service, but for using it). I would assume it isn't fine to run a hyperscaler (but I wouldn't know). Those are extremes, and there are going to be a ton of situations in between.

I can't personally speak to what the limit of docker compose is, as I have only worked on the lower end of this: self hosting for personal use and for small internal services serving maybe 20 users.

From my personal experience if deployment strategy is thought through then Docker running through Compose can handle few hundreds of thousand of users per day without an issue and probably could handle more with proper hardware upgrades.
Most people/apps only need the toy cases... If you're writing an internalized tool for a company that will only have a handful of users, then doing much more than compose for deployments is a violation of KISS and YAGNI.

Are you really going to try to get 4+ 9's of uptime for a small, one-off app? Do you really need to use a cloud distributed data store that only slows things down for no real gains in practice? Do you really think the cloud services are never down, and you're willing to spend a f*ck-ton of money to create a distributed app when historically an Access DB or VB6 app would have done the job?

I've moved applications deployed via compose pretty easily... compose down -t 30 then literally sftp the application to a backup location then to the new server which only needs the Docker Engine community stack installed.. then compose up -d ... tada! In terms of deployment, you can use github action runners if you want, or anything else... you can even do it by hand pretty easily.

I love it so much I have created a thin statless orchestrator layer upon it:

https://github.com/daitangio/misterio

It works very well!

Extremely debatable. They still have never fully implemented health checks and auto healing. I have had compose itself behave in unexpected ways, weird things like not realizing the tag of an image it is running is actually in use, and letting prune commands yank it out from under the system. Other things I can't remember. I'd rather use something like Nomad or for simpler systems maybe plain systemd. But realistically kubernetes is a superior orchestrator in just about every way, and installing k3s is simple and k3s is actually production ready. I don't like kubernetes all that much as cluster tech, but as a container orchestrator it has a lot of nice features.
I'm totally onboard with k3s/k8s being better in a lot of cases.

But docker compose can actually be very sufficient for what many projects actually need.

Granted I am a guy pushing for compose based localdevs and such but going further you often just cannot beat the simplicity of doing update QA or other CI/CD workloads in compose based projects. I have had dozens of projects where we replaced flaky slow and maintenance heavy pipelines with just docker compose up --build --wait in the past years. How come you say health checks are still broken?

I do use compose for some things, smaller one off type setups, and I’ve done the compose up --build CI/CD approach before. I’m generally not a fan of building on the production node outside of very small deployments. It can work, I just think it tends to blur the line between build and runtime more than I’m comfortable with.

Some of my concerns with compose aren’t purely technical. It makes it easier to lean on local state like volumes, bind mounts, and large .env files. Similar mechanisms exist in kubernetes, but the additional setup tends to force a bit more thought about whether they’re actually needed or just a shortcut.

On the health check side, they exist, but compose doesn’t fully act on them, that's the part that is missing. There’s no built in remediation or orchestration behavior tied to health status, which is why things like https://github.com/willfarrell/docker-autoheal exist. It’s something that was never fully carried through in Docker itself.

> Extremely debatable. They still have never fully implemented health checks and auto healing.

Agree.

Plus there's the monitoring of the host that is always overlooked in articles. I've ended up chucking Monit on there to monitor disk usage et al, and also used it for monitoring compose too and restarting containers.

And then there's Healthchecks.io, and external uptime monitoring... the list goes on. Properly monitoring systems, even single server systems, is not simple.

How do I backup docker volumes? I never found a native flow for backing up docker compose projects.

While not built in k8s has at least velero and kasten. However they are only possible because of snapshots https://kubernetes.io/docs/concepts/storage/volume-snapshots... and kasten has a plugin like architecture (because of k8s ) that supports application specific backups. However I never found something like that for compose. And that is troublesome in bigger projects like sentry

The "easiest" way is to use bind mounts to a local directory (or multiple directories) instead of volumes. Then you can just use normal backup tooling.

Docker volumes (and bind mounts) however have the minor problem of being hard to get a consistent copy to without stopping the service. You can work around this by, e. G., having ZFS or btrfs as the underlying FS and making a snapshot there. Otherwise, your software (like PostgreSQL) might also have other online backup tooling.

AFAIK volumes are nothing more than a bind mount on a private docker folder, e.g. the files for volume my-volume are stored in /var/lib/docker/volumes/my-volume/_data, so backup strategies (an problems) for bind mounts apply also to volumes
Yep, that is accurate. There is also a command/API route to find the path on disk iirc.

In my setups it just was easier to use fixed paths (or relative to project dir) from a permissions management perspective. Backup tools did not always have to/should run as root which is helpful on machines providing multiple distinct services.

Putting borg or a similar tool in a container that is part of the compose manifest file can also help. I haven't seen this used in practice though yet.

Why use a docker volume? Seems like a good way to accidentally lose your files. Just volume-mount from the external filesystem and back it up the same way you would any linux application's files - maybe stop it, maybe not, depends on how it uses files.
Docker volumes still exist on the filesystem. Wouldn't one be able to point the backup solution at that directory?
It's nice to be able to survive someone purging Docker by accident, and it's nice to know `/wherever/you/like` is where your files are instead of in `/var/lib/containers/some long hash/`
Really liked reading your blog. Bookmarked for future. One question: for databases, do you recommend using containers as well because in development, I love the ease of using databases in docker compose as well but I always worry about production in terms of resilience. Thoughts ?
For databases, I usually host them on a separate server. This could either be through Docker Compose or a managed DB server. If a managed DB is affordable enough I'd reach for it.

It's because I like keeping my servers stateless when possible. It makes it easier to upgrade them in a zero downtime way later.

If your web server has your DB too, then you can't do zero downtime system upgrades. For example I would never upgrade Debian 12 to 13 on a live server. Instead, I'd make a new server with 13, get it all ready to go and tested and then when I'm ready flip over DNS or a floating IP address to the new server. This pattern works because both the old and new server can be writing to a database on a different server.

With all that said, if you were ok with 1 server, then yeah I'd for sure run it in Docker Compose.

> This pattern works because both the old and new server can be writing to a database on a different server.

How would you upgrade the server running the database?

It depends on the business use case and requirements.

Using a managed database solves this problem, so there's that an option.

If you self host your DB, if the data is on block storage you can at least spin up a new instance and connect that storage device onto the new instance with a short period of downtime. This is usually a satisfactory level of downtime for an event that doesn't happen too frequently.

What I like about the above is it'll work with any database and avoids needing to even think about performing real-time or near real-time replication with multiple writers.

There's also the scary truth that there's a ton of stuff out there where compliance requirements aren't enforced. I'm not saying it's a good idea but you can choose not to upgrade too. This is a risk assessment you'd need to do. At the very least if you go down this route, please make sure your server doesn't even have a public IP address. If it's super locked down, that doesn't mean it's safe but you'll want to limit the number of attack vectors as much as you can.

At this stage the volume/persistence configuration for all of the major DBs is arguably extremely well understood and has been for years. The only real risk in running the DB as a container for most people is not configuring volumes for persistence correctly.

For most DBs it's one or two paths in the container, and virtually all DBs vendors have a reference Docker Compose example somewhere showing volume config. I can't remember the last time I ever "natively" installed a DB personally!

Do you prefer self hosting DB with container OR using a managed service liek RDS ? I guess both can work depending on your level of comfort and even though I am a big self host guy, db hosting is something that makes me nervous and I end up just leaving it to RDS etc.
The answer to this for me anyway depends entirely on the size of the solution, what the rest of the stack looks like, how many users, what is my support contract like etc etc, do I have to collaborate with other engineers or is it just me? Similarly, if you already have a bunch of ops guys managing some RDS stuff, it might make sense to just take advantage. RDS also comes with a ton of features a simple compose stack won't, especially around redundancy and disaster recovery.

I don't think there's a good one size fits all answer to whether hosting in Compose or RDS is right for you or a given project.

Not OP, but I think it depends heavily on your use case and where you are deploying... I've used containerized DBs as well as leaned into hosted DBs in a given cloud environment. I've tended to favor PostgreSQL for container dev simply because it is well supported in pretty much every first and second tier cloud provider out there.

It really comes down to YMMV... Sometimes for a singular app surface, it's easier to just use a compose file that includes the database. mailu/mailcow is a good example... you don't necessarily want to comingle email on the same server as other services.

That said, if you need to share a single DB or set of DBs across an applicaiton with several instances/deployments, then it makes much more sense for a central deployment. I almost never do my own host level install, instead relying on cloud hosting and mgt. The only real exception is MS-SQL on internal servers... MS-SQL in Docker is barely acceptable for dev, and missing a few key features you may actually want/need.

What effect does docker compose have on database resilience?
I probably used the wrong word. I meant more about managing volume property so we dont have data loss, backups, replication etc etc. I assume going managed is easier if you can pay for it (e.g. RDS)
Hey, just want to say thank you for your blog. I've learned so much about Docker, dev tooling, and engineering from reading it over the past 7 years.
Thanks a lot, I really appreciate it.
Thank you. I had been procrastinating on learning how to work with containers and finally got a handle on Docker Compose to play with self-hosting a coding agent and was worried that I'd once again procrastinated so long that I'd picked something up long after it was already dead.
It makes things amazingly simple and portable, dealing with things otherwise seems so horrible now.
If the project fits on a single server (which it probably can in 2026) docker compose is great.
Have you read the article?