Ask HN: What Is the Hype with Docker?
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 ] threadWhich 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.
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.
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.
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:
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.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.
Its not perfect, but its good enough and there is a lot of support for it, so its easy to plug into my team.
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)
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.
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.
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.
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.
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 don't see anything hype about it. You might just be frustrated with more of the minor issues.
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.
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.
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.
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.
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.
Yeah, don’t do that.
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?
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.
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.
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.
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).
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.
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...
Huh. I did not know this. Seems useful. "docker image history name:tag".
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 can just put shell commands in the Dockerfile.
Can't you just put the shell commands in a shell script?
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)
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.
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.
Docker fixed that.
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 also help avoid issues when one person is working on multiple things that have conflicting dependencies.