Systemd mata el servicio inmediatamente después del inicio

14

Estoy escribiendo el archivo de unidad systemd para OSSEC HIDS. El problema es que cuando systemd inicia el servicio, los detiene inmediatamente.

Cuando uso esa directiva ExecStart todo funciona bien.

ExecStart=/var/ossec/bin/ossec-control start

Pero cuando hago una pequeña mejora, estoy bien en los registros de OSSEC, que recibe SIG 15 después del inicio.

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'

Si hago otro cambio pequeño, el servicio recibirá SIG 15 después de 20 segundos.

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'

Entonces, supongo, que systemd mata / bin / sh proceso después del inicio del servicio, y bin / sh luego mata a OSSEC.

¿Como puedó resolver esté problema?

Daniil Svetlov
fuente
1
¿Cuál es el tipo de servicio?
Wieland
@Wieland, estaba intentando simple y bifurcación, pero el resultado sigue siendo el mismo.
Daniil Svetlov

Respuestas:

36

falta de coincidencia del protocolo de preparación

Como Wieland implicó, Typela prestación del servicio es importante. Esa configuración indica qué protocolo de preparación systemd espera que el servicio hable. Se simplesupone que un servicio está listo de inmediato. Se considera forkingque un servicio está listo después de que su proceso inicial bifurca a un niño y luego se cierra. Se considera dbusque un servicio está listo cuando aparece un servidor en el Bus de escritorio. Etcétera.

Si no logra que el protocolo de preparación declarado en la unidad de servicio coincida con lo que hace el servicio, entonces las cosas salen mal. Los desajustes del protocolo de preparación hacen que los servicios no se inicien correctamente o (más comúnmente) sean diagnosticados (erróneamente) por systemd como fallidos. Cuando se considera que un servicio no puede iniciar systemd, se garantiza que todos los procesos adicionales huérfanos del servicio que podrían haberse dejado como parte de la falla (desde su punto de vista) se eliminan para que el servicio vuelva correctamente al estado inactivo. estado.

Estás haciendo exactamente esto.

En primer lugar, las cosas simples: sh -cno coincide Type=simpleo Type=forking.

En el simpleprotocolo, el proceso inicial se toma para ser el proceso de servicio. Pero, de hecho, un sh -ccontenedor ejecuta el programa de servicio real como un proceso secundario . Entonces MAINPIDsale mal y ExecReloaddeja de funcionar, para empezar. Cuando se usa Type=simple, uno debe usar sh -c 'exec …'o no usar sh -c en primer lugar. Este último es más a menudo el curso correcto de lo que algunas personas piensan.

sh -ctampoco coincide Type=forking. El protocolo de preparación para un forkingservicio es bastante específico. El proceso inicial tiene que bifurcar a un niño y luego salir. systemd aplica un tiempo de espera a este protocolo. Si el proceso inicial no se bifurca dentro del tiempo asignado, es un fracaso estar listo. Si el proceso inicial no sale dentro del tiempo asignado, eso también es un fracaso.

el horror innecesario que es ossec-control

Lo que nos lleva a las cosas complejas: ese ossec-controlguión.

Resulta que es un rcscript del Sistema 5 que desvía entre 4 y 10 procesos, que a su vez se bifurcan y salen también. Es uno de esos rcscripts del Sistema 5 que intenta administrar un conjunto completo de procesos del servidor en un solo script, con forbucles, condiciones de carrera, sleeps arbitrarios para tratar de evitarlos, modos de falla que pueden ahogar el sistema en un estado medio iniciado, y todos los otros horrores que hicieron que las personas inventaran cosas como el Controlador de recursos del sistema AIX y las herramientas demoníacas hace dos décadas. Y no olvidemos el script de shell oculto en un directorio binario que reescribe sobre la marcha, para implementar idiosincrásicos enabley disableverbos.

Entonces, cuando lo /bin/sh -c '/var/ossec/bin/ossec-control start'que sucede es que:

  1. systemd bifurca lo que espera que sea el proceso de servicio.
  2. Ese es el caparazón, que se bifurca ossec-control.
  3. Eso, a su vez, desembolsa entre 4 y 10 nietos.
  4. Los nietos se bifurcan y salen a su vez.
  5. Los bisnietos se bifurcan y salen en paralelo.
  6. ossec-control salidas
  7. Sale el primer caparazón.
  8. Los procesos de servicio fueron los grandes-estupendo, nietos, sino porque esta forma de partidos de trabajo ni el forking ni el simpleprotocolo de preparación, systemd considera el servicio como un todo para han fracasado y se cierra de nuevo hacia abajo.

Nada de este horror es realmente necesario bajo systemd en absoluto. Nada de eso.

una unidad de servicio de plantilla systemd

En cambio, uno escribe una unidad de plantilla muy simple :

[Unidad]
Descripción = El servidor OSSEC HIDS% i
Después = network.target 

[Servicio]
Tipo = simple
ExecStartPre = / usr / bin / env / var / ossec / bin /% p-% i -t
ExecStart = / usr / bin / env / var / ossec / bin /% p-% i -f

[Instalar en pc]
WantedBy = multi-user.target

Guarda esto como /etc/systemd/system/[email protected].

Los diversos servicios reales son instancias de esta plantilla, llamada:

Luego, la función de habilitar y deshabilitar viene directamente del sistema de administración de servicios (con el error RedHat 752774 corregido), sin necesidad de scripts de shell ocultos.

 systemctl enable ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ analysisd ossec @ logcollector ossec @ remoted ossec @ syscheckd ossec @ monitord

Además, systemd conoce y realiza un seguimiento de cada servicio real directamente. Puede filtrar sus registros con journalctl -u. Puede saber cuándo un servicio individual ha fallado. Sabe qué servicios se supone que están habilitados y en ejecución.

Por cierto: Type=simpley la -fopción es tan correcta aquí como en muchos otros casos. Muy pocos servicios en la naturaleza en realidad señalan su preparación a fuerza de exit, y estos tampoco son tales casos. Pero eso es lo que forkingsignifica el tipo. Los servicios en la naturaleza en general solo se bifurcan y salen debido a una noción errónea de sabiduría recibida de que eso es lo que se supone que deben hacer los demonios. De hecho, no lo es. No ha sido desde la década de 1990. Es hora de ponerse al día.

Otras lecturas

JdeBP
fuente
2
Respuesta muy detallada! También sugeriría crear un objetivo de "agrupación", por ejemplo, ossec.target, que Requires=todas las instancias necesarias, y luego establecer PartOf=ossec.targeten ossec @ .service. Esto permitirá iniciar y detener ossec iniciando y deteniendo ossec.target.
intelfx
@JdeBP, ¡guau! Muchas gracias por ese tipo de respuesta detallada. Espero hacer esta unidad y escribir aquí sobre los resultados. Sin embargo, pensé que sería más fácil. Pero tienes razón, ossec-controll es un infierno inicial.
Daniil Svetlov
1
¿Cuál es la razón para usar / usr / bin / env como envoltorio?
Marius Gedminas
1

Mantenga Type = forking y proporcione una ubicación de archivo pid si el servicio / aplicación de inicio mantiene cualquier pid.

[Unidad]
Descripción = "Ejecutar aplicación en el arranque"
Después = network.target syslog.target auditd.service

[Servicio]
Tipo = bifurcación
PIDFile = / var / run / apache2 / apache2.pid
ExecStart = / etc / init.d / apache2 iniciar
ExecStop = / etc / init.d / apache2 detener
StandardOutput = syslog
StandardError = syslog
Reiniciar = en caso de falla
SyslogIdentifier = webappslog

[Instalar]
WantedBy = multi-user.target
Alias ​​= webapps

Raushan
fuente
0

Algo relacionado, tenía un servicio systemd que parecía que systemd lo "mataría" después de los 30 años.

systemctl status service-nameaparecería main process exited, code=exited, status=1/FAILUREdespués de que hubieran transcurrido 30 años.

Funcionaría bien "de forma aislada" (como manualmente en la terminal con el mismo entorno ).

Resulta que era

Type=forking
...
Environment=ABC="TRUE"
ExecStart=/path/to/my_script_to_spawn_process.sh

dentro my_script_to_spawn_process.shestaba haciendo

/bin/something > /dev/null 2>&1 &

que funciona pero estaba descartando información de registro de salida (normalmente va a un archivo, o, si no es eso, posiblemente journalctl).

Cambiarlo para iniciar sesión en otro lugar como /bin/something > /tmp/my_file

luego siguiendo la /tmp/my_filerevelada la causa real. Lo que era (tangencialmente) que no puede usar la sintaxis Environment=ABC="true"como puede hacerlo en bash, no tiene que ser comillas o el valor clave, todo dentro de comillas, como lo Environment="ABC=true"que estaba causando que mi proceso salga "en su fase de configuración" después de unos 30 años.

rogerdpack
fuente
-4

Tenga en cuenta que el modelo de daemon de systemd es simplista e incompatible con muchos daemons existentes que realizan múltiples bifurcaciones, ejecuciones y ajustes. Los más comunes son los demonios que comienzan como root para configurar las cosas y luego cambian a un UID menos privilegiado para la operación de rutina. por ejemplo, la inicialización del archivo Pid es una cosa que falla en systemd debido a problemas de privilegios. Hay soluciones (no arreglos) pero está mal documentado.

La explicación de JdeBP es bienvenida pero incompleta y su afirmación de que todo es culpa del control de Ossec simplemente no es cierta. Incluso cosas bastante triviales son problemáticas, por ejemplo, obtener líneas de registro no truncadas para depurar problemas o mensajes de error significativos del propio sistema cuando mata procesos.

John
fuente
1
¿Para qué sirven los archivos PID? Si existe uno para un servicio determinado, puede haber o no un proceso real con ese PID, y cuando existe un proceso con el PID correcto, puede o no ser el servicio esperado.
JoostM