77

There are --init and --init-path options for docker run, but it's not clear how to use it.

At first, I thought it's something like dumb-init, but included in docker core (kind of "native"). But --init key demands --init-path to be set as well, pointing to docker-init binary, and gives no clue on where to take it. Google is silent about docker-init.

Okay, maybe I'm supposed to use yelp/dumb-init or 'phusion/baseimage-docker', but those solutions don't seem to use docker run's --init option.

So, I'm curious where do I take this "docker-init binary" to set the --init-path to?

srk
  • 4,857
  • 12
  • 65
  • 109
Mikhail Vasin
  • 2,421
  • 1
  • 24
  • 31

2 Answers2

104

Specifiying the new docker --init option in the run command basically sets ENTRYPOINT to tini and passes the CMD to it or whatever you specify on the commandline.

For example, without init, CMD becomes pid 1. In this case, /bin/bash

docker run -ti --rm ubuntu:16.04 /bin/bash
root@d740f7360840:/# ps -fA
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  1 03:30 ?        00:00:00 /bin/bash
root        11     1  0 03:30 ?        00:00:00 ps -fA

With --init, tini (/dev/init) becomes pid 1

docker run -ti --init --rm ubuntu:16.04 /bin/bash
root@5b5fe6ee71b5:/# ps -fA
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  1 03:30 ?        00:00:00 /dev/init -- /bin/bash
root         7     1  0 03:30 ?        00:00:00 /bin/bash
root        12     7  0 03:30 ?        00:00:00 ps -fA

tini is a first class init process that can be run as pid 1 correctly. A pid 1 process must reap forked child processes correctly, if it doesn't then bad things happen like resources get leaked and zombies appear.

This is what you want for applications that fork and haven't been written with child reaping in mind as normally they would leave this up to the init system. A classic example is java Jenkins applications.

hookenz
  • 36,432
  • 45
  • 177
  • 286
  • 8
    Very good points here! I would also recommend to everyone to have a look on [this](https://github.com/krallin/tini/issues/8#issuecomment-146135930) post about tini – ira Oct 19 '17 at 16:42
  • So I've got an image with python app installed that has multiple commands and processes to run, webserver, monitor, worker… I made an entry point script which does some setup for each so I can run 3 versions of the image and pass only webserver, monitor, or worker as the command. The entry point handles a little bit of initialization for the webserver that differs from the others. I do get some zombie processes though if a gunicorn worker dies; I've been wondering if I can throw in `--init` and keep the entry point and command as is. – dlamblin Jul 02 '18 at 04:20
  • 1
    @dlamblin it seems to be possible; see the documentation of Tini here: https://github.com/krallin/tini#existing-entrypoint – Apteryx Aug 28 '19 at 01:43
  • @Apteryx; I actually wonder if using docker's `--init` will change the entrypoint to be prefixed by tini as tini docs suggest it should be, or if it leaves the entrypoint as is but then runs it with tini (effectively the same thing but different metadata on the image), or if it replaces the entrypoint with tini (which is what the docker docs seem to say). – dlamblin Aug 29 '19 at 08:04
  • 1
    @dlamblin looking at the PR for the --init feature (https://github.com/moby/moby/pull/26061/commits#diff-ea22bb26655e758dc94c291dbaee0e76R596), what the implementation does (in the populateCommonSpecs procedure of the oci_linux.go module) is: prefix any program and args that would have been executed with "/dev/init", which is bind-mounted to the binary of Tini. My guess is that the metadata is untouched, as this populateCommonSpecs command's purpose seems to be to initialize the base file system of the container. – Apteryx Aug 30 '19 at 00:55
  • 4
    One thing that I found misleading in this answer is that using `--init` doesn't actually set the entrypoint in the container metadata (i.e. if there is no ENTRYPOINT in the Dockerfile, and you use `--init`, the entrypoint field in `docker inspect` will still be null). What it does is setting the key `HostConfig.Init` to `true`. The docker-init binary (specified with init-path), is bind mounted as `/dev/init` in the container. When that key is set, `/dev/init` is prepended to the user's command args. Tested on docker 18.06. – init_js Jun 08 '20 at 18:02
10

I've found this in documentation:

You can use the --init flag to indicate that an init process should be used as the PID 1 in the container. Specifying an init process ensures the usual responsibilities of an init system, such as reaping zombie processes, are performed inside the created container. The default init process used is the first docker-init executable found in the system path of the Docker daemon process. This docker-init binary, included in the default installation, is backed by tini.

I couldn't find docker-init on a macOS Docker installation, but on Linux it's here:

/usr/bin/docker-init

Mikhail Vasin
  • 2,421
  • 1
  • 24
  • 31