A
I'm struggling to understand the rationale of using Docker where the environments are essentially the same, and the applications are relatively simple.
In reality, it is highly unlikely that any development environment on any project would ever be anywhere near the same as staging/production.
Services running in staging/production will nearly always be physically hosted and managed somewhere which is not intended to be operated interactively by a human day-to-day, with an appropriate IT/security profile to match;
The nature of development work, and even internal build/testing typically requires a different IT profile to that of a production server.
Developers rarely have control over the underlying infrastructure or the organisation's IT/security policies.
There are many ways in which the IT profile of developer environments, including build agents and even test machines, can deviate from production:
Users/permissions or other security settings.
Installed tools, SDKs, runtimes, debug/test tools, OS features/packages, and other dependencies operating with debug/test configurations enabled.
Environment variables
Filesystem structure and the content of files in globally shared directories
Configurations of globally-installed dependencies such as web servers.
Furthermore, consider the nature of physical devices and VMs
They are stateful and mutable
Every change to any aspect of a device or VM, including installed software and configuration changes potentially affects its entire state for all processes running on it.
Physical devices and VMs typically run many processes/services concurrently, it would usually not be considered economical to have a whole server or VM just for a single running process.
What containers provide:
Isolation from the host device/VM and from an organisation's IT, Network and Infrastructure policies.
Isolation from each other - for example, consider the issue of requiring multiple versions of globally-installed runtime dependencies or modifications to shared host resources such as environment variables or local files.
Developers typically have full control over their choices of container images and the networking/orchestration inside the container runtime.
Images are based on immutable layers, meaning it is not possible for the state of any layer in an image to change, so a published image should always be a good, known, valid starting point.
The size of a parent image tends to be inconsequential because there's typically no reason to duplicate nor to re-download it unless a new version of that parent image is published.
A container is its own thin, mutable layer on top of an image, usually negligible in size, and uses the parent image for all dependencies.
if a container ends up in an invalid state, it may be quickly and cheaply disposed and replaced with a fresh, clean new container almost instantly by recreating another fresh new container layer.
The cheap, light-weight nature of containers makes it very efficient to run a single process per-container.