What are Dev Containers you might ask?
Elementary, my dear Watson* / fellow developer.
It’s a fancy way of using container images as a full blown development environment. You can read containers.dev for more details, but the key IMHO that is missing on the homepage, is that it can run actual compose.yaml (popularised by docker-compose) as an entry point.
You can consider this post a follow up A Go(lang) journey in live reload and pretty panics. As I was writing tests, I realised that by just starting docker compose, there’s no easy way to have the tests also run in the container while also allowing the usage of the built in debugger in vscode.
I decided to give devcontainers a go, and see how they would work. The idea as mentioned in the intro is pretty nice since it allows you to:
- use a compose.yaml as your actual entry point to the system
- setup the required extensions in vscode (not strictly in the spec, but a nice to have)
- have the tests run in the actual container, so you don’t need to worry about different golang versions (or any other problems you might have with project specific packages)
You could argue that compared to the old-school setup of setting up your images, and then using them in something like Vagrant, this is a newer approach in which composability (ha, the puns) helps you build your development environment from various pieces.
If your database has different dependencies and packages from your queue system this makes it an non issue as each runs in its own container. Same goes for your test mailing system, queue system and whatever other dependency you will add in the future.
That brings us to the following config:
|
|
After you take a quick look at the config, you’ll notice an interesting key called initializeCommand
.
That is being used to actually solve a thing / bug / annoyance or whatever you want to call it.
Usually when you run inside a container, you mount your application code and then the user that container image is built with is the root user. That makes it annoying for a very simple reason, the owner of the file in WSL is going to be root, making it a pita to do cleanup and/or editing of the vscode workspace when the docker engine (in my case) doesn’t work.
To fix that, I’m semi abusing the functionality provided by compose.yaml to provide build arguments to the base image. The devcontainer.sh looks like this:
|
|
This allows the creation / reuse of the local .env file that gets automatically used by docker as a source for your ENV variables making the usage in compose.yaml painless.
|
|
Now we get to the Dockerfile
itself. It’s technically a container image, but for all intents and purposes you shouldn’t treat it different than a normal VM.
This is a development environment, so it is going to need all kinds of packages, especially for support tools like git.
|
|
After all is set and done, it is a pretty nifty and useful setup, since it makes the onboarding in your application a lot more approachable, and developers can just open it in vscoode and have a fully working environment.
With additional support from Jetbrains and other tools it will become hopefully more wide spread and used in other editors and ides, making the life of a DX (developer experience) engineer a lot easier (or however your organisation calls the hard working people that work on allowing your developers to focus on you know… development).
If this doesn’t work for you, you can buy me a beer and tell me how to improve it ;-).
* Yes, Sherlock never said that, but it's pop culture :P.