Eh.
If I'm running nginx on Debian I have to worry about Debian and Debian's version of nginx. If I'm running an nginx container on Debian I have to worry about Debian, Debian's container manager, the runtime nginx is containerized with, and the version of nginx in the container.
The release cadence of Debian is well-known and can be planned around. The release cadence of an nginx container is not well-known, and is another thing the intern can configure wrong (I still shudder every time I see shops use "FROM foo:latest" in production, which is shockingly common). Not to mention the addition of an entire new class of supply chain vulnerabilities to worry about/mitigate (yes, I can build my own container, but I can also just build my own .deb file).
All this conversation reminded me of Solaris containers having Linux compatibility layers that pretended you were running on Linux even though you had a Solaris kernel under it.
Wonder how much of that lives now in Illumos and other descendants of OpenSolaris.
I actively avoid running workloads on bare metal and have been doing so since the early 2000’s. It’s always easier to move a VM image to a new generic VM host than to reinstall everything from scratch.
What Docker does is to make delivering the app easier (it’s less involved than a full VM) and also automate the build process with a simple tool (Docker build).
Ansible?
Rebuild from playbooks, and/or Docker compose.
All containers are, are a standardized way to ship (distribute) your artifact (application) with it's dependencies inside it. It's a tar archive with a manifest file. I find it easier to think of them as RPM/deb files. You get an artifact repository for free and benefits of the onion file system to reduce size.
People package entire OS distributions in their container, I consider that an anti pattern. Unless you are shipping static HTML your container shouldn't have NGINX or any other stuff in their, especially if you are running NGINX in front of your container anyway.
If your app is written in Go/Rust/C, anything that produces a static executable, the only thing in the container should be the static executable... i.e. 'FROM scratch', 'cp my-app /bin/my-app`, 'ENTRYPOINT /bin/my-app'.
If you use Java, Node, Python, anything that needs a runtime you can use NIX to build a container with only the dependencies needed to run those, nothing else. If you don't like NIX there's other ways to do it although I'm not familiar with them personally.
All the security issues with containers comes from the junk rather than just your application and only the dependencies needed for that app. If a system library is not in your container you don't need to worry about patching it.
Containers I find are always a good idea, it's a standard way to package/distribute.
How you run those containers, that's another matter with Kubernetes becoming the de-facto because it's Kuberenetes and everyone else is using it. You don't need Kubernetes to run a container, especially if it is just one or a handful of containers.
Now, I 100% agree that an otherwise-empty container is all you need for a Go app, but then what is the container actually doing that I can't just do with cgroups in systemd or runit? The whole point of containers was "Devs! Free yourself from the tyranny of a sysadmin limiting your library choices!" but, well, that's exactly the problem they introduce.
You have several teams, each working on their own Python app. Each app is in various maturity levels, some are old in maintenance mode, some are new using the latest libraries.
These teams or other teams also have other languages they deploy outside of Python.
I'm familiar with Python but far from an expert. I think outside of Docker you would need to use Virtual env and maybe publish to a pip repo or package an an RPM/Deb. You'd have to roll your own build/deployment scripts. Alternatively you'd have ansible scripts or similar, maybe packer to build a vm or something. Multi tenant Python install's are bit of a pain which is why I think you'd need virtual env.
If you do use pip that will not work for teams who do not use Python so you'd have a second set of special build scripts and another way to distribute the app.
So in that scenario you have multiple different deployment mechanisms, a bunch of custom scripts etc.
Using a container would give you a common deployment mechanism across all languages. In your scenario though you should absolutely be a fascist greybeard and say "You must use our companies blessed base image before we will deploy your app". Then when a security update comes out you update the base image and send an email out saying "we see your app is using base image v0.0.0, we have released a new image with patched security vulnerability xyz, please update your application to use it by YYYY-MM-DD"
Nix wouldn't be to bad an alternative for a container but it has a few rough edges and getting everyone to build the nix way can be a big ask. Nix would solve the dependency + distribution issue with it's binary cache.
Either that or you trigger a rebuild of their images because a dependency changed.
This is one of the very few cases where using “:latest” is the right thing to do.
I maintain a docker image on Docker Hub (rbanffy/vm370) and I rebuild it from time to time so that it picks up the latest versions of the underlying OS. I still need to migrate it from Debian to something more minimalistic so that this becomes less of an overhead.
Containers give you an extra networking layer, theoretically, but the way it is implemented is extremely brittle and leaky, so most people don't use it anyway.
I assume the same logic applies if you're using some other way of building instead of Nix, too.
This is kind of a funny example to me because it’s one of the reasons I liked containers so much when I first encountered them: Debian’s packages are notoriously old, and anytime I wanted to run a newer version of something I’d wind up with some patchwork of configuration management code and shell scripts. In contrast, a Dockerfile provides a simple and clear way to run whichever version I want without messing with the base system, and even multiple versions of a given package with conflicting dependencies on the same machine without any fuss.
> Now you have fifty operating systems to upgrade instead of one. Enjoy.
Using nix-copy-closure basically solved all my problems with one command.
Also you need to worry about provenance of base containers, are they up to date wrt security fixes and are they trusted, etc.
Keeping it simple is what matters. At the base level you can treat a container very much like a single binary if you want to - build it, SCP it to a server, and add a systemd unit to run it. But you have the advantage (and some costs) of mostly isolating yourself from the runtime environment.
The orchestration frameworks are where I start to get itchy about complexity and would definitely put that process off as long as possible.
Using containers without a registry feels like a iffy middle ground. You lose the standard workflows and can't use it on container native platforms.. But maybe it makes sense sometimes.
It has upsides too, sure.
[0] https://github.com/marketplace/actions/digitalocean-app-plat...