Comment by bunderbunder
4 months ago
Years ago, this is exactly how I got my coworkers interested in containers. I never pushed for any changes to how we do things in production. All I did was start using containers to manage run-time environment on my workstation for development and testing purposes. And then my colleagues started to see how much less time I spent fussing with it compared to our more typical VM-based way of managing run-time environment. Soon enough people started asking me to help them get set up the same way, and eventually we containerized our CI pipeline too. But we never changed what was happening in production because Ops was perfectly happy with their VMs+Ansible setup and nobody had a reason to mess with it that was more cogent than "rah rah containers."
Fast forward to now, though, and I feel like the benefit of containers for development has largely been undone with the adoption of Devcontainers. Because, at least from my perspective, the real value of containers for development was looser coupling between the run-time environment for the application you do your typing in, and the run-time environment where you do your testing. And Devcontainers are designed to make those two tightly coupled again.
If you know your way around the Docker CLI, you can mount your workspace in a new container environment and run it however which way you want. You can attach VSCode to arbitrary containers. You can find the commands used to build the dev container image and run it, either in the logs or with docker inspect.
There’s no coupling being forced by devcontainers. It’s just a useful abstraction layer, versus doing it all manually. There is some magic happening under the hood where it takes your specified image or dockerfile and adds a few extra layers in there, but you can do that all yourself if you wanted to.
I will say, if you stray too far off the happy path with devcontainers, it will drive you insane, and you’ll be better off just doing it yourself, like most things that originated from MSFT. But those edge cases are pretty rare. 99% of workflows will be very happily supported with relatively minimal declarative json configuration.
Ok, but I love my devcontainer. It’s not like I can go back. I can’t install dozens of environment programs and variables and compilers and niche applications per machine.
The devcontainer, also does not preclude the simple testing container.
You wouldn't have to. You just set up your containerization scheme so that it doesn't rely on the editor extension.
I'm confused by your perspective.
The simplest (and arguably best) usage for a devcontainer is simply to set up a working development environment (i.e. to have the correct version of the compiler, linter, formatters, headers, static libraries, etc installed). Yes, you can do this via non-integrated container builds, but then you usually need to have your editor connect to such a container, so the language server can access all of that, plus when doing this manually you need to handle mapping in your source code.
Now, you probably want to have your main Dockerfile set up most of the same stuff for its build stage, although normally you want the output stage to only have the runtime stuff. For interpreted languages the output stage is usually similar to the "build" stage, but out to omit linters or other pure development time tooling.
If you want to avoid the overlap between your devcontainer and your main Dockerfile's build stage? Good idea! Just specify a stage in your main Dockerfile where you have all development time tooling installed, but which comes before you copy your code in. Then in your .devcontainer.json file, set the `build.dockerfile` property to point at your Dockerfile, and the `build.target` to specify that target stage. (If you need some customizations only for dev container, your docker file can have a tiny otherwise unused stage that derives from the previous one, with just those changes.)
Under this approach, the devcontainer is supposed to be suitable for basic development tasks (e.g. compiling, linting, running automated tests that don't need external services.), and any other non-containerized testing you would otherwise do. For your containerized testing, you want the `ghcr.io/devcontainers/features/docker-outside-of-docker:1` feature added, at which point you can just use just run `docker compose` from the editor terminal, exactly like you would if not using dev containers at all.