I have a simple express.js server that, for some operations, needs to spawn some docker containers. I want to dockerize this NodeJs server using a Dockerfile, so that it will spawn docker containers inside a docker container. My Dockerfile currently looks like this:
FROM docker:23.0.6-dind-alpine3.18
RUN apk update
RUN apk add --no-cache nodejs
RUN apk add --no-cache npm
RUN apk add --no-cache iptables bash
RUN apk add --no-cache --upgrade bash
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --force --verbose
COPY . .
RUN npm run completeBuild
EXPOSE 4000
CMD ["npm","start"]
I build it with:
docker build -t trydocker .
And I run it with:
docker run --privileged -it -p 4000:4000 -p 2375:2375 -p 2376:2376 trydocker
The server process gets spawned correctly and I can access my express server via localhost:4000.
But when I try to call docker pull
from inside the container I get an error that says that my docker daemon is not running.
Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?
Instead, if I remove the last directive CMD ["npm","start"]
from the Dockerfile, the docker daemon starts correctly, but my server is not online!
Is there a way to have both running?
I have looked at some related issues, like this one, but it did not help.
A Docker container only runs one process. Your image runs the Node application (its CMD
runs npm start
) but because of this it does not run the nested Docker daemon.
If you really need Docker-in-Docker (do you?) then you need to launch the nested Docker daemon as a sibling container. This Docker Compose setup could do it, for example:
version: '3.8'
services:
docker:
image: docker:24-dind
privileged: true
environment:
DOCKER_TLS_CERTDIR: /certs
volumes:
- docker-certs-ca:/certs/ca
- docker-certs-client:/certs/client
- docker-data:/var/lib/docker
app:
build: .
environment:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: /certs
volumes:
- docker-certs-client:/certs/client
volumes:
docker-certs-ca:
docker-certs-client:
docker-data:
The Docker Hub docker
image page has some more details on the settings.
Your application image itself doesn't embed the Docker daemon and so it can use a more normal node
image base
FROM node:lts
# exactly the last half of your existing Dockerfile
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --force --verbose
COPY . .
RUN npm run completeBuild
EXPOSE 4000
CMD ["npm","start"]
Using Docker-in-Docker is usually discouraged, since there are many complexities around which Docker daemon you're actually using and the DinD container must run in privileged mode. With this same Dockerfile, you could remove the docker
container and associated volumes, and instead bind-mount the host's /var/lib/docker.sock
socket file into the container on the same path, which would allow you to launch containers on the host's Docker daemon.