HACKER Q&A
📣 jdthedisciple

Docker vs simple DLLs?


I'm already feeling bad for creating yet another docker-related post but I figured f** it, I just don't get the hang of it so somebody pls conclusively, once-and-for all, explain the need for and blessing of docker in a simple, fool-proof fashion:

What I did understand so far is "Docker is useful if you have multiple applications with different versions of the same dependencies running on the same machine, as well as for deploying onto any machine".

MY QUESTION: (Why) don't dynamically linked libraries (.dll) already solve this problem?

I come from the .NET world and there I can run any number of applications all with their respective dependencies, e.g. NuGet packages, as .dll files in their own isolated directories - doesn't this already solve the problem of isolation and avoid dependency-conflicts? This is also easy to ship to any machine as I just compile the whole thing for the respective architecture and then copy and paste it over, set it up as a service/daemon, whatever.

To me a standalone application is simply a directory with an executable and all dependency-dlls in the same directory / some subdirectory. This is already a software-wise isolated application (obv not on the hardware side but lets leave that out for a second), of which I can run multiple on the same system. Why do I need docker on top of that?

I am probably misunderstanding something fundamental here so for the 21375th time, what is an idiot-proof explanation for the need of docker in light of dlls?


  👤 brozaman Accepted Answer ✓
Becuase your solution is specific to your specific software.

Then you have lads who use python who can use virtualenv, and then the ruby ones who use rbenv and then you have the CPP developers which are usually fine but on Tuesday Joe messed up the linker settings and all of a sudden we're not statically linked, thanks Joe.

And then our Java team forgot to tell the sysadmins that they upgraded the JVM version.

The thing with docker is that you just get a complete package with everything delivered directly by the developer and it's very hard to mess up.

Also docker can run applications that aren't shipped by people in your company and also does more stuff (like more sandoboxing and it also helps you with the resource management).


👤 nirui
> I am probably misunderstanding something fundamental here

Don't blame yourself, it took me quite awhile to figure out the benefits as well.

Docker, or containerization in general is not a system that only helps you manage dependencies and isolation. It's about dependencies management, isolation (to a degree), fast and expectable deployment, automatic scaling and so on.

Now days, application backend are expected to run on multiple nodes. Sure, you can manually code your app to automatically deploy/update itself on multiple servers and so on, but that is a huge task, and the maintenance responsibility comes with it is even bigger.

Containerization platform such as Docker and Kubernetes provides a standard operating environment for operators and developers to manage the lifecycle of a scalable application, IMO that's where the gold is. Dependency management and isolation etc is just a natural part of that.

Of course, you're still responsible in creating a scalable application, but once you did that, deploying the application will be as simple as running a `git push`, then a remote system takes over, creating a container image according to your Dockerfile, and then deploy those containers onto necessary amount of servers. It all happens automatically, like a dream :)


👤 codeflo
It’s a different conversation from the dev side and from the sysadmin side, and neither might apply to you.

As a dev, containers allow you to care a lot less about what’s installed on the server and in which version. You’ve already solved that in a different way for your setup, which is fine. I’d say the trick in your case isn’t the DLLs specifically (I’m not sure why you focus on that aspect), it’s the fact that .NET allows you to create a standalone application, including (in modern times) the .NET runtime. If that’s all you need, you’ve already minimized your dependencies on the OS, and you’re unlikely to benefit from using containers.

However, if you need anything else on the server (another runtime, a database server, a mail server), Docker could still help. Having the whole tech stack pinned in version control is really nice, and having the ability to make any changes to one’s setup at whim is very liberating.

For admins, there’s a different advantage. Especially when multiple technologies are in use somewhere, containers are a standard interface to host any kind of server application the same way. You don’t need to know or care that one technology just copies a directory, the other one requires a specific configuration of Apache and the third one requires setting up an extra cron job — just start the container and you’re done.

But it’s always important to remember that there’s no shame in not using a technology that HN has deemed cool, particularly if it doesn’t solve a problem you have.


👤 Hackbraten
> To me a standalone application is simply a directory with an executable and all dependency-dlls in the same directory / some subdirectory.

Not everyone who packages an app is willing to lock all their dependencies into a specific version.

Look at dependencies that are usually coming from the system package manager, such as OpenSSL, pandoc, libicu, the timezone database, and whatnot. Sometimes those require updates. Apps may want to pick up those updates. I understand every app packager who says, „I don’t want to cut a new release every time an OpenSSL vulnerability gets patched, or whenever some country decides to update their time zone.“

So vendors may prefer their app to pick up system-level packages rather than ship those along with the app. Docker will update those packages for you every time you build your image, and you don’t depend on the app vendor to cut a release whenever you do. At the same time, containerization helps isolate versioning conflicts that stem from those common dependencies.


👤 ccouzens
> Docker is useful if you have multiple applications with different versions of the same dependencies running on the same machine, as well as for deploying onto any machine

Different languages get a different amount of boost here. Ruby is an example which strongly benefits from docker deploys. You don't need to worry about what version of ruby (if any) will be installed on the host. And you don't need to worry about getting your gem dependencies installed on the host or figure out how to bundle them into your app code.

I think older dot net apps required the runtime to be installed on the host. Docker would have helped then.

The other big draw of docker is uniformity in deployment (the shipping container metaphor). Deploying code of any language and third party apps can be very similar. This is a powerful enough idea that giant abstractions like kubernetes have come to exist. This would be much more fiddly if each application needed to be special cased.


👤 Faaak
How to you deal with resource allocation (memory limits, cpu limits, etc.) ? How to give a different IP address to each application ? What if an application fails and starts filling your disk space and thus impacts others ?

Docker, and the tools on top of that, can make these problems easier


👤 zorr
The logo for Docker is a shipping container. Most shipping containers have well-defined standardized dimensions. This way cranes/boats/trucks/trains all over the world can handle any container, regardless of what is in it.

Docker does this for software. A docker image packaging an application has a well-defined interface to start/stop/configure/log the application, regardless of which language it was written in.

This way infrastructure tools (for example container orchestration like Kubernetes, docker-compose, swarm,... but also CI/CD tools and local development environments) can work with all sorts of applications in the same way. Docker (or containers) provide a uniform interface to all of these tools.


👤 rr808
Docker helps with two problems DLLs dont:

1) what if I want to run your app on my Linux server and I dont have dotnet set up. I dont want to deal with installing and maintaining dontnet. And I dont trust your setup script

2) You want run a database and message as part of your application, and they aren't dotnet.


👤 Beltiras
System wide dependencies and settings become completely encapsulated. You can even run shell command lines repeatedly from the same system state with the "input" of the command being changed files in a mounted volume. DLLs don't solve those problems.

👤 kcartlidge
- Your DLLs, assets, etc comprise a complete application you can deploy anywhere.

- But that anywhere needs to be a consistent environment for you to be sure your application behaves as expected (OS versions, system libraries, file system layouts etc).

- Docker (actually containers generally) goes one step lower and provides that consistent environment by effectively running your application inside a precisely defined virtual OS that is always the same regardless of the actual hardware.

---

That's all moderately simplified, so not 100% precise terminology, but in effect you can think of Docker as a lightweight virtual machine to run your app in, that always behaves the same, and that can in turn be hosted inside most 'real' servers regardless of what they themselves are running.

A bit like running a PS1 game in a PS1 emulator on Windows, but running a .Net Core app in Debian on an Azure VM (for example).

The same config can be used to run the app in Debian on a local Windows box, or your designers Mac, without changes and with guaranteed identical behaviour as all your app sees is the Debian host.

(in reality it's more lightweight and faster launching than a VM is, and it's not actually using emulation, but that's all technical detail)


👤 Ecco
You personally don’t need Docker. Another example where it’s pretty much useless is if you can compile your code as a static binary.

Now if you use a wide variety of programs written in a wide variety of languages (e.g. a C database server and a Ruby web app and a JS daemon), then Docker is a very efficient way of staticizing your app just like you did with your .Net dlls or like you would by statically linking a Rust app.


👤 pmontra
Some dependencies are not DLLs. Actually docker needs a Linux kernel so there won't be any DLL, only .so, but that's basically the same thing. The point is that in a container we can encapsulate all libraries, files, other applications, etc, dump them in an image, ship, deploy and run them more or less as if they were in a VM of their own with no access to the rest of the system.

I don't know if there is a comparable technology for Windows. If you really want to appreciate the difference I think that you have to invest some time building and running docker containers and thinking if you really could do the same by switching DLLs. Don't forget the deployment story.


👤 wilde
1) Most software isn’t purely a collection of executable code. Usually there’s some configuration stored somewhere. (Files, registry, whatever.) Containerization ensures that we have one self-executing file that contains all of that state.

At this point you might respond with “I could zip up all that state and still make sure it unzips to a single folder” But that leads us to

2) Most production software has at least one dependency that needs isolation. Even if you’re good about making sure that you follow the rules to make folders self-isolating, eventually you’ll have to take a dependency made by someone who isn’t following the rules.


👤 altikereyedi
A container is a happy place for a piece of software.

It has all the dependencies it needs, there is nothing else executing, the files are laid out just the perfect way, every configuration file or environment variable just magically appears.

It's very cheap to create and get rid of this happy place in contrast to dedicating an entire VM or bare metal. It's also cheap to move containers around so you could orchestrate them on multiple hosts.

Even though they raise others, they really answer to a lot of questions around developing, deploying and monitoring software reliably. That's why it's usually worth the hussle.


👤 PaulHoule
Circa 2005 or so I had perfected methods for running large numbers of web applications on a server, which mostly involved being disciplined about where you keep files, configuration, etc.

Most people aren’t disciplined though.


👤 0xcoffee
If you have a standalone application, then great, maybe docker doesn't add a lot

Maybe your application requires xyz lib to be installed via apt or something similar

Now docker is useful, as it can maintain that environment easily

Now imagine you work in a company with many different teams, and just want a similar way of deploying all services without requiring knowledge of how the application dependency tree looks, just use docker everywhere.

That is why imo you see docker used in places it doesn't really offer a benefit, because a standardized way of deploying is a benefit in itself.


👤 HelloNurse
Suppose you have not one of your well behaved .NET apps, but 15 accumulated over time. You'd like them to share the same server, but they need different and incompatible OS fixes, different C runtime versions, multiple different executables with the same name in the PATH, carefully separated Windows Event Log categories, registry keys and whatever... sharing a server isn't so easy after all.

Docker lets you isolate a complete environment, not only your own application files.


👤 Const-me
I don’t do web development, but when I need something similar on Linux, I usually creating custom packages.

A bad thing about them, they are distro-specific: Debian is using deb packages, Alpine is using apk packages. Not just the installer other things are also substantially different between them. If deploying some services, some distros are using systemd but Alpine uses openrc. Firewalls are different as well.

At least in my experience it’s not terribly bad. On servers and embedded these environments are stable, people don’t usually switch randomly between unrelated distros.

A good thing about the approach is little to no overhead for runtime performance, management complexity (the installer infrastructure included in the OS makes it trivially easy to upgrade/remove these packages), and binary size.

These Linux repositories are huge, there’s very high chance whatever runtime support one might possibly need is already there, tested carefully by the maintainers of the distro. When that’s the case, a dependency becomes a single line in the package manifest, such as “libsomething (>= 12.34)” for a Debian package.


👤 pacifika
You can run multiple (.net or other) services that are required by a project or application suite and manage it in a generalised way.

For example a database container a application container a web server.

Maybe you’re confusing docker with something like flatpak. .Net applications AFAIK are already simple to package and run so the benefit there is limited.

Context I’m a web engineer.


👤 pacohope
In addition to what the others have written, let's not forget the abstraction of storage and networking. Docker let's you present virtual network interfaces to the software, so the config can be the same everywhere. Every container thinks it's listening on port 3000 on its local host. Without Docker, if you want to run 2 or 3 different bits of software on the same host but listening on different ports, that's has to be part of the software config, not external to the software config. With Docker, every instance of the software inside a container can have the same network config, but external to the container you can do whatever network jiggery-pokery you want to line it up.

Likewise Docker volumes and mount points. The software gets an abstracted filesystem that's actually a "volume". Could be a chunk of local filesystem, an NFS mount, whatever. The software doesn't need to know. It just acts like it's the only software on the "system" and writes to any path that it can find. It can't corrupt any other containers also running on the same host by writing global configuration files or making "system-wide" changes because those system wide changes are contained to the container.

Docker also abstracts a ton of sysadmin/deployment type tasks. I have 1 container of app X running on host A. There's a load spike. I want a second instance of app X running on host B. Ok. Load spike is over, I want to get rid of the instance of app X on host B. Docker makes this kind of dynamic deployment/destruction automatable via APIs and there's huge libraries of software out there to do it. I don't know about the .NET packaging/deployment (NuGet, etc.) and whether that's as easily done.

It sounds like you know a lot about .NET, and I know very little. So it's entirely possible that Microsoft has solved the network and storage abstraction in ways I don't know about. In that case, if you don't NEED Docker, because you have this homogenous environment and effective isolation controls built into it, be comfortable in your lack of need.


👤 nonplus
> what is an idiot-proof explanation for the need of docker in light of dlls?

I think the key thing is it's not a need. What you are doing is fine if your team can hire the talent they need to maintain (and grow) the product/software to match the companies needs.

OCI standards (what Docker uses) to some extent are trying to make a uniform ecosystem so engineers and architects know what to expect before digging into a project. That should not be compulsory though; other systems that work only make 'bigger' systems from places like the open container initiative better by showing what works in the wild.


👤 nullfield
The very very short? It’s fully isolated (as much as cgroups can be) and, more importantly, disposable. Cattle, not pets.

Runs funny? Shoot it in the head, process it, and replace it. Wrong version (hide color) today? Shoot it in the head and…


👤 watmough
I'm maybe a bit of an edge-case here, but I use Docker to provide a CentOS 7 compatible development and run-time environment for a CUDA-based visualization app. There are several benefits to this:

  * The Dockerfile describes my development environment,
  * I can replicate this environment just by setting up Docker and copying a few files,
  * I can run my development/run-time environment on *fast* AMD Ryzen 9 hardware that  causes a real CentOS 7 kernel to panic at boot.
For me, in practical terms, I can do a build in 6 minutes versus 25, when compared with my work laptop (2019 Razer Blade 15)

👤 samsaga2
The main reason to use Docker are the reproducible environments. Today, applications, have a lot of dependencies. In the application I am working, I have to install like ten different software programs and libraries only to be to run it, and I have to use concrete versions. If you work with other people, it is very tedious to have to install and configure all manually. With Docker you can make sure all of you are using the same kernel version with the same dependencies. So, also you can avoid, bugs derived from strange software versions combination.

👤 arwhatever
I think answering the initial question might benefit from a lot of context.

I've worked on quite a few teams who built atop dotnet core (cross-platform) and also have access to auto-horizontal-scaling PAAS solutions (such as Azure App Services) and who tend to reach for Docker well before they need it.

Now we all have to manage port mappings, env var mappings, file path mappings etc., the better part of a full OS-worth of abstractions when all the abstraction that we need is provided by the technologies I mentioned prior to adding Docker.


👤 tompazourek
I think it's a similar pattern, but at a different layer.

You can compose methods, compose classes/instances (DI), compose libraries/assemblies, compose processes, microservices, or entire apps and multi-app systems. There are similar patterns of composition, just each is at a different level of abstraction of the whole thing.

Sometimes it makes more sense to compose it inside an app, sometimes it makes more sense to design it differently and compose on another layer. Sometimes it can be both or it's blurry and not clear...


👤 partialzero
Ports.

Others will probably provide some other good reasons, but to me, Docker is multiplexing the global shared resource that is typically singular on a machine (at least a cloud/vm) - network ports. Of course you can easily stand up multiple services (of varying or same software platform) but you will need to carefully negotiate and manage and proxy ports. Docker provides an abstraction that does this for you, where services are hosted under unique internal host names which are easily addressable.


👤 sirwhinesalot
It's best to think of Docker containers as mini virtual machines. They let you have a system that always boots up in the same state. Thats not really possible with standalone apps because the state of the OS is not isolated, even changes to the PATH can easily screw things up. The problem is 10x worse in Linux with all its distros and that's where Docker was invented. Try making a standalone app in Linux and you're soon looking into flatpaks and AppImages which have their own problems.

👤 rvieira
The birds eye view of your application can be much more complex than code or library dependencies.

Your app might be expecting database X running on port Y, a specific OS version, Kafka running, etc...

Containers allow to configure all these "boxes" easily. Your co-worker can test the application with exactly the same "system" as you. And you can deploy it in that same "system" too.


👤 bluehatbrit
I'm going to use the word "container" because these days "docker" is really just a company that pushed them forwards but there are a bunch of different container types now.

Containers are really more about packaging and isolating applications in a standard way that is tech-stack agnostic. If your entire company runs .NET and the entire company deploys with DLLs in specific directories then you've got some of the benefits already. Containers take it a step further though, it's no longer something .NET, Python, Ruby, and Go developers all do differently - containers wrap around all of those.

Because containers are standard and agnostic to whats inside them you can also securely isolate without them even having to care about it. If your application writes files to a temp directory, you don't need to worry about another application also writing to that directory. If your application uses a particular port you don't need to worry about another .NET application also wanting to use that port. Suddenly you've gone from shipping oddly shaped boxes of different sizes and dimensions, and you've now just put everything from a car to 100,000 packets of M&M's into a standard package, the shipping container.

The ship doesn't give a crap what's inside each container, and the crew don't need to worry about figuring out the best way to fit everything in, they just know how many containers they can take, load them up, and go.

Whoever's responsible for your infrastructure no longer cares if you use .NET. You can decide to branch out into a bit of machine learning and use cobble together a model in python and all you need to do is create the container properly (Docker being a nice way of doing it). You hand the container to your infrastructure or infra team, request the right amount of resources, and it's there running very happily.

You also get some benefits around dependency management from this, such as deps are pulled in at container build time. Great! Now as long as that container image is around, you never have to resolve those deps again, there's no chance they will ever change under your feet for that container, and if they disappear you can still run the older versions of the containers as often as you like. That's not just the same for NuGet packages though, if you depend on an OS package like OpenSSL you don't need to worry that some other person will update it and it'll break your app.

Dependency management is almost a side-effect of the concept of containers, it's a great addition but the point was always standardising packaging and deployment of applications as a whole regardless of their technology.


👤 jenscow
VMs virtualise hardware, containers virtualise the OS.

Simply, it's like: `mount disk.img dir && chroot dir`

Or in Windows.. mounting a disk image to X: drive, then starting an application with SystemDrive=X:, SystemRoot=X:\Windows, etc. (pretend that works)


👤 dnndev
I had the same issue and we ended up skipping docker all together.

We went from hosting on prem to directly azure web apps.

Something in between I think is where docker would be helpful.


👤 oneplane
Because it's not about some code or about some shared stuff. It's about atomic operations across different hosts without involving hard-barriered teams.

A container image can be seen the same way a machine image can be used: you ship an image of a solution instead of some files and instructions and 'hope for the best'.

If you imagine your application and it's required environment as a complete machine as a starting point, and then running/scaling that by simply having the only requirement on any host be "it must be able to run this image". That's a much smaller and more standard interface than individual files.

If you were to just make a 'smaller' version of that you'd end up with chroot/jails and if you want to use cgroups on linux for isolation you'd end up with containers (i.e. Docker containers). It's not the only method or the best method, but it's the easiest and most widely supported method.

Going even 'smaller' you could simply build static binaries with everything included and tell the OS that when it gets started it should do so with no permissions to access anything else on the host.

Smaller beyond that is unikernels where your application is the OS and runs bare on a host (be it bare metal or virtual).

The downside of the last two is that all the 'extra' files like assets and temporary data needs to be embedded inside that single file. The downside of chroot and jail are that there is no cross-host packaging method and it usually just works on one specific OS or host.

Virtual machine images and container images have the same benefits but the virtual machine has the drawback that it is much bigger, much slower to start up (generally) and has a much larger attack surface and maintenance overhead.

What containers aren't is:

  - A package manager
  - Application Server Containers
  - Configuration management (well it shouldn't)
  - A replacement for a single-purpose VM
Technically containers also require you to be stateless and read-only. This nearly universally leads to better applications, better operations and better security. That gets us to the cattle vs. pets part of containers: the idea is that you ship containers, not whatever happens to be "inside" those containers. As long as a container is "good", any host that can run containers should be able to perform exactly the same to the point where running it on your laptop, on a mainframe and on a standard bare metal server does exactly the same thing. If you then wipe the server, install a different OS that can run containers and start the container again, it still does exactly what it should do.

👤 nikanj
Because DLLs are old and Docker is new.

DLLs have the unmistable stench of C++, COM and deep plumbing around them. Docker smells of json-over-http and familiar things.