systemd: serializar el arranque

systemd: serializar el arranque

El arranque en mi Ubuntu 17.04 falla y quiero depurarlo.

El arranque falla aleatoriamente y creo que se debe a una condición de carrera.

¿Puedo pedir que systemdno se ponga en paralelo ninguna tarea para poder ver si esto hace que el arranque falle de forma predecible?

Respuesta1

Una solución alternativa: ejecutar servicios manualmente

Tuve unfalla durante el inicio. En mi caso, el bloqueo se produjo después de alcanzar el basic.targetobjetivo, pero antes multi-user.target, por lo que quería saber cuál de los servicios iniciados multi-user.targetestaba causando el bloqueo.

Primero arreglé arrancar desde basic.targetmás un shell raíz. Puedes hacerlo permanentemente (¡suponiendo que consigas arrancar!) con

systemctl set-default basic.target
systemctl enable debug-shell

El debug-shellservicio ejecuta un shell raíz en tty 9.

Puede obtener el mismo efecto agregando los parámetros systemd.unit=basic.target systemd.debug-shella la línea de comando del kernel. Por ejemplo, en Grub, edite la línea de comando a algo como

linux /vmlinuz-4.13.0-38-generic root=/dev/mapper/crypt-root ro systemd.unit=basic.target systemd.debug-shell

Desde este shell, ejecuté el siguiente script para iniciar los servicios uno por uno. Tenga en cuenta que esto no se ha probado en gran medida (lo ejecuté una vez y falló como se esperaba en el servicio problemático).

#!/bin/sh
wants=$(systemctl show -p Wants multi-user.target | sed 's/^Wants=//' | tr ' ' '\n' | sort)
log=/var/tmp/multi-user-steps-$(date +%Y%m%d-%H%M%S)

log () {
  echo "$* ..." | tee -a "$log"
  sync
  "$@"
  ret=$?
  echo "$* -> $ret" | tee -a "$log"
  sync
  return $ret
}

# systemd services
for service in $wants; do
  log systemctl start $service
  sleep 2
done

# upstart services
for conf in /etc/init/*.conf; do
  service=${conf##*/}; service=${service%.conf}
  log service ${service} start
  sleep 2
done

# sysvinit services
for service in /etc/rc3.d/S*; do
  log ${service} start
  sleep 2
done

Agregar dependencias adicionales

El siguiente script declara dependencias "Antes" de las unidades systemd que son dependencias directas de un objetivo determinado para obligarlas a ejecutarse en un orden específico. Quizás quieras ejecutarlo en multi-user.targeto basic.target.

Tenga en cuenta queeste script no funciona en generalporque no tiene en cuenta las dependencias existentes: puede provocar un bucle de dependencia. Un script adecuado debe recopilar las dependencias existentes y realizar una clasificación topológica. Resolví mi problema, así que no tengo intención de trabajar más en él; Lo publico por si alguien quiere adaptarlo a sus necesidades.

Tenga en cuenta también que esto no afecta a los servicios Upstart y SysVinit.

¡Haga una copia de seguridad /etcantes de ejecutar esto! (Recomiendo encarecidamente usaretc guardián.)

#!/bin/sh
set -e

if [ $# -eq 0 ] || [ "$1" = "--help" ]; then
  cat <<EOF
Usage: $0 TARGET
Linearize the dependencies of a systemd target so it starts deterministically.
This scripts adds systemd unit files called linearize-for*.conf containing
extra Before= dependencies for each dependency of TARGET.
EOF
fi

service_dir=/etc/systemd/system
target=$1

wants=$(systemctl show -p Wants "$target" | sed 's/[^= ]*=//' |
                                            tr ' ' '\n' | sort)
previous=
for want in $wants; do
  [ -d "$service_dir/$want.d" ] || mkdir "$service_dir/$want.d"
  cat <<EOF >"$service_dir/$want.d/linearize-for-${target%.*}.conf"
[Unit]
Before=$previous
EOF
  previous=$want
done

información relacionada