7

A well-written program will be configurable. It will have a configuration file or database which specifies where to look for files, which network ports to open etc.

An Operating System lets many programs run together at the same time. It can place each program in a separate directory, no problem there.

So why is Docker neccessary? Is it possible that the main reason for Docker existing is to work around current limitations of Linux?

Docker avoids DLL hell by packaging applications together with the dynamic libraries they use. However, we could improve the way Linux looks for libraries or link the applications statically.

In Linux, there is another problem; Linux has fragmented to the point that a Linux program can only run on the flavour of Linux it was built on. Therefore Docker is needed, again, to make sure the libraries are included.

Operating Systems abstracted Displays, File Systems, Memory so that Applications could share the same hardware. Shouldn't the operating system be able to handle the configuration of applications as well?

Wouldn't it be better to improve Linux rather than invent Docker? I am a happy user of Docker, but I can't help wondering about this.

7
  • 2
    Have you gotten so far in your usage of docker that you are using docker-compose to run several docker instances talking together? That you have understod the pod concept of kubernetes allowing you to have many docker instances across several Linux hosts without having to care about outgrowing physical machines? Dec 8 '20 at 16:42
  • Thank you for your comment. No, I haven't looked into Kubernetes. I am approaching Docker because we have started using Git and want to adopt CI/CD. Our company compiles, tests and distributes C programs for various hardware architectures. Maybe we are not the best match for Gitlab CI/CD and Docker? Dec 8 '20 at 16:53
  • Re A well-written program will be configurable. Wouldn't that be nice? It would also be nice if programs were fully backward compatible. They aren't. Major releases are oftentimes used an excuse to drop backward compatibility. It would even nicer if programs / libraries were fully forward compatible -- for example, it would be nice if version 0.9 of some program / library could solve problems whose solutions were first introduced in version 3.0 of that program / library. Dec 8 '20 at 19:15
  • "We have started to use git and want to adopt ci/cd". You have a lot of technological progress to catch up on. I would suggest that you just go with "CI" - that is a build server triggered by commits - to ensure the build works and tests pass. You have tests, yes? Dec 11 '20 at 1:58
  • Not enough tests, no! :) Dec 11 '20 at 9:47
11

A major benefit of virtual machines and containers is the way you can isolate an application from any other applications, and reason about it as being a separate entity with clear interfaces that you can throw away or rebuild at any moment. It's like being able to have a lot of physical machines, but at virtually no cost.

Why does it matter, and wouldn't you have the exact same benefits “if applications behaved better”? Well, it depends on what you mean by better behavior. Imagine your machine hosts a very old piece of proprietary software which wasn't updated for ages, and which works on Windows 2000 only. The same machine hosts a relational database, and you learn that the support for the database will end by the end of December. Unfortunately, newer versions of the database rely on features which are only available on Windows Server 2008. What do you do?

Or simply imagine a Linux server hosting a few dozens of services and applications. You have just upgraded one of the applications, and discovered that it requires OpenSSL 1.1.1 for one of its features. You remember that there are at least several services which too rely on OpenSSL, although you don't remember well which ones. You also remember your colleague cursing aloud a year ago when somebody tried to upgrade the server from OpenSSL 1.0.2 to OpenSSL 1.1.0 and it broke the LDAP for the entire company. What do you do?

In both examples, applications don't behave badly in a sense that they overwrite each one's files or try to be the first to grab a specific port. They, however, have different expectations about their environment. In order not to do that, they need to find a way to be completely environment-agnostic. They can do it by putting themselves in a container, or be distributed in a form of a virtual or hardware machine. Some companies actually did this for a while. If you purchase their software, they came to put their servers in your physical data center. And now, there are a lot of applications distributed in a form of Docker containers.

You see, it's all about the level of abstraction that you need in a specific context:

enter image description here

Sometimes, you have applications which require a different kernel to be used. One app may work on Windows. Another one is limited to Linux. In order to host them both, you need a separation in a form of physical machines or virtual machines.

Sometimes, two apps can run on the same kernel, but they require different operating systems. With containers, you can indeed run an application on Debian, while using Red Hat kernel. Nothing wrong with that. Obviously, you can also use the two other forms of isolation: virtualization or dedicated hardware.

Some other times, you have two apps which don't care about operating systems and system libraries. Their sole difference is within the packages they use: for example, one Python app may use a specific version of a Python library, whereas the other one needs another version. Here, you can use venv for Python, or similar isolation technologies for other languages. Sometimes, the isolation comes for free, by design. In .NET, for instance, you can host together the applications which need different versions of assemblies, and even different versions of .NET itself.

The issue is with the element in the middle: the system dependencies. You believe that it's up to the operating system to provide some sort of isolation for the apps, in order to be able to provide different environment for each. The fact is, this is exactly what operating systems already do, in a form of user space—the thing which is used by Docker.

When you move from right to left, you notice that the isolation capability decreases, but the cost decreases as well. The isolation provided by .NET or venv comes at no cost in terms of time required to set it up or resources wasted, whereas, at the opposite, physical machines are expensive, cannot magically appear in your data center, and require human intervention (to install them in the rack and plug them in). This is why one would generally chose the isolation approach towards the right, even if the approaches on the right provide a higher level of isolation.

Anything you can do with virtual machines and containers, you could do without them as well, by purchasing a lot of hardware. You get the same isolation, and the same way to automate deployments (thanks to PXE). The difference, however, is that physical hardware costs a lot, wastes space (you're limited to 42 bays per rack cage, not counting the space needed for network devices and UPS units), and is extremely slow to set up: it could take a few weeks from the moment you decide to purchase a machine to the moment where your new web app is fully deployed on it.

With virtualization and containers, however, you can have a new machine running for free on a matter of seconds if we talk about a VM, or milliseconds if we talk about containers. And this is a complete game changer, because it encouraged extreme isolation one could rarely see in the past.

Essentially, containers are exactly what you talk about abstracting away the environment from the applications. You believe that it's up to the applications to be self-isolated. Well, they are, through containers.

Two examples:

  • Ten years ago, when you wanted, as a developer, to test a new database, or a fancy new JavaScript framework, you would install it on your development machine, play with it, and either uninstall it later or more probably keep it, because you never know when you'll want to play with it again. A few years later, you found yourself in a situation, where you have hundreds of things installed on your machine, and you don't even know half of them. It's a mess.

    And then some tools don't play well together, simply because they can't. At some point, you find a Python 3 library that you want to test. So you install Python 3. Later on, you find a tool which requires Python 2, and expects Python 2 to be the default version. Do you switch to Python 2, and take the risk of breaking something which was installed when Python 3 was the default on your machine? Or do you spend the next two hours tweaking the tool to work on your environment?

    Today, you would simply create a container, and play with the new technology within this container. It can even be an app you downloaded from a weird website you don't trust at all: if it's a virus, well, there is a chance it will make really nasty things inside your container. No big deal.

  • Ten years ago, it wasn't unusual (alas, it's still frequent even now) to see small companies hosting everything on the same server, because there is simply no enough money for additional hardware. You'll find the same machine running corporate LDAP, serving the website while also running the database it uses, hosting all the files distributed in a form of network shares, and doing dozens of other things. Chances are, in a case of a hardware failure or a hacker finding a way to get root access, the company is in a big, big trouble.

    With virtual machines and containers, it's different. Not only isolation prevents bad things from propagating to other machines/containers, but you can also rebuild a virtual machine or a container relatively easy, knowing it will have either no impact on the environment, or the impact will be very limited. You can destroy all the containers hosting your corporate website, and LDAP will still work. Or you can take down network shares, and the website will still serve requests.

5
  • Thank you! I will quote you when I explain to my colleagues why we are going down this road! Dec 8 '20 at 16:56
  • One thing that might be worth adding is repeatability. Every container you build is in a known state and can be used for dev, testing or production. It eliminates a lot of the fun of "works on my machine" or "can't reproduce in non-prod environment".
    – Becuzz
    Dec 8 '20 at 18:13
  • Another interesting angle to think about: would docker containers/VMs be necessary if OSes predicted these issues and were built around them. The iOS model of not having a shared file system with universal access is an example of this. Why are applications allowed to installed themselves anywhere BUT a single folder designated for them? The pollution across /bin, /usr, ~/usr, ~/bin, etc. is brutal
    – Alexander
    Dec 10 '20 at 3:54
  • Why would you need separate hardware? The question seems to be asking: Why don't you just run it all on one machine?
    – user253751
    Dec 10 '20 at 21:06
  • @user253751: fair. I edited my answer several times, and haven't noticed that it drifted away and was not answering the actual question. I edited it now by adding the paragraphs 2 to to 4. I hope it made it more relevant to the original question. Dec 10 '20 at 22:25
3

An Operating System lets many programs run together at the same time. It can place each program in a separate directory, no problem there.

So why is Docker neccessary? Is it possible that the main reason for Docker existing is to work around current limitations of Linux?

Docker (containerd, or other container runtimes) allow you to run processes in Isolated Environments (so called containers). Containers feel similar to Virtual Machines, but they aren't.

It's not Docker, that runs these Containers and the containing processes. It's the underlying Operating system (Linux) that does this. The docker backend is more like a convenient "frontend" or abstraction for a group of features of the linux-Kernel. One of these Kernel-Features, that you may have heard about is "chroot". It allows you to lock a process and its child-processes into a sub-tree of your File-System. Docker allowes you to manage these features in a simplified way (containers).

So technically, docker isn't necessary. You can provide the same level of process-isolation also with bash-scrips and the tools provided by the Linux-Kernel. But I don't know, why someone would do that, because using docker is much more simpler. Docker exists not because limitations of the Linux-kernel. It's more an abstraction of features of the Linux-kernel.

(These explanations are simplified, to give a coarse overview, of how containers work)

3

You are correct. In a perfect world, everything that Docker does (whatever that may be) would be done by the operating system.

Containers are just another form of process isolation, which is a core operating system feature.

Operating systems also allow processes to communicate with each other. These interfaces weren't really designed to form a cohesive whole - each new feature was duct-taped on until the entire operating system was made of duct tape. In this environment, setting up a reliable security boundary can be a nightmare, because there are so many features that could be used to poke a hole in it. Imagine your "sandboxed" process accidentally inherits a DBus socket file descriptor which it can use to install an item in your taskbar which launches a malicious program when you click on it. Oops. Docker is a kind of fresh start from that.

The holes go both ways. Many people publish Docker containers because they want to lock down the environment in which their program runs for reliability reasons. It's just as hard to control all the ways that information could accidentally sneak into a program.


You can actually see that a lot of research operating systems don't have any such holes. And it's actually quite easy to do. You just don't let processes have direct access to hardware.

Take Mach ports for example (disclaimer: I haven't actually used Mach). Everything in the system boils down to one form of IPC, which is called a port - basically a Unix socket. You send a request to the port, and get a response back. And you cannot get access to anything except by a port. And you can't get access to ports except by getting them from other ports.

Your process starts with a handful of ports (I think), which it must use to do everything it wants to. Of course, normally, these ports connect you to some central process which hands out access like candy (provided that you have permission). The first process gets a port from the kernel which allows it to access the computer's physical hardware.

That means if you want to sandbox a process, it's really easy. Instead of giving it the normal startup ports, you create your own ports and give it those! As far as the new process is concerned, your process is the central access-giving process - it can't tell the difference. Whenever it wants to access any part of the system, the request will go straight to your container process. There's no way for it to escape this sandbox, because it doesn't have any ports unless the sandbox gives them to it.

As far as I can tell, this is a pretty common approach to sandboxing. It seems almost like common sense, really. It's even used for sandboxing in scripting languages like Lua. You can achieve it on Linux with seccomp. And so on.

So why doesn't Linux do this? Well, it has to actually run your programs. Which use the Unix API. Whenever a team implements that API on one of these operating systems, they inevitably find out that everything is interconnected. If you want to run code that uses kill for example, you'll find yourself writing a "Unix PID manager", which implements PIDs like Unix does, and then you make it so the central access-giving process will give out access to the PID manager on request. And then, you can't stop process A from sending signals to process B. You can block it from accessing the PID manager at all but then it doesn't actually work. You can write your own sandboxed PID manager but then it's very difficult to allow access to PIDs outside the sandbox. And then the filesystem manager lets you read PIDs from /proc that don't line up with the ones in your fake PID manager. Oops! Better write a new filesystem manager too, since we can't remove /proc for compatibility reasons...

Even in this awesome-sounding security model, you end up having to either duplicate everything inside the sandbox and not be able to talk to things outside the sandbox (except through very narrow channels), or accept zillions of IPC holes for compatibility.

And the first one is an instant no-go because then people can't run their programs. Just look at Qubes OS, which tries to do this. It's been described as "separate computers which all just happened to share a display screen".

In fact, the macOS kernel (Darwin) implements Mach, but it also implements the Unix API in parallel, so you can't simply use the Mach sandboxing approach.


On Linux, Docker is the "duplicate everything inside the sandbox" approach. Running the program normally is the "accept zillions of holes" approach.


Update: Randall Munroe has created a webcomic about flip-flopping between isolating everything and accepting holes.

2
  • Well, if you want to get to the brass-tacks level on this, all of the functionality provided by "a container" is being "provided by the operating system." But they're being provided as "primitives." So now, what the container-management software is doing is: "stitching it all together into a consistent, easily(?) manageable illusion that an application program can run in." Jul 27 at 0:33
  • @MikeRobinson an illusion of... an operating system
    – user253751
    Jul 27 at 8:29
2

Let's take this from the top, shall we?

A well-written program will be configurable. It will have a configuration file or database which specifies where to look for files, which network ports to open etc.

This is quite a statement. Do you think curl needs a configuration for files to lookup? Which port to use? Some programs simply need some inputs, and it would even be detrimental to be able to configure them. Configuration != input. You don't need to be able to configure every bit of a program: this would lead to just more problems, like if you could configure each path an application looks up. Having some things un-configurable is an advantage, take git for example. You can't choose the name of the .git, that'd be such a hassle to deal with, and being able to ensure that every git repository has a .git folder is a nice way to tell if a directory is a repo or not.

An Operating System lets many programs run together at the same time. It can place each program in a separate directory, no problem there.

So why is Docker neccessary? Is it possible that the main reason for Docker existing is to work around current limitations of Linux?

No, Docker exists for about the same reasons as VMs exists: the need for abstraction. VMs abstract away the hardware, Docker and containers abstract away the operating system on which Docker is run. This is nice because, for instance, permits you to run Linux executables on Windows, without cross-compiling them.

Docker avoids DLL hell by packaging applications together with the dynamic libraries they use. However, we could improve the way Linux looks for libraries or link the applications statically.

Docker was never made to avoid DLL hell (which doesn't exist on Linux, by the way), it's just a result of the abstraction it provides. Because it abstracts away the operating system as a whole, you get out of DLL/libraries hell. Not the other way around.

In Linux, there is another problem; Linux has fragmented to the point that a Linux program can only run on the flavour of Linux it was built on. Therefore Docker is needed, again, to make sure the libraries are included.

I don't know where you're getting this idea, any statically linked Linux executable uses the ELF format, which means it could be run on any distro.

What you're referring to is only a problem if you explicitly use shared libraries, which is something you accept you have to deal with if you don't statically link all your dependencies. Docker is one solution to this problem, not the solution, nor was it made to solve only this problem. If you want to understand why Docker (and containers) exists, you have to stop thinking only about your problem with shared libraries and start thinking about the bigger picture.

Operating Systems abstracted Displays, File Systems, Memory so that Applications could share the same hardware. Shouldn't the operating system be able to handle the configuration of applications as well?

Wouldn't it be better to improve Linux rather than invent Docker? I am a happy user of Docker, but I can't help wondering about this.

And Docker thought that, for the benefits of reproducibility, stability and deployability, we should be able to abstract the operating system itself away: with Docker installed on a CentOS machine, I can run a container in Arch Linux if I want, and that's a nice thing for a lot of other reasons than "configuration".

I recommend you watch this talk to better understand what's a container. Maybe it'll help you get out of the "Docker is only there to abstract away configuration!". And even if it was, that'd still be quite a nice thing to have IMHO.

6
  • Wondeful answer, thank you very much! I will watch the talk. Dec 8 '20 at 17:26
  • 5
    While DLL hell doesn't exist on Linux (DLLs are a Windows-specific concept), an equivalent does exist on Linux. The generic concept is dependency hell, and even using Docker does not necessarily fix this. Dec 8 '20 at 19:09
  • @DavidHammen Yeah, I wrote "libraries hell" but I was definitely looking for "dependency hell", it slipped my mind.
    – Kawemi
    Dec 8 '20 at 21:21
  • Um, no, Docker absolutely doesn't achieve that. You're still using the same kernel. Docker does allow you to use a different version of a system library, but you can also do that without Docker.
    – user253751
    Dec 10 '20 at 21:07
  • @user253751 yes and no. Strictly speaking, a Linux-based container cannot run on Windows of course, but even from its very early days, the Docker for Windows included a Linux VM that made it seem like that. So effectively, from the point of view of the developer, it runs Linux containers on Windows. The other war around doesn't work at all, though. Dec 10 '20 at 21:56
2

Your question is based on an expectation that we can unify operating systems in a way that application files are universally compatible. In other words:

enter image description here

That's the long and short of it, really. If it were easy to unify these things, and everyone (from all sides) was in agreement, then we would have already done it.

That "if" in your own premise is a very big if. It requires both consensus on the intention and consensus on which system has to change to fit with the other. Herein lies a big problem: "Why should we change? Our way is better."

In the same vein, a lot of people agree that it would be better if we stopped with the metric/imperial unit schism, or the DMY/MDY schism. But neither party is willing to sacrifice their own system for that of the other, so nothing moves.

Enter Docker. Instead of waiting for the OSes to behave, which there seems little driving force for, it simply adds a compatibility layering between the OS and the application files, so that you do actually get that inter-OS-operability.

But Docker brings more value to the table than that. It also takes over the main responsibility of those who have to install/provision applications: installing the dependencies. If your server is going to run tools A, B and C, you have to check their requirements/dependencies and make sure that they are installed.

Tool D needs to be installed. Do we need to install extra dependencies? Maybe, unless the others already had the same dependency.

Hey, it's been a few years, do we still use dependency D1 on this server? Well, I don't know if the application that once needed it is still on the server. I'll have to check all currently installed application and see if I can find it.

There's a lot of management that goes into that, some of which is rooted in the concept of having shared dependencies. Docker throws the concept of shared dependencies out the window, because the relatively small additional file size means that you can skip a lot of the management juggling.

With docker, it's the equivalent of plug and play. You don't need to investigate dependencies or what else has been installed on the server. The only thing you have to consider is whether you either start your container or you don't, and the menial jobs inbetween are already taken care of.


As a whole, the answer to "if [problem] did not exist, would we need [solution to problem]?" is obviously no. But that question very much dodges the question of whether you can remove that problem and whether it's better/easier than the solution you already have.

1

You said,

Operating Systems abstracted Displays, File Systems, Memory so that Applications could share the same hardware.

Docker and Kubernetes abstract away Machines and Networks, so that applications can share all the hardware, even when not in the same physical machine.

10
  • How do they do this? You still can't share memory with a different machine. In fact Docker forces you to use networking even for processes that run on the same machine!
    – user253751
    Dec 10 '20 at 21:08
  • Docker doesn't. Kubernetes does it by ensuring that the host running the pod, has the resources the pod needs (stated in the various files describing how the pod should be deployed). If the pod tries to use more than it said it would, it is killed and restarted (perhaps elsewhere). Dec 11 '20 at 1:55
  • And yes, you need to use networking because how else will you make the isolation between "me" and the rest of the world? Dec 11 '20 at 1:56
  • You can also write a distributed application without Docker. Docker forces you to write one; it doesn't enable you to write one.
    – user253751
    Dec 11 '20 at 13:55
  • @user253751 Yes you can but then you don't get the benefit of "We are just running inside a Linux-box" API. Dec 11 '20 at 14:10
0

One of the rule I go by in computer science is:

It's all about humain

Sure, in a perfect world, docker would be detrimental to the global system as it take some precious processor cycle. Heck, memory mapping protection would not be needed and could be ditched! Free Hardware access for best performance!

Thing is: what docker is trying to solve is not a technical issue but a humain one: How does your team deals with dependency conflict? How does your team ship application? How does your team manage system and software update?

What is 5% cpu usage against being called at 1am on christmass eve cause the server is dead and you need to redeploy everything from scratch?

4
  • Thank you for your comment. I am not worried about the CPU cost of Docker or VM, but I do worry about whether we are building the next layer of computing solutions on a platform that may not be here long because it solved a problem that turned out to be fleeting. Unix is 50 years old - but will I get fired for choosing Docker? Dec 8 '20 at 16:57
  • 2
    I think I didn't built my answer properly then. The point docker is trying to solve will not go away (in our lifetime) because it is an organisation problem, not a technical one. You will never get fired for "choosing docker", you will be for "Recklessly using docker over your team established deployment process without providing any value". The discussion you want to have is about what you want to bring to the team and figure how docker can help you with that
    – s.lg
    Dec 8 '20 at 17:16
  • The answer is probably downvoted because it sounds like you think the problem is the CPU cost
    – user253751
    Dec 10 '20 at 21:59
  • @KáriHarðarson Going with docker allows you to focus on your solution and not how it should be run and where. This has traction, this will stay for the foreseeable future Dec 12 '20 at 11:14
0

You do not have to use Docker! If you have confidence in the reliability over you various applications you can run them together without docker and many, many systems run this way.

However most software has bugs and not just programming bugs misunderstanding business rules, wrong versions detailed in spec. etc. etc.

Look up the history of the mainframe program IEFBR14 which consisted of a single machine code operation. After running on numerous mainframes and being executed thousands of times a day - a bug report was raised and it become a two instruction program. It is an object lesson on how bugs creep into the simplest of programs.

0

"Docker" is only one of many "containerization solutions" that are out there. It is specifically engineered for a very-common use case in which you would like to stitch-together a new solution quickly by building it using "a series of 'black boxes.'"

For instance: "I want an [Apache Server] which talks to a [MySQL database] ..." or whatever. The General Store Is Open: grab what you need off the shelf." That's "Docker" for you.

"Containerization, itself," though, is much more generic than that. At its core, it is mostly a matter of clever illusion. You "put rose-colored glasses" on a process or series of processes so that they perceive "an environment" that doesn't actually match the reality of the hardware. Yet each one of them, as perceived by the host operating system, is in fact "an ordinary user process." This is much more "lightweight" than the alternatives, and much more scalable.

All of the underlying functionality that is needed to make "containerization" work is necessarily provided "by the operating system," but containerization software stitches the whole thing together into one functional, easily-manageable piece. ("The OS is performing the illusion, but the containerization system is managing the auditorium and selling tickets.")

The impetus for this development is simple – "cloud computing." It is, if you will, "'shared hosting' without the 'shared.'" The Docker paradigm is intended to provide maximum flexibility by encapsulating everything into opaque "black boxes" so that cloud hosts can predictably run them – on whatever hardware they have – without conflict.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.