Ask HN: What Is the Hype with Docker?

105 points by spencerchubb ↗ HN
I have used Docker more than almost any other tool, and I have genuinely given it a fair shot. After all of that, I still don't understand the appeal.

Docker nearly seems to be an industry standard by now. Some people treat it like an obvious choice, but it's not so obvious to me.

People say that Docker can run anywhere. It solves the infamous problem of "works on my machine". Despite what people claim, I have not found this to be the case. I developed containers on windows and then I still had to debug the containers when deploying on Linux. There were formatting issues, filenotfound issues, and chmod issues. I have spent so much time configuring docker, and been able to complete the same task in a VM in a fraction of the time.

Am I alone here? Am I doing it wrong? Is it the case that I am not the intended audience, and it's meant for larger teams?

106 comments

[ 5.0 ms ] story [ 185 ms ] thread
I guess it wasn't meant to run on Windows. And linux people meant "run anywhere as long as it's some linux".

Which is good enough for me. Considering how it is easy to install, distribute and run and manage apps in Docker vs bare metal setting up and fighting issues in complex setups until your eyes are red.

I absolutely agree with this opinion.

Docker saves me the headache of having to manually reconfigure stuff when I want to spin it up on another machine. It's not perfect, but it's close enough.

Docker compose and keep all the data in volumes with the compose file.

Makes it absolutely trivial move the service between machines.

Backups get easy too, plus if you use ZFS/btrfs you can snapshot per project really easily too, and you only have to grab the data.

Snapshot per Project? Sounds interesting. How would you do that?
Quite simple, assuming you use a filesystem that supports snapshots.

I'll assume you're using btrfs, but ZFS works too.

You create a subvolume.

You create a docker-compose.yml file inside this subvolume. You create a directory beside the docker-compose.yml, and you put ALL of your stored volumes for each container in your project in it. I define the volumes with relative paths so I can just pick up and move the project around.

Terrible art incoming:

    example-project/  <-- this is your subvolume
    |- docker-compose.yml
    |- volumes/
       |- example-project-psql/
          ... files ...
       |- example-project-conf/
          |- configuration.yml
       |- example-project-redis
          ... files ...
Now when it's time to upgrade, you can snapshot the whole thing. App and DB are both frozen in that point in time, and you proceed not needing to worry about how you will rollback.
When docker is used to develop and deploy on linux, it's amazing. Running any kind of container on Windows (let alone Windows containers) will absolutely lead to headaches at some point.
I can attest to the pains of using Windows containers first hand.

I'm currently working on a project that requires mixing Windows and Linux containers. The deployment and development process since the addition of the Windows containers into the mix has become so cumbersome that we're actually seriously considering using Wine in a Linux containers just to avoid the integration of the Windows containers altogether.

Docker is like the Java of Infra
Pretty sure Java is more like the Java of Infra
Docker has a bunch of pros and cons, but to me the most important thing is that it standardizes a 'good enough' way to deploy servers. That means I can have one dev write some docker files used to deploy a server, then later switch to a different dev and the other dev should be able to easily figure it out. Contrast that to before when people had custom scripts and VMs and you would always need to spend time digging in to figure out what is actually happening and whats breaking.

Its not perfect, but its good enough and there is a lot of support for it, so its easy to plug into my team.

When you put it that way, it does sound like quite a nice benefit to have a standard way to deploy. I will persist with docker and develop on Linux more as other people have said.
It's also very good for CI, to put all the dependencies and the entire build process in code that way. In the pre-docker days, you had a lot of configuration management inside the CI agents. Nowadays, often all that they need to do is be able to run Docker (+ manage secrets and a few other things) and you're good to go.

I have never liked Docker for local development, apart from running external dependencies (e.g. have postgresql and redis launch through docker-compose in a standardized way). Local development of company code should not use Docker, too much hell with caching and (as OP notes) discrepancies between developer environments.

(On that note, I have found that developers typically use Docker very different from people that work on CI / deployments -- more often than not, I've seen devs just have continuously running docker containers, executing all kinds of commands on them, save/loading them, etc, without using any Dockerfile at all. That just makes me irk, I don't understand that type of flow)

Local development is way easier with Docker for certain things. It’s great to have known and consistent package versions, a build process that’s documented by the nature of dockerfiles, and having a fairly standardized deployment method.

There’s been plenty of times in my work history where I had to take what was a legacy application nobody knew anything about and went through the process of deploying it using a container. The biggest problem was figuring out how to get the thing to actually run; “I don’t even know anything about Scala. What the heck even is sbt, no clue.” But just starting out with a blank image where I can install random things that don’t affect my machine is great, and once I finish the process now everybody knows how it’s deployed; it’s in the Dockerfile. If I want to explain it in a readme, I copy and paste what I have in the dockerfile and expand on it, going step by step. When that image is deployed in an EC2 instance running our standardized AMIs, I know it’ll work; I’ve tested it. Converting that deployment image to run unit tests just means changing a few commands in the dockerfile, and now Spinnaker can run tests before the image is deployed anywhere. Easy pickle.

At my current job, we do not currently have a process like that. We have Jenkins workers where we occasionally have to install different packages that the devs need in order for their build process to work as expected, and we have to have Jenkins workers specifically for that team. If they ran their builds in a container instead, we wouldn’t have that issue. At my previous role, our Jenkins nodes were regular EC2 instances running our standard AMIs and the dev teams built their code inside a container. When I had to build Python packages, it didn’t matter what Python packages were on the system, or that the EC2 instance didn’t have Python-dev and GCC installed. Build happens in a container. I know the build will succeed because I tested it locally on my machine.

The containerisation part is where it shines. Collecting and running any dependency for your image with the Dockerfile make it very flexible and independent of the host platform.

I can agree that the problems start on the edge between the host platform and the containers like networking and mounted volumes, conflicting user and group ids.

It seems like most of the value of Docker comes from the Dockerfile more than the containerization. The Dockerfile defines how to (build,) package and run an app, including the operating system dependencies. (That's not necessarily Docker specific, but I got the feeling you weren't asking only about Docker).
And docker-compose is really killer.

You can switch between whole stacks of variously-versioned things for projects on dev machine very quickly.

Docker-compose down && cd otherproject && docker-compose up

Way easier than VMs or localhost version-handling ever was. You dont need co-existing postgres's, rubies, pythons, nodes, etc stepping on each other's toes.

Plus sandboxing.

By running software in a container, I know my machine is pretty nicely shielded from malice, incompetence and carelessness on the side of the developer.

Docker allows you to run multiple workloads on the same machine and have them all share a kernel while each having their own segmented user space so it's much less likely that processes will be able to interfere with each other. This is important for both the security and stability of the system and is similar to BSD Jails with the advantage of not being restricted to that operating system.

Running multiple heavy VMs which segment system resources gives you even better and more complete separation at the cost of being very performance intensive. The industry by and large has opted for containers as a compromise between reasonable separation and performance.

Also as Docker grew in popularity there has been an ecosystem of tooling built around it for container orchestration, image repositories, and development that make it worth using just to get access to the tooling that surrounds it.

I think with different OS's you're still gonna have some challenges but the fact is you still get better consistency, especially if you're on a Linux machine. I use the Mac and I have minor issues with the network, performance, and having to manually clean up my docker storage from time to time but I'll take that anytime over wondering why I can't install something or reproduce an issue in another env.

I don't see anything hype about it. You might just be frustrated with more of the minor issues.

Docker is pretty awesome for deploying your services and having an isolated environment that is the same everywhere. Although with the new M1 arm chips this is slightly breaking down since arm and amd have inherent differences that get introduced to the build environment unfortunately.

Docker is abused as a developer environment though and I hate seeing teams try and force everyone to develop inside a container that eventually gets merged with the service itself and turns into a 2GB image nightmare.

Yes you're doing it wrong. It's effectively Linux tech, and attempts to shoehorn it into Windows can only cause pain. Run it on Linux and it's very smooth.

I just had this discussion with a colleague. It does, semi-half-assedly but quite effectively, what nix promises. You can make hermetic images of not just binaries (that'd only be as good as static linking) but of entire machines (sans Linux kernel, because you're running what the host runs, but that's always Linux so it's fine, and when it's not Linux you're not having a good day).

Wrap that up in a stackable system (build your own images atop of others) and a way to quickly run processes out of images, and you've got yourself a highly portable and reusable system for apps. Want to build an app to run on a random k8s node in AWS? shove it in a docker image and now you've just got to write some yaml.

Got a few python libraries that you want packaged atop of all of pandas+jupyter+numpy+whateverelse? Reference a stock jupyter prebuilt image (there are many official ones you can start with) and add thew few packages you want in a Dockerfile, and bam, you've got a redistributable data science appliance as a docker file.

I can build docker images on my laptop and then run them on my crappy celeron nas for months without thinking twice about it.

Like others said; it is less than great under Windows, but from Linux to Linux or mac to Linux, it’s mostly painless. Most problems arise if you try to do anything outside containers; for instance having some stuff inside containers and then developing other things outside, under mac, can lead to (known) horrible network perf issues. However because it’s known, you just adjust your flow a bit on anutopilot (experience) and all will work indeed automatically on Linux.

I resisted it at first but now I cannot do without, neither in team projects nor personal ones. It can be improved but it is better than the alternatives that I know of.

I've never run it under Windows - was this regular Windows or Windows+WSL?
I have done some of both - Windows and Windows+WSL. When I ran on Windows+WSL, there was a known issue where it would use up all available RAM. So the only workaround was to configure WSL to only have 2 GB of RAM.

When I ran on Windows, there were just small, annoying differences between Windows and Linux. So as others have suggested, I will persist with Docker and develop on Linux.

> People say that Docker can run anywhere. It solves the infamous problem of "works on my machine".

Linux containers do that, not Docker. However, that statement isn't as universal as some readers might think. Linux containers are just that, for Linux. In all reality, it also depends on how the host kernel has been configured if you want two containers to run the same way. Windows has Windows Containers, and the BSDs have jails. They're all quite different because their host operating systems are all quite different. Windows and MacOS are usually running Linux containers in a hypervisor.

Docker when juxtaposed to manually burning container images and standing up containers as they exist from LXC is extremely useful. It also inspired the growth of the Docker Runtime.

Our issues are even worse than that - we're not only all using linux, we're all on the same version of Ubuntu and still have constant "works on my machine" problems. Half the team can't even get some projects to run that were developed by another team, and the rest of us usually have to fiddle with them for a while before they'll run.
That just made me have a realization (probably a novice one). When people refer to the "works on my machine problem", it is probably mostly about machine configuration and installed programs, not the choice of OS entirely! As a lot of people have said, Docker still has portability issues between e.g., Windows and Linux.
The problem is believing the branding. The Docker company was calling the emulator version and the native version the same name, but they're very much not. It's a Linux native system in the end.
> I developed containers on windows

Yeah, don’t do that.

> I developed containers on windows and then I still had to debug the containers when deploying on Linux.

I basically avoid Windows altogether when doing development now. Unless it's for video game development, which even then I wish I didn't have to use Windows.

Dockers containers are standard for a reason. In fact I can't imagine not using Docker as a daily driver nowadays. Within seconds I can spin up a sterile container for my development environment. Or application. Or a data store. Or a queue. And it's all isolated and seamlessly communicates with each other. I'm now even compiling Unreal Engine servers on Windows and deploying them on Linux machines using Docker containers.

Are you using Docker Compose by the way?

sterile… do you use dockerhub or create the base layer yourself?
I only create the baselayer on machines where I compile the kernel from source
Problem with Windows is that, if you're running Linux containers on them, it launches inside an embedded virtual machine (at least last I checked). This means that networking and storage suddenly has to go through another hop, making things that should be trivial extremely annoying.

E.g. a service binding telling you "please connect to http://127.0.0.1:8088" and for the love of god you don't know why it doesn't work, but it's because the container, while using --network=host, thinks you're on the same host, while that's actually the virtual machine which is almost entirely inaccessible to you.

Windows + docker is a minefield.

Docker (and all container solutions out there) runs the Linux container in a VM on _any_ non-Linux OS. This is a designed trade-off of using Linux virtualisation and not really Windows’s fault (nor macOS where I do a lot of development and has all the same problems).
I haven't encountered this issue on docker for mac. I can access containers from my web browser just fine. Yes it runs in a VM but I guess the GUI tool handles everything for you.
There are indeed edge cases where the VM implementation detail leaks, which I assume is what parent was referring to. Typical port exposing just works out of the box on Windows as well.
I’m not saying it’s anyone’s fault, I’m just saying that the approach has very rough edges that are difficult to grasp for beginners. It’s one of the reasons Docker is not always a good choice for a development workflow.
I'd prefer just go with hyperv at that point and build containers in a Linux environment..

IDEs can still access your VMs so you can have all the nice syntax highlighting etc from Windows but you are building inside Linux.

You have really nice networking options on hyperv so you can even check how your app deploys in a distributed environment.

I can wrap a complex python deployment, dependencies, models, random stuff. All the ML libraries that are tough to install. Then I can push it into the cloud and run it. If it gets deleted, I can create the exact same image. Or revert back to an old one.
IMO it's a poor tool for local dev. It's just too much of a pain to work inside of a vm—or at least what's essentially a vm. The real value is for production deployments since the way you setup dependencies is consistent across different app types.

In theory it is also better because you can manage a fleet of containers just by looking at their memory and CPU usage and not really caring about what's inside, but I think the reality is that k8s is so complex it's not clear the tradeoff of finer-grained management is worth the difficulty of setting it up. Maybe, depends on your use-case.

People are saying the issue is that you're running it on Windows but I would counter that running on macOS can be just as bad if you're trying to run x86 containers on an ARM box.

Yeah, I tried out developing locally with Docker once and gave up within the same day. But I just checked and I have 12 containers currently running on my NAS. Can't really beat that easea and speed of deployment, and isolation.
Quite the contrary, I’ve found Docker to be absolutely indispensable for local dev, particularly when I’m debugging various cloud-targeted components, e.g. AWS Lambdas and Step functions. A container can nicely simulate most of the running environment of those things, and mock everything else. Docker + JetBrains IDE is a must-have for that reason
What images do you use? I would love to hear about your setup to debug lambda functions.
I use the AWS Toolkit for PyCharm; it automates most of the process, including pulling an image (built by Amazon, I believe) that emulates the Lambda environment. All I have to do is write the Lambda function with the correct method signature, designate it as such, start a debug session, and PyCharm + Docker do the rest. It's insane that PyCharm Professional only costs $100 or so, it saves me that much in development time in a single day.

Edit: all of the above will work with the free version of PyCharm, I believe, but without the in-IDE control panel for Docker (which you don't absolutely need).

Pycharm still struggles to provide debug of Python interpreters running in local docker containers from an orchestration.

It’s supposed to just work but jetbrains has broken it and changed the config over and over with a big regression as recently as 2022.2.

Vscode apparently handles this better.

I follow posthog, and they keep all components of their local dev env in containers _except_ the web dev and I think that’s the right move.

For my personal projects I just run services I need locally. But all CI and deployment is via orchestrated containers.

> Am I alone here? Am I doing it wrong? Is it the case that I am not the intended audience, and it's meant for larger teams?

No. Probably not. Maybe, but also probably not, you may just not have had the "Ah-hah!" moment. A lot of technologies are like that.

Take any random Windows or Linux server someone else has built. Log in to it. Now tell me how it was built such that that build can be reproduced on a slightly different platform, e.g.: a different processor or base image.

Good luck with that.

Traditional operating systems are write only. Trying to get the configuration back out after the fact is effectively impossible in the general case.

Even if you have a "scripted process", "policy", "documentation", or "declarative state configuration", drift occurs anyway because of things such as disk corruption, updates applying out-of-order, different levels of updates, quick fixes/tests, etc, etc...

It is basically impossible to keep a large fleet of supposedly identical machines identical.

As a random example from the Windows world: I've seen Group Policy applied to user accounts such that when an admin user logs on to a server, that triggers an on-login install of some software. Could be anti-virus, a print utility or whatever. Suddenly pristine servers become... not so pristine.

People have tried to work around this kind of thing... clumsily.

For example, in the Windows world you can build standard operating environment (SOE) disk images for servers using a tool like System Center Configuration Manager (SCCM) task sequences. This can deploy Java runtimes, ODBC drivers, or whatever you business app needs. (Linux has things like Packer)

The principle is fine, the implementations however are terrible.

A complex SCCM Task Sequence might run for hours and then fail at step number 57 out of 83. Fix it, start from the beginning.

Oops, failed again after several more hours. Fix it, try again.

Success! Now step #62 is failing. Fix it, try again.

This can mean days down the drain. Wouldn't it be just awesome if the build system could take snapshots of the VM at each step, so that it could restart at the last known good step, making the edit-build cycle super fast?

Docker does that.

Build systems like SCCM task sequences or Packer aren't typically parameterised, or the parameters are "baked in" at build time, and/or get passed at annoying points such as a very early "network boot" step, which has technical and security limitations.

Docker does the right thing, simply passing in parameters as environment variables at runtime. This allows one image to be used in many environments, without changing it. If you test something in UAT, then production will by byte-for-byte identical (SHA256 hashed!), except for the minimum required config changes.

Typical build systems produce a single opaque binary image. This could contain anything, and the "link" to the source script that produced that build is immediately lost.

Docker maintains the step-by-step build script that lead to the final docker image, in the image itself.

Typical build/deployment systems require "full VMs" and associated images, which start from merely big at ~32 GB and go up to a way-too-big ~127 GB as is the typical case for servers in the cloud. These are mostly blank space, and need the wiggle-room for things such as after-the-fact updates.

Docker maintains an efficient content-addressed store of image layers. A small change on top of an existing chain of image layers might need just tens of megabytes. Deploying this to the production environment similarly requires only tens of megabytes, allowing very efficient blue-green deployments rolled out automatically via dev-ops. Existing deployments are maintained as-is and there's no side effects of a roll-back. Compared to this, updating any shared framework or system-wide inst...

> Docker maintains the step-by-step build script that lead to the final docker image, in the image itself.

Huh. I did not know this. Seems useful. "docker image history name:tag".

It's kind of janky but it's the best thing we have right now.
All I can do is provide another anecdote, but I'm not sure how I'd provision servers without something like Docker. I guess there's ansible, but Docker is great since I can just put shell commands in the Dockerfile.

At work, we recently started using GitHub Codespaces for development. It uses Docker to set up the dev environment. It's been fantastic and legit has solved 99% of "works on my machine" problems.

What's causing your file-not-found issues? Surely it's not actually Docker, but rather some poorly written Dockerfiles.

> I'm not sure how I'd provision servers

> I can just put shell commands in the Dockerfile.

Can't you just put the shell commands in a shell script?

You can do anything with a shell script, and typically you could use tools like Ansible to provision them - that would be similar to Docker's Dockerfile.

Unlike shell script, you generally need to build Docker image only once though + it just feels faster and less cumbersome.

I just use Docker whenever I need to run something on multiple machines. It essentially runs the same shell script, but I don't have to care for making sure the environment for the shell script is compatible (i.e. distribution version, os package dependencies and so on)

Are you deploying to servers that are already running other services? If so, why not just create a fresh VPS dedicated for your new deployment? Not saying either way is better or worse, just looking to understand why that may be the case.
Sure but then I have to make sure the commands work well for servers that are already half configured. With Dockerfiles, I can just be naive and write the scripts with the assumption that it's a fresh system every time.
Right, I can see your point but I just want to understand a bit more... why would some servers be half configured already? When you fire up a new server don't you just select a standard distro image? What happens when the Docker image is updated?
Can’t speak to issues with Windows and Docker, but teams I’ve worked on effectively used Docker to eliminate the “runs on my machine” problems. I’ve only used MacOS and Linux the last ten or so years and for me it works really well on both.

I’ve had one or two coworkers on Windows and they used WSL I think. Can’t comment on their experience.

The Dockerfile prescribes exactly what operating system and packages the container has. Docker Compose sets up dependencies in other containers and in most cases this was all that was required to run and test. It does require you to make some platform agnostic decisions on how you structures both but I find it easier than scripting.

Outside of that YMMV.

Docker on Windows absolutely sucks.

I write a lot of tools for my colleagues and I've gone out of my way to say "I can gurantee this .devcontainer will work on WSL2" and leaving my support of it there. Since even .devcontainers behave differently on Linux and Windows.

Before Docker, especially when I was working with PHP and Python, my single biggest concern was always that I'd need to use some dependency that was difficult to install on my server.

Docker fixed that.

All bets are off when you're dealing with Windows in the open source world, especially when it comes to something like Docker which was designed around the linux kernel and a unix-style perspective on systems.

Docker's core strength is that it provides your applications with process, network, and filesystem isolation on an individual host. Applications are very sensitive to their host environment and before the popularity of containerization a lot of effort was spent ensuring that host machines were provisioned in a manner that made them capable of supporting application needs. Things could often get hairy when deploying multiple applications to the same host due to conflicting lib versions, network ports, environment variables, file permissions etc. Things could also become precarious when there was a need to manage rollbacks across dependency upgrades on the host.

With docker (or a similar container solution), all of that pain is abstracted away, you don't have to think about the host machine at all, the container coddles your application so that it has a pristine working environment, conveniently configurable with environment variables.

It can take an unknown amount of persistent state (what's installed? how's it configured?) and replace that with a small file that's checked in to source control.

It can also help avoid issues when one person is working on multiple things that have conflicting dependencies.