When I use the unadorned word “Docker” below, I’m generally referring to one or all of the Docker daemon, the Docker CLI, or perhaps the Docker image format, and no other additional/adjacent components. If that is not the way OP is using the word
Docker, I apologize now.
with regards to distribution, replication, process management, monitoring, and so on.
Strictly speaking, Docker itself as an individual tool doesn’t provide any considerations for these aspects of operating a complex and/or distributed system, without accentuating Docker with still more tools. Kubernetes, Nomad, Swarm, Mesos/DCOS, etc. cover a lot of these functionality gaps with varying approaches.
Distribution: Docker itself is not multi-host aware, and you cannot make it so without layering an orchestration tool on top, such as the aforementioned Kubernetes/Nomad/Swarm. The additional requirements for Swarm are included in most Docker OS packages, but that does not mean that its functionality comes for free or by default. There is no built-in way for container A on host 1 to directly communicate with container B on host 2 with no additional components involved. This concept is supported within the BEAM runtime.
Replication: In order to make sure that X copies of image ABC are running at all times, you need another component. Docker Compose can do some rudimentary scaling of a given container definition to more than one actual running container on a single host, but the Docker daemon itself doesn’t see them as having any direct relationship other than incidental similarities. Docker Compose is not multi-host aware without exporting an app bundle for use with Swarm, or translating to a similar manifest for Kubernetes using something like kompose. AFAIK, this is basically subject to DIY on the BEAM based on how you build your supervision trees, etc. but is not infeasible.
Process Management: This is the one possible exception that Docker itself might provide, depending on on whether you meant management of process groups composed of containers or process groups within single containers. Docker added a minimal
--init feature flag for
docker run and derived commands, which helps manage child processes within a single container. I believe it uses the semantics of, or directly leverages the code of, tini. It definitely cannot compete with systemd, upstart, runit, supervisord etc. for features or for complexity. More, I would say this functionality does not provide a useful degree of feature parity to process supervision trees in BEAM.
For multiple-container process groups, Docker Compose comes close with the YAML manifest plus a little bit of networking and DNS glue. However, all inter-container communication most go over a shared filesystem or network calls, even if they’re over
localhost, crossing various process and memory boundaries. Docker Compose itself is responsible for the creation and “enforcement” of that multi-container environment through its various sub-commands, and the Docker daemon doesn’t have inherent knowledge of those over-arching concerns.
Monitoring: Other than the option to restart exited containers always or under failure conditions, I don’t consider Docker itself to have had meaningful monitoring or supervision behavior for quite a lot of its life as a project. The late introduction of the
HEALTHCHECK directive for Dockerfiles did add some better capabilities of self-healing behavior compared to early releases. In Docker, you can’t natively express the idea that when one container exits abruptly, none/one/some/all of its logical siblings should also get restarted, but this is a first-class capability in BEAM.
Docker seems to provide a lot of the kinds of concurrent programming superpowers that the BEAM VM does.
Anything that Docker seems to be able to do with regards to concurrency is probably incidental, and are mostly enabled by the operating system itself, not by Docker. The running containers are just represented as separate OS processes (or process trees) on the host and are subject to the same kernel CPU scheduling as any other program you might run.
I would encourage most newcomers to think of Docker as providing three main value propositions:
- an extremely portable, straightforward, unsophisticated packaging format for your deliverables
- a way to (imperfectly) isolate those deliverables from each other while sharing an underlying host
- a vehicle for abstracting away the differences between different runtime environments and languages
On that last point, Docker doesn’t provide a great abstraction by itself, but by way of example, intentional design of disparate Docker images to have similar “APIs” in the form of their
CMD, etc. can present a unified front in a polyglot organization with applications authored in several different runtime languages.
To come at these points from another angle, operators of software packaged via Docker often only need to care about some limited logistical details:
- what image and tag to run
- what CPU/memory resources to allocate
- what simple arguments to supply
- what network ports to expose
- where to expose those ports to
The execution model of the program itself can be a black box. There’s no need for the operator to have much if any knowledge of the implementation language or other “internal” details.
I wouldn’t say any of these three value propositions have direct analogues in the BEAM, and some of them don’t seem to make sense for it anyway.