Mounting the Docker Socket
Alright, let's get real for a moment. This one's a PSA, folks. We're diving into that elusive puzzle piece you might have missed in your docker-compose files. You know the one that's been quietly driving you nuts? Yeah, we've been there too. And hey, we even tweaked the logs to drop you some hints, but let's dissect this riddle anyway. You guessed it it’s the "/var/run/docker.sock:/var/run/docker.sock" volume mount. If you try to create a Lambda function, for example, you won’t be able to. This has happened enough times now that the logs look like this:
localstack | 2023-08-24T20:56:47.079 ERROR --- [Executor-1_0] l.services.lambda_.hints :
Failed to pull Docker image because Docker is not available in the LocalStack container but
required to run Lambda functions. Please add the Docker volume mount
"/var/run/docker.sock:/var/run/docker.sock" to your LocalStack startup.
Let’s break it down a bit and see how we got here. To optimize LocalStack as much as possible, every service that is available as an image will run in its own container. You’ll be able to see this with services like Lambda, ECS, certain databases, while resources like S3, API Gateway, etc., will continue to be part of the LocalStack main container.`
There are two striking ways of achieving this behaviour, known around the Internet as Docker-in-Docker and Docker-out-of-Docker. Jérôme Petazzoni adeptly articulates what lies behind both methods in this great blog post and why you’d wanna use one over the other.
DinD involves creating a separate Docker runtime environment within a container. This means that inside the container, you're essentially running another Docker daemon, isolated from the host's Docker daemon. This approach offers isolation and encapsulation, but it comes with its own set of challenges: security vulnerabilities, risk of data corruption, and overall the complexity might outweigh the isolation benefits.
In the DooD approach, you use the Docker daemon from the host system to interact with containers. Containers themselves don't have their own Docker runtime; they communicate with the host's Docker. This offers some distinct advantages: simplicity in managing the containers and resource efficiency, as containers don't need to run their own Docker daemon.
This way the main container will have access to the Docker socket and will, therefore, be able to start containers. The only difference is that instead of starting “child” containers, it will start “sibling” containers.
So, if you’re reading this on the go, next time you set up your docker-compose file you’ll hopefully visualize these diagrams and remember to add that simple YAML line before you realize you’re missing services ;).