1
0
mirror of /repos/baseimage-docker.git synced 2025-12-30 08:01:31 +01:00

Correctly handle Docker shutdown.

When a container is stopped with 'docker stop', SIGTERM is sent to the
init process. Unfortunately neither bash nor runit-init handle that correctly,
so we write our own init system in Python that also waits for all services to
shutdown.
This commit is contained in:
Hongli Lai (Phusion) 2013-11-12 22:36:55 +01:00
parent 7b4e2b6d77
commit 99306bcfcd
No known key found for this signature in database
GPG Key ID: 06A131094B6F4332

View File

@ -1,5 +1,64 @@
#!/bin/bash
set -e
# No exec. We want bash to be the init process so that it can kill
# zombie processes.
/usr/sbin/runsvdir-start
#!/usr/bin/python2
import os, sys, signal, errno
def reap_child(signum, frame):
global pid, status, waiting_for_runit
try:
result = os.wait3(os.WNOHANG)
if result is not None and pid == result[0]:
status = result[1]
except OSError:
pass
def stop_runit(signum, frame):
global pid
print("*** Shutting down runit (PID %d)..." % pid)
try:
os.kill(pid, signal.SIGHUP)
except OSError:
pass
# Start runit.
signal.signal(signal.SIGCHLD, reap_child)
print("*** Booting runit...")
pid = os.spawnl(os.P_NOWAIT, "/usr/sbin/runsvdir-start", "/usr/sbin/runsvdir-start")
print("*** Runit started as PID %d" % pid)
signal.signal(signal.SIGTERM, stop_runit)
# Wait for runit, and while waiting, reap any adopted orphans.
done = False
while not done:
try:
this_pid, status = os.waitpid(pid, 0)
done = True
except OSError as e:
if e.errno == errno.EINTR:
# Try again
pass
else:
# The SIGCHLD handler probably caught it.
done = True
# Runit has exited. Reset signal handlers.
print("*** Runit exited with code %s. Waiting for all services to shut down..." % status)
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
signal.siginterrupt(signal.SIGCHLD, False)
signal.siginterrupt(signal.SIGTERM, False)
# Wait at most 5 seconds for services to shut down.
import time
def shutdown(signum = None, frame = None):
global status
if status is not None:
sys.exit(status)
signal.signal(signal.SIGALRM, shutdown)
signal.alarm(5)
done = False
while not done:
done = os.system("/usr/bin/sv status /etc/service/* | grep -q '^run:'") != 0
if not done:
time.sleep(0.5)
shutdown()