Skip to main content

Docker and Dumb-Init

· 4 min read

when it comes to containerized environment gracefull shutdown, process management and reducing attack surface, i believe we cant leave dumb-init out of it.

What is Dumb-init

Dumb-init, a tool developed by Yelp which is simple and non heavy process management tool with less footprint, so that way we dont end up exposing our applications to more issues through the tooling security vulnerabilities.

dumb-init can also be desribed as a tool who serves as parent process to other process in your docker or containers.

Why use dumb-init with your docker or containers

  1. Signal Forwarding

when you have the following CMD ["npm start"] in your Dockerfile, then if the npm start runs in your container, it will take the process PID 1 which is an init process, the first process that runs at the boot time of any Unix system.

PID   USER     TIME  COMMAND
1 node 0:00 npm start
6 node 0:01 node /app/node_modules/.bin/ts-node-dev --poll src/index.ts
17 node 4:09 sh
24 node 0:58 ps

And knowing that Node.js is not designed to run as PID 1, so running it as PID 1 would make it gives some unexpected behaviours such as the app not responding to the SIGTERM and other signals.

or if you have the following ENTRYPOINT ["source -c env && ./app.sh"] in your docker file, then source -c env && ./app.sh will become PID 1 and then the started application itself becomes a sub process and

PID   USER     TIME  COMMAND
1 node 0:00 source -c env && ./app.sh
6 node 0:01 app.sh -- Listening on PORT 9000

since the app itself is the one configured to handle SIGINT and SIGTERM, the shell script wont be able pass those signals to the app.

  1. Reduced attack surface

Since the container process are wrapped around dumb-init and other processes are now child to the dumb-init process which is PID 1 process now, this shields your app process againts responsibilities that comes with PID 1

for example if you want to make sure your app process doesn't assume new privileges in the container, you can simply set prctl(PR_SET_NO_NEW_PRIVS, 1) or use securityContext: allowPrivilegeEscalation=false, but this linux kernel feature doesn't works with PID 1 process, instead it works with the child processes.

So letting your main app process assume PID 1 in the container they are running can be risky.

Using Dumb-Init with your Dockerfile

You will have to install dumb-init in the dockerfile, also its advisable call this before other command layers.

now you can do this in two ways, using ENTRYPOINT, CMD or yaml file if you are working with kubernetes.

with ENTRYPOINT, you can call the dumb-init to be the PID 1

FROM node:latest
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init
....
ENTRYPOINT ["dumb-init","npm start"]

with ENTRYPOINT and CMD, you can call the dumb-init to be the PID 1

FROM node:latest
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init
....
ENTRYPOINT ["dumb-init", "--"]
CMD ["npm start"]

but in situation you are experiencing issues getting dumb-init in your docker images, there are other ways to get on depending on the system.

generalized containers with dumb-init binary

FROM node:latest
RUN wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64
chmod +x /usr/local/bin/dumb-init
....
ENTRYPOINT ["dumb-init", "--"]
CMD ["npm start"]

ubuntu

FROM ubuntu:latest
RUN apt install -y dumb-init
....
ENTRYPOINT ["dumb-init", "--"]

alphine

FROM alphine:latest
RUN apk add dumb-init
....
ENTRYPOINT ["dumb-init", "--"]

python

FROM python:latest
RUN pip3 install dumb-init
....
ENTRYPOINT ["dumb-init", "--"]

Using dumb-init with kubernetes yaml file

      containers:
- image: ourdockerfile:latest-dumb-init-installed
name: container-name
command:
['dumb-init', 'sh', '-c']
args:
['npm start']

Also if you pay closer attention to the dockerfile layer above, you will see they are not meeting the production/security readiness for creating Dockerfiles.

Its better to use multistage building and changing user ownership from root to node.

Well, that's it, folks! I hope you find this piece insightful and helpful.

References


Comments