Non-Obvious Docker Uses
matt-rickard.com
matt-rickard.com
Nice thing about this strategy is that you can uniformly enforce dependencies, versions, etc
Unless you're talking about running it on Windows or Mac. In which case, don't do that. You don't want your developers developing on a different OS than your CI & deployment environment anyway.
Eh, this kinda depends on what tech you're using. We use node.js at work which has very good cross-platform support. And we've had literally zero issues developing on mac and deploying to Linux in the 3 years I've been here.
Or just tooling issues like BSD vs. GNU versions, Homebrew installing things differently (e.g. using the more logical 'openapi-generator' vs. 'openapi-generator-cli' used by upstream and respected by at least apt, apk, and pacman).
I’ve had issues where modules didn’t run when upgrading OS versions (either macOS or Linux - but usually macOS), but we run prod on LTS versions of Ubuntu so that doesn’t happen very frequently, gets caught by our staging server, and is usually a case of simply upgrading libraries to newer versions.
I suppose using busybox as your base image will most readily highlight any missing library issues if you fancy it.
(If I remember in the morning I think I can quite quickly find whatever it was that was last a problem - it was definitely an npm not a pip install when last I encountered it.)
We do both containerized and native for developing one service, but generally docker compose for the composition (vs say k8s or all native). And important that CI is in docker: that means we can do accurate local docker testing of same env in case of CI fails.
I totally agree, if the year was 1992.
Compute is cheap. Storage is cheap. Let's not try and keep living in the past.
I would argue that if you only have one good tool to do something, you have an opportunity to make much better tools for that something.
It's not docker's job to be better than Makefile with every use-case. You do realize what you're asking for here right? It's impossible. No tool is perfect for every use-case.
The root of this thread is
> We actually use docker multistage build as mentioned here as a replacement for make file.
So yes, it absolutely is reasonable to ask that docker, when used in the exact same way as make, should not give us a noticeable performance regression compared to running make.
It’s not a ratio that’s a problem, although that doesn’t help. It’s that there are psychological cutoffs where adding a minute to a build drastically changes how people interact with it. 1 vs 3 vs 7 vs >7 minutes make substantial differences.
So taking a build from 8 to 6 minutes is valuable out of all proportion to the actual speed up, and slowing from 6 to 8 is a substantial loss.
Another thing we have done is added cache mounts that let you keep application-specific cache between builds. This is usually, where the speed benefit from running things on the host used to come if your tools wrote some cache under $HOME etc.
There is still a constant container sandbox initialization time ~100ms, with some room to optimize that as well. If you have good examples of builds that can’t be easily optimized in containers would love to get your feedback/examples on the issue tracker.
Who's running OS X servers in production?
What are the devs running OS X and IntelliJ tools deploying on?
Mostly our devs run whichever of macOS or Windows is their personal preference (and in a few cases they choose Linux), and deploy to containers (or occasionally bare) Ubuntu or AWS Linux.
We occasionally get new devs bumping into the well known problems (case sensitivity, file path differences, some weird depenacncy that ends up platform-specific), but that's the kinda thing that is very easily debugged by someone who's made those mistakes before and even the greenest of new devs rarely make that same mistake twice (or at least they debug it themselves and don't admit to it).
You can very successfully write code that runs on Linux on either MacOS or Windows, depending on what you're developing.
Probably not a big deal, but just seems pointlessly narrow to think all developers would or should prefer actually developing on Linux exclusively.
Feels kinda wasteful sometimes to have all this compute horsepower in my MacBook, and then offload a bunch of the workload to a few hundred bucks worth of external hardware, but I reckon it'd saved my boss the entire cost of the NUC in the first week or two.
Not the right answer for everyone, but it works for me.
Except rather than using WSL2 for your local remote (confused yet? I am) sessions.
Hardware _is_ cheap, if MacOS can't support a decent enough environment for Docker, provide your Engineers with some cheap hardware like a NUC or even a remote AWS Linux EC2 instance or similar and get a native *nix environment that way.
Personally I’m a fan of buying a fancier Mac and running a VM that resembles production somewhat. I was using VMWare Fusion and now UTM. Works great for me by minimizing Homebrew drama.
Once the docker image is pulled into cache, a runc process is started, that process is placed into a specific cgroup and given various isolated namespaces, any volumes are mounted into the file system namespace, any special network mappings are created, and otherwise, yes running within Docker is as fast as running natively.
It depends what you're working on, but for a classic server backend in a high-level language, I don't find it a problem. It's very rare to hit an OS-specific problem, and it shows up in CI so the dev can correct it before code review.
Is there something obvious I may be doing wrong or some resources I should read about this?
It’s been a major issue for me. It seems to happen regardless of whether I’m using Docker Volumes or not.
When I started using Docker four years ago that was my biggest issue. When builds fail, I can't just pick up where it left to expect the environment and try stuff out (unless I purposely build an image with a ton of layers).
Soooo much time was wasted figuring out what was going on.
[0] https://www.gnu.org/software/make/manual/html_node/Choosing-...
[1] https://www.redhat.com/sysadmin/podman-inside-kubernetes
Don’t get me wrong, make is great, but I think it only really shines when you’re using a language like C/C++ where you can use it’s awesome dependency graphs. For projects in Go or JavaScript it quickly becomes a task runner with a very inconvenient syntax.
Earthly gives you a make-esque syntax while doing all of the work in Docker which gives you repeatability and parallelization for free.
Podman seems like a simpler container management tool for things that are merely wrapping/emulating traditional command line tools.
We use docker in this way for work, and it’s merely okay. We use docker to bundle the environment (which changes rarely) separate from the code and build system (which changes often). For this, docker has been great for 95% of all our internal users: way more than a makefile helped, but the remaining 5% were a huge pain. The most recent issue was the in-docker user having a different id from the local user, which isn’t a problem on macOS but is on Ubuntu.
At the point where docker made sense as a compatibility layer, it was trivial to convert the whole system into a service running on Kubernetes.
Probably the mount id mapping added in the linux kernel can be a way to resolve problem when user in docker and host have different id.
Although I don't know whether the system utils / docker command have integrated it or not yet.
[1]: https://github.com/kevin-hanselman/dud/blob/e98de8fcdf7ad564...
I tried `touch`ing hidden files for each step and then add those as a dependency but that is not very elegant. Do you have this problem at all?
Make is great and you'd likely use it inside the container. But everything around make is typically an enormous pain to manage across multiple machines, multiple architectures, etc. and that's where docker containers help greatly.
As if something being fast is all that matters.
As a more expressive frontend of BuildKit, we created a simple, non-Turing-complete logic programming language, which can also be thought of as docker-based Makefile.
Guess so!
I use a multistage build to generate a podman/docker image that contains all my build artifacts and then just copy them out of the container onto my host system. What advantages would there be in using BuildKit for this sort of thing?
I use Docker for sort of a virtual network interface to allow me to connect to two VPNs (a VPN inside a VPN environment). Any good hardware/software finds all sorts of niches to fill in time.
I use the Tailscale extension to let my development pods talk to my tailnet. It's really handy (would be even better if it worked with the local Kubernetes cluster in Desktop). Of course you can do this yourself fairly easily, but it's nice to have it "managed" for a non-essential part of the workflow.
- Alternative docker frontends - https://matt-rickard.com/building-a-new-dockerfile-frontend/ (https://github.com/r2d4/mockerfile)
- Docker merge - https://matt-rickard.com/docker-merge/ (https://github.com/r2d4/docker-merge)
[0] https://docs.docker.com/build/buildx/#build-multi-platform-i...
It also supports running other architecture images using the same QEMU magic. It's really quite polished and works well.
Docker does provide environment variables you can use to automatically download the right file depending on the target architecture, but the syntax is very cumbersome.
That said, yes using something on the JVM is much more convenient, but that’s not possible if you’re not using a JVM language.
I forget what they were using it for, but it boiled down to packing up a json file or two in a tarball and pushing it to the local daemon with a special suffix. Then it could pull that and unpack it on the next run.
- cosign signatures, SBOMs, attestations: https://docs.sigstore.dev/cosign/overview/
- Istio wasm plugins: https://istio.io/latest/docs/reference/config/proxy_extensio...
- OPA bundles: https://www.openpolicyagent.org/docs/v0.13.5/bundles/
- Tekton bundles: https://github.com/tektoncd/resolution/tree/main/bundleresol...
There's even a demo (plug: in a talk I co-presented) of running a RISC-V emulator where its memory is stored in an OCI registry: https://www.youtube.com/watch?v=Xt_G-pUArTM
These all tend to include a CLI to collect/generate/validate resources and push/move/pull them, but the underlying implementation is roughly the same -- package content in a tarball, generate some JSON pointing to it, push that JSON to the registry (with auth).
The real benefit to this is that basically everyone has access to a registry these days -- in their cloud provider, on-prem, whatever -- with exactly the same APIs and mostly sane auth and client tooling.
If you're interested in exploring it for your use case let me know, I'd be happy to give you some pointers.