Merge pull request #121021 from pennae/container-sigterm

nixos/nix-containers: use SIGTERM to stop containers
This commit is contained in:
Florian Klink 2021-04-30 21:35:16 +02:00 committed by GitHub
commit 44a0debca7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 11 deletions

View File

@ -35,6 +35,9 @@ let
'' ''
#! ${pkgs.runtimeShell} -e #! ${pkgs.runtimeShell} -e
# Exit early if we're asked to shut down.
trap "exit 0" SIGRTMIN+3
# Initialise the container side of the veth pair. # Initialise the container side of the veth pair.
if [ -n "$HOST_ADDRESS" ] || [ -n "$HOST_ADDRESS6" ] || if [ -n "$HOST_ADDRESS" ] || [ -n "$HOST_ADDRESS6" ] ||
[ -n "$LOCAL_ADDRESS" ] || [ -n "$LOCAL_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS" ] || [ -n "$LOCAL_ADDRESS6" ] ||
@ -60,8 +63,12 @@ let
${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)} ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
# Start the regular stage 1 script. # Start the regular stage 2 script.
exec "$1" # We source instead of exec to not lose an early stop signal, which is
# also the only _reliable_ shutdown signal we have since early stop
# does not execute ExecStop* commands.
set +e
. "$1"
'' ''
); );
@ -127,12 +134,16 @@ let
''} ''}
# Run systemd-nspawn without startup notification (we'll # Run systemd-nspawn without startup notification (we'll
# wait for the container systemd to signal readiness). # wait for the container systemd to signal readiness)
# Kill signal handling means systemd-nspawn will pass a system-halt signal
# to the container systemd when it receives SIGTERM for container shutdown;
# containerInit and stage2 have to handle this as well.
exec ${config.systemd.package}/bin/systemd-nspawn \ exec ${config.systemd.package}/bin/systemd-nspawn \
--keep-unit \ --keep-unit \
-M "$INSTANCE" -D "$root" $extraFlags \ -M "$INSTANCE" -D "$root" $extraFlags \
$EXTRA_NSPAWN_FLAGS \ $EXTRA_NSPAWN_FLAGS \
--notify-ready=yes \ --notify-ready=yes \
--kill-signal=SIGRTMIN+3 \
--bind-ro=/nix/store \ --bind-ro=/nix/store \
--bind-ro=/nix/var/nix/db \ --bind-ro=/nix/var/nix/db \
--bind-ro=/nix/var/nix/daemon-socket \ --bind-ro=/nix/var/nix/daemon-socket \
@ -259,13 +270,10 @@ let
Slice = "machine.slice"; Slice = "machine.slice";
Delegate = true; Delegate = true;
# Hack: we don't want to kill systemd-nspawn, since we call # We rely on systemd-nspawn turning a SIGTERM to itself into a shutdown
# "machinectl poweroff" in preStop to shut down the # signal (SIGRTMIN+3) for the inner container.
# container cleanly. But systemd requires sending a signal
# (at least if we want remaining processes to be killed
# after the timeout). So send an ignored signal.
KillMode = "mixed"; KillMode = "mixed";
KillSignal = "WINCH"; KillSignal = "TERM";
DevicePolicy = "closed"; DevicePolicy = "closed";
DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices; DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices;
@ -747,8 +755,6 @@ in
postStart = postStartScript dummyConfig; postStart = postStartScript dummyConfig;
preStop = "machinectl poweroff $INSTANCE";
restartIfChanged = false; restartIfChanged = false;
serviceConfig = serviceDirectives dummyConfig; serviceConfig = serviceDirectives dummyConfig;

View File

@ -111,6 +111,26 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
machine.succeed(f"nixos-container stop {id1}") machine.succeed(f"nixos-container stop {id1}")
machine.succeed(f"nixos-container start {id1}") machine.succeed(f"nixos-container start {id1}")
# clear serial backlog for next tests
machine.succeed("logger eat console backlog 3ea46eb2-7f82-4f70-b810-3f00e3dd4c4d")
machine.wait_for_console_text(
"eat console backlog 3ea46eb2-7f82-4f70-b810-3f00e3dd4c4d"
)
with subtest("Stop a container early"):
machine.succeed(f"nixos-container stop {id1}")
machine.succeed(f"nixos-container start {id1} &")
machine.wait_for_console_text("Stage 2")
machine.succeed(f"nixos-container stop {id1}")
machine.wait_for_console_text(f"Container {id1} exited successfully")
machine.succeed(f"nixos-container start {id1}")
with subtest("Stop a container without machined (regression test for #109695)"):
machine.systemctl("stop systemd-machined")
machine.succeed(f"nixos-container stop {id1}")
machine.wait_for_console_text(f"Container {id1} has been shut down")
machine.succeed(f"nixos-container start {id1}")
with subtest("tmpfiles are present"): with subtest("tmpfiles are present"):
machine.log("creating container tmpfiles") machine.log("creating container tmpfiles")
machine.succeed( machine.succeed(