Tabla de contenido
CMD
s6-overlay es un conjunto de scripts y utilidades fácil de instalar (¡simplemente extraiga uno o dos archivos tar!) que le permite usar imágenes de Docker existentes mientras usa s6 como pid 1 para su contenedor y supervisor de procesos para sus servicios.
Construya el siguiente Dockerfile y pruébelo:
# Use your favorite image
FROM ubuntu
ARG S6_OVERLAY_VERSION=3.2.0.2
RUN apt-get update && apt-get install -y nginx xz-utils
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
CMD ["/usr/sbin/nginx"]
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
ENTRYPOINT ["/init"]
docker-host $ docker build -t demo .
docker-host $ docker run --name s6demo -d -p 80:80 demo
docker-host $ docker top s6demo acxf
PID TTY STAT TIME COMMAND
11735 ? Ss 0:00 _ s6-svscan
11772 ? S 0:00 _ s6-supervise
11773 ? Ss 0:00 | _ s6-linux-init-s
11771 ? Ss 0:00 _ rc.init
11812 ? S 0:00 | _ nginx
11814 ? S 0:00 | _ nginx
11816 ? S 0:00 | _ nginx
11813 ? S 0:00 | _ nginx
11815 ? S 0:00 | _ nginx
11779 ? S 0:00 _ s6-supervise
11785 ? Ss 0:00 | _ s6-ipcserverd
11778 ? S 0:00 _ s6-supervise
docker-host $ curl --head http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 17 Jan 2022 13:33:58 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 17 Jan 2022 13:32:11 GMT
Connection: keep-alive
ETag: "61e56fdb-264"
Accept-Ranges: bytes
Si está migrando de una versión anterior de s6-overlay ( v2 ) a la nueva versión ( v3 ), es posible que deba realizar algunos cambios en sus servicios o en la forma en que usa s6-overlay para que todo funcione sin problemas. Este documento intenta ser preciso sobre cómo funciona la versión 3, pero tenemos una página separada que enumera las diferencias principales y las cosas que probablemente notará. ¡Léelo si estás en esta situación!
El proyecto tiene los siguientes objetivos:
cont-init.d
), finalización ( cont-finish.d
) y sus propios servicios con dependencias entre ellos.PID 1
adecuadas6
y s6-portable-utils
. Incluyen utilidades prácticas y componibles que nos hacen la vida mucho, mucho más fácil.logutil-service
que utiliza s6-log
bajo el capó.USER
de Docker, para ejecutar todo el árbol de procesos como un usuario específico. No es compatible con todas las funciones, detalles en la sección de notas. Uno de los mantras de Docker que se repite con frecuencia es "un proceso por contenedor", pero no estamos de acuerdo. No hay nada inherentemente malo en ejecutar múltiples procesos en un contenedor. Nuestra política es "una cosa por contenedor", más abstracta: un contenedor debe hacer una cosa, como "ejecutar un servicio de chat" o "ejecutar gitlab". Esto puede implicar múltiples procesos, lo cual está bien.
La otra razón por la que los autores de imágenes evitan a los supervisores de procesos es que creen que un supervisor de procesos debe reiniciar los servicios fallidos, lo que significa que el contenedor Docker nunca morirá.
Esto efectivamente rompe el ecosistema Docker: la mayoría de las imágenes ejecutan un proceso que saldrá cuando haya un error. Al salir en caso de error, permite que el administrador del sistema maneje las fallas como prefiera. Si su imagen nunca saldrá, ahora necesita algún método alternativo de recuperación de errores y notificación de fallas.
Nuestra política es que si "la cosa" falla, entonces el contenedor también debería fallar. Hacemos esto determinando qué procesos pueden reiniciarse y cuáles deberían cerrar el contenedor. Por ejemplo, si falla cron
o syslog
, lo más probable es que su contenedor pueda reiniciarlo sin efectos nocivos, pero si falla ejabberd
, el contenedor debería cerrarse para que el administrador del sistema pueda tomar medidas.
Nuestra interpretación de "The Docker Way" es la siguiente:
y nuestro sistema de inicio está diseñado para hacer exactamente eso. Sus imágenes se comportarán como otras imágenes de Docker y encajarán con el ecosistema de imágenes existente.
Consulte "Escribir un script de finalización opcional" en la sección Uso para obtener detalles sobre cómo detener "la cosa".
Nuestro inicio de superposición está adecuadamente personalizado para ejecutarse adecuadamente en entornos en contenedores. Esta sección explica brevemente cómo funcionan las etapas, pero si desea saber cómo debería funcionar un sistema de inicio completo, puede leer este artículo: Cómo ejecutar s6-svscan como proceso 1
/etc/cont-init.d
./etc/s6-overlay/s6-rc.d
, siguiendo las dependencias/etc/services.d
) a un directorio temporal y haga que s6 los inicie (y supervise)./etc/cont-finish.d
.TERM
. De todos modos, no debería haber ningún proceso restante.KILL
. Entonces el contenedor sale. s6-overlay viene como un conjunto de archivos tar que puedes extraer en tu imagen. Los archivos tar que necesitas son función de la imagen que utilizas; la mayoría de las personas necesitarán los dos primeros, y los otros son extras que puedes usar cuando te convenga.
s6-overlay-noarch.tar.xz
: este tarball contiene los scripts que implementan la superposición. Lo llamamos "noarch" porque es independiente de la arquitectura: sólo contiene scripts y otros archivos de texto. Todos los que quieran ejecutar s6-overlay deben extraer este archivo tar.s6-overlay-x86_64.tar.xz
: reemplace x86_64
con la arquitectura de su sistema. Este tarball contiene todos los binarios necesarios del ecosistema s6, todos vinculados estáticamente y fuera del camino de los binarios de su imagen. A menos que esté seguro de que su imagen ya viene con todos los paquetes que proporcionan los archivos binarios utilizados en la superposición, debe extraer este archivo tar.s6-overlay-symlinks-noarch.tar.xz
: este tarball contiene enlaces simbólicos a los scripts de s6-overlay para que sean accesibles a través de /usr/bin
. Normalmente no es necesario, se puede acceder a todos los scripts a través de la variable de entorno PATH, pero si tiene scripts de usuario antiguos que contienen shebangs como #!/usr/bin/with-contenv
, instalar estos enlaces simbólicos hará que funcionen.s6-overlay-symlinks-arch.tar.xz
: este tarball contiene enlaces simbólicos a los archivos binarios del ecosistema s6 proporcionados por el segundo tarball, para que sean accesibles a través de /usr/bin
. Normalmente no es necesario, pero si tiene scripts de usuario antiguos que contienen shebangs como #!/usr/bin/execlineb
, instalar estos enlaces simbólicos hará que funcionen.syslogd-overlay-noarch.tar.xz
: este archivo tar contiene definiciones para un servicio syslogd
. Si está ejecutando demonios que no pueden iniciar sesión en stderr para aprovechar la infraestructura de registro s6, pero codifica el uso del antiguo mecanismo syslog()
, puede extraer este tarball y su contenedor ejecutará una emulación ligera de un demonio syslogd
, por lo que sus registros de syslog serán capturados y almacenados en el disco.Para instalar esos archivos tar, agregue líneas a su Dockerfile que correspondan a la funcionalidad que desea instalar. Por ejemplo, la mayoría de la gente usaría lo siguiente:
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
Asegúrese de conservar los permisos del archivo al extraer (es decir, usar la opción -p
para tar
).
El proyecto se distribuye como un conjunto de archivos .tar.xz estándar, que se extraen de la raíz de la imagen. (Necesita el paquete xz-utils para tar
para comprender los archivos .tar.xz
; está disponible en todas las distribuciones, pero no siempre en las imágenes del contenedor predeterminado, por lo que es posible que necesite apt install xz-utils
o apk add xz
, o equivalente, antes de poder expandir los archivos).
Luego, configure su ENTRYPOINT
en /init
.
En este momento, recomendamos usar la directiva ADD
de Docker en lugar de ejecutar wget
o curl
en una directiva RUN
: Docker puede manejar la URL https cuando usa ADD
, mientras que es posible que su imagen base no pueda usar https o que ni siquiera tenga wget
o curl
instalados.
A partir de ahí, tienes un par de opciones:
CMD
de su imagen.CMD
Usar CMD
es una forma conveniente de aprovechar la superposición. Su CMD
se puede proporcionar en el momento de la compilación en el Dockerfile o en el tiempo de ejecución en la línea de comando; de cualquier manera está bien. Se ejecutará como un proceso normal en el entorno configurado por s6; cuando falla o sale, el contenedor se cerrará limpiamente y saldrá. Puede ejecutar programas interactivos de esta manera: solo el CMD recibirá su comando interactivo, los procesos de soporte no se verán afectados.
Por ejemplo:
FROM busybox
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
ENTRYPOINT ["/init"]
docker-host $ docker build -t s6demo .
docker-host $ docker run -ti s6demo /bin/sh
/package/admin/s6-overlay/libexec/preinit: notice: /var/run is not a symlink to /run, fixing it
s6-rc: info: service s6rc-oneshot-runner: starting
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
s6-rc: info: service legacy-services successfully started
/ # ps
PID USER TIME COMMAND
1 root 0:00 /package/admin/s6/command/s6-svscan -d4 -- /run/service
17 root 0:00 {rc.init} /bin/sh -e /run/s6/basedir/scripts/rc.init top /bin/sh
18 root 0:00 s6-supervise s6-linux-init-shutdownd
20 root 0:00 /package/admin/s6-linux-init/command/s6-linux-init-shutdownd -c /run/s6/basedir -g 3000 -C -B
24 root 0:00 s6-supervise s6rc-fdholder
25 root 0:00 s6-supervise s6rc-oneshot-runner
31 root 0:00 /package/admin/s6/command/s6-ipcserverd -1 -- /package/admin/s6/command/s6-ipcserver-access -v0 -E -l0 -i data/rules -- /packa
58 root 0:00 /bin/sh
66 root 0:00 ps
/ # exit
s6-rc: info: service legacy-services: stopping
s6-rc: info: service legacy-services successfully stopped
s6-rc: info: service legacy-cont-init: stopping
s6-rc: info: service legacy-cont-init successfully stopped
s6-rc: info: service fix-attrs: stopping
s6-rc: info: service fix-attrs successfully stopped
s6-rc: info: service s6rc-oneshot-runner: stopping
s6-rc: info: service s6rc-oneshot-runner successfully stopped
docker-host $
La otra forma de utilizar un contenedor con s6-overlay es supervisar sus servicios. Puede supervisar cualquier número de servicios; Por lo general, son solo servicios de soporte para el demonio principal que ejecuta como CMD, pero si eso es lo que desea, nada le impide tener un CMD vacío y ejecutar su demonio principal también como un servicio supervisado. En ese caso, s6 reiniciará el demonio cada vez que salga; el contenedor solo se detendrá cuando usted le indique que lo haga, ya sea mediante un comando docker stop
o desde el interior del contenedor con el comando /run/s6/basedir/bin/halt
.
Hay dos formas de realizar un servicio supervisado. La forma anterior, que todavía se admite, es crear un directorio de servicios "puro s6". Cree un directorio con el nombre de su servicio en /etc/services.d
y coloque un archivo run
ejecutable en él; este es el archivo en el que colocará la ejecución del proceso de larga duración. Para obtener detalles sobre la supervisión de los directorios de servicios y cómo puede configurar cómo s6 maneja su demonio, puede consultar la documentación de servicedir. Un ejemplo sencillo se vería así:
/etc/services.d/myapp/run
:
#!/command/execlineb -P
nginx -g "daemon off;"
La nueva forma es crear un directorio de definición de origen de s6-rc en el directorio /etc/s6-overlay/s6-rc.d
y agregar el nombre de ese directorio al paquete user
, es decir, crear un archivo vacío con el mismo nombre. en el directorio /etc/s6-overlay/s6-rc.d/user/contents.d
. El formato de un directorio de definición de origen se describe en esta página. Tenga en cuenta que puede definir longruns , es decir, demonios que serán supervisados por s6 al igual que con el método /etc/services.d
, pero también oneshots , es decir, programas que se ejecutarán una vez y saldrán. Su servicio principal probablemente sea de largo plazo , no de una sola vez : probablemente necesite un demonio para quedarse.
La ventaja de este nuevo formato es que le permite definir dependencias entre servicios: si B depende de A , entonces A comenzará primero, luego B comenzará cuando A esté listo y cuando se le indique al contenedor que salga, B se detendrá. primero, luego A. Si tiene una arquitectura compleja donde varios procesos dependen unos de otros, o simplemente donde tiene que mezclar one-shots y longruns en un orden preciso, esto puede ser para usted.
El ejemplo anterior podría reescribirse de esta manera:
/etc/s6-overlay/s6-rc.d/myapp/type
:
longrun
/etc/s6-overlay/s6-rc.d/myapp/run
:
#!/command/execlineb -P
nginx -g "daemon off;"
/etc/s6-overlay/s6-rc.d/user/contents.d/myapp
: archivo vacío. (Esto agrega myapp
al conjunto de servicios que s6-rc iniciará en el arranque del contenedor).
/etc/s6-overlay/s6-rc.d/myapp/dependencies.d/base
: archivo vacío. (Esto le indica a s6-rc que solo inicie myapp
cuando todos los servicios básicos estén listos: evita condiciones de carrera).
Le recomendamos que cambie al nuevo formato, pero si no necesita sus beneficios, puede seguir con los directorios de servicios habituales en /etc/services.d
, funcionará igual de bien.
Si ejecuta su servicio principal como CMD, no tiene nada que hacer: cuando su CMD sale, o cuando ejecuta docker stop
, el contenedor saldrá naturalmente con el mismo código de salida que su servicio. (Sin embargo, tenga en cuenta que en el caso docker stop
, su servicio obtendrá un SIGTERM, en cuyo caso el código de salida dependerá completamente de cómo lo maneje su servicio; podría atraparlo y salir de 0, atraparlo y salir de otra cosa. , o no atraparlo y dejar que el shell salga de su propio código (normalmente 130).
Sin embargo, si ejecuta su servicio principal como un servicio supervisado, las cosas son diferentes y necesita decirle al contenedor con qué código salir cuando le envía un comando docker stop
. Para hacer eso, necesitas escribir un script finish
:
/etc/services.d
, necesita un script ejecutable /etc/services.d/myapp/finish
./etc/s6-overlay/s6-rc.d/myapp/finish
que contenga su script (el archivo puede ser ejecutable o no). Este script finish
se ejecutará cuando finalice su servicio y tomará dos argumentos:
En el script finish
, debe escribir el código de salida del contenedor que desea en el archivo /run/s6-linux-init-container-results/exitcode
, y eso es todo.
Por ejemplo, el script finish
del servicio myapp
anterior podría ser algo como esto:
#! /bin/sh
if test " $1 " -eq 256 ; then
e= $(( 128 + $2 ))
else
e= " $1 "
fi
echo " $e " > /run/s6-linux-init-container-results/exitcode
Cuando envía un comando docker stop
a su contenedor, el servicio myapp
se cerrará y se ejecutará este script; escribirá el código de salida de myapp
(si myapp
capta la señal TERM) o 130 (si myapp
no capta la señal TERM) en el archivo especial /run/s6-linux-init-container-results/exitcode
, que será leído por s6-overlay al final del procedimiento de cierre del contenedor, y su contenedor saldrá con ese valor.
Esta sección describe una funcionalidad de las versiones de s6-overlay anteriores a la v3. fix-attrs todavía se admite en v3, pero está obsoleto por varias razones: una de ellas es que generalmente no es una buena política cambiar la propiedad de forma dinámica cuando se puede hacer de forma estática. Otra razón es que no funciona con contenedores USER. En lugar de fix-attrs, ahora le recomendamos que se ocupe de la propiedad y los permisos en los montajes del host sin conexión, antes de ejecutar el contenedor . Esto debe hacerse en su Dockerfile, cuando tenga toda la información necesaria.
Dicho esto, esto es lo que escribimos para versiones anteriores y que todavía se aplica hoy (pero deje de depender de ello):
A veces es interesante corregir la propiedad y los permisos antes de continuar porque, por ejemplo, ha montado/asignado una carpeta de host dentro de su contenedor. Nuestra superposición proporciona una forma de abordar este problema utilizando archivos en /etc/fix-attrs.d
. Este es el formato de patrón seguido por los archivos fix-attrs:
path recurse account fmode dmode
path
: ruta de archivo o directorio.recurse
: (establecido en true
o false
) Si se encuentra una carpeta, recurra a través de todos los archivos y carpetas que contiene.account
: Cuenta de destino. Es posible utilizar de forma predeterminada uid:gid
si no se encuentra la cuenta. Por ejemplo, nobody,32768:32768
intentaría usar la cuenta nobody
primero y luego recurriría al uid 32768
. Si, por ejemplo, la cuenta daemon
es UID=2
y GID=2
, estos son los valores posibles para el campo account
:daemon: UID=2 GID=2
daemon,3:4: UID=2 GID=2
2:2,3:4: UID=2 GID=2
daemon:11111,3:4: UID=2 GID=11111
11111:daemon,3:4: UID=11111 GID=2
daemon:daemon,3:4: UID=2 GID=2
daemon:unexisting,3:4: UID=2 GID=4
unexisting:daemon,3:4: UID=3 GID=2
11111:11111,3:4: UID=11111 GID=11111
fmode
: modo de archivo de destino. Por ejemplo, 0644
.dmode
: Modo directorio/carpeta de destino. Por ejemplo, 0755
.Aquí tienes algunos ejemplos de trabajo:
/etc/fix-attrs.d/01-mysql-data-dir
:
/var/lib/mysql true mysql 0600 0700
/etc/fix-attrs.d/02-mysql-log-dirs
:
/var/log/mysql-error-logs true nobody,32768:32768 0644 2700
/var/log/mysql-general-logs true nobody,32768:32768 0644 2700
/var/log/mysql-slow-query-logs true nobody,32768:32768 0644 2700
Aquí está la antigua forma de hacerlo:
Después de corregir los atributos (a través de /etc/fix-attrs.d/
) y antes de iniciar los servicios proporcionados por el usuario (a través de s6-rc o /etc/services.d
), nuestra superposición ejecutará todos los scripts que se encuentran en /etc/cont-init.d
, por ejemplo:
/etc/cont-init.d/02-confd-onetime
:
#!/command/execlineb -P
with-contenv
s6-envuidgid nginx
multisubstitute
{
import -u -D0 UID
import -u -D0 GID
import -u CONFD_PREFIX
define CONFD_CHECK_CMD "/usr/sbin/nginx -t -c {{ .src }}"
}
confd --onetime --prefix="${CONFD_PREFIX}" --tmpl-uid="${UID}" --tmpl-gid="${GID}" --tmpl-src="/etc/nginx/nginx.conf.tmpl" --tmpl-dest="/etc/nginx/nginx.conf" --tmpl-check-cmd="${CONFD_CHECK_CMD}" etcd
Esta forma todavía es compatible. Sin embargo, ahora existe una forma más genérica y eficiente de hacerlo: escribir las tareas de inicialización y finalización de una sola vez como servicios s6-rc, agregando directorios de definición de servicios en /etc/s6-overlay/s6-rc.d
, haciéndolos parte del paquete user
(para que en realidad se inicien cuando se inicia el contenedor) y hacer que dependan del paquete base
(para que solo se inicien después de base
).
Toda la información sobre s6-rc se puede encontrar aquí.
Cuando se inicia el contenedor, las operaciones se realizan en este orden:
/etc/fix-attrs.d
./etc/cont-init.d
se ejecutan secuencialmente.user
los inicia s6-rc, en un orden definido por dependencias. Los servicios pueden ser oneshots (tareas de inicialización) o longruns (demonios que se ejecutarán durante toda la vida útil del contenedor). Si los servicios dependen de base
, se garantiza que comenzarán en este punto y no antes; si no lo hacen, es posible que se hayan iniciado antes, lo que puede causar condiciones de carrera, por lo que se recomienda siempre hacer que dependan de base
./etc/services.d
.user2
con la dependencia correcta. (La mayoría de las personas no necesitan usar esto; si no está seguro, quédese con el paquete user
).Cuando se detiene el contenedor, ya sea porque el administrador envió un comando de detención o porque el CMD salió, las operaciones se realizan en orden inverso:
user2
con la dependencia correcta./etc/services.d
se detienen.down
en el directorio de definición de origen; así es como el s6-rc puede realizar tareas de finalización./etc/cont-finish.d
se ejecutan secuencialmente. El objetivo del paquete user2
es permitir que los servicios de usuario declarados en él se inicien después de los de /etc/services.d
; pero para poder hacerlo, cada servicio en user2
debe declarar una dependencia de legacy-services
. En otras palabras, para que una foobar
de servicio comience tarde, es necesario:
/etc/s6-overlay/s6-rc.d/foobar
como cualquier otro servicio s6-rc./etc/s6-overlay/s6-rc.d/foobar/dependencies.d/legacy-services
/etc/s6-overlay/s6-rc.d/user2/contents.d/foobar
. Eso asegurará que foobar
se inicie después de todo lo que esté en /etc/services.d
.
De forma predeterminada, los servicios creados en /etc/services.d
se reiniciarán automáticamente. Si un servicio derriba el contenedor, probablemente debería ejecutarlo como CMD; pero si prefiere ejecutarlo como un servicio supervisado, necesitará escribir un script finish
, que se ejecutará cuando el servicio esté inactivo; para detener el contenedor, se debe invocar el comando /run/s6/basedir/bin/halt
. Aquí hay un ejemplo de secuencia de comandos de finalización:
/etc/services.d/myapp/finish
:
#!/command/execlineb -S0
foreground { redirfd -w 1 /run/s6-linux-init-container-results/exitcode echo 0 }
/run/s6/basedir/bin/halt
La primera línea del script escribe 0
en el archivo /run/s6-linux-init-container-results/exitcode
. La segunda línea detiene el contenedor. Cuando detiene el contenedor mediante el comando /run/s6/basedir/bin/halt
ejecutado desde dentro del contenedor, se lee /run/s6-linux-init-container-results/exitcode
y su contenido se utiliza como código de salida para el comando docker run
que lanzó el contenedor. Si el archivo no existe, o si el contenedor se detiene con docker stop
u otro motivo, el código de salida tiene como valor predeterminado 0.
Es posible realizar operaciones más avanzadas en un script de finalización. Por ejemplo, aquí hay un script que solo cierra el servicio cuando sale de un valor distinto de cero:
/etc/services.d/myapp/finish
:
#!/command/execlineb -S1
if { eltest ${1} -ne 0 -a ${1} -ne 256 }
/run/s6/basedir/bin/halt
Tenga en cuenta que, en general, los scripts de finalización solo deben usarse para limpiezas locales después de que un demonio muere. Si un servicio es tan importante que el contenedor debe detenerse cuando muere, realmente recomendamos ejecutarlo como CMD.
Cada servicio puede tener su registrador dedicado. Un registrador es un servicio s6 que lee automáticamente desde la salida estándar de su servicio y registra los datos en un archivo rotado automáticamente en el lugar que desee. Tenga en cuenta que los demonios generalmente se registran en stderr, no en stdout, por lo que probablemente debería iniciar el script de ejecución de su servicio con exec 2>&1
en shell, o con fdmove -c 2 1
en execline, para poder capturar stderr .
s6-overlay proporciona una utilidad llamada logutil-service
que es un contenedor del programa s6-log
. Este ayudante hace lo siguiente:
S6_LOGGING_SCRIPT
nobody
(el valor predeterminado es 65534:65534
si no existe) Luego, s6-log se ejecutará para siempre, leerá los datos de su servicio y los escribirá en el directorio que especificó en logutil-service
.
Tenga en cuenta:
s6-setuidgid
nobody
puede escribirlonobody
puede escribir en la carpeta principal. Puede crear carpetas de registro en scripts cont-init.d
o como oneshots s6-rc. A continuación se muestra un ejemplo de un servicio registrado myapp
implementó a la antigua usanza:
/etc/cont-init.d/myapp-log-prepare
:
#! /bin/sh -e
mkdir -p /var/log/myapp
chown nobody:nogroup /var/log/myapp
chmod 02755 /var/log/myapp
/etc/services.d/myapp/run
:
#! /bin/sh
exec 2>&1
exec mydaemon-in-the-foreground-and-logging-to-stderr
/etc/services.d/myapp/log/run
:
#! /bin/sh
exec logutil-service /var/log/myapp
Y aquí está el mismo servicio, myapp, implementado en s6-rc.
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/dependencies.d/base
: archivo vacío
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/type
:
oneshot
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/up
:
if { mkdir -p /var/log/myapp }
if { chown nobody:nogroup /var/log/myapp }
chmod 02755 /var/log/myapp
(Comienzo de la sección detallada).
Entonces, los archivos up
y down
son especiales: no son scripts de shell, sino líneas de comando únicas interpretadas por execlineb. No debería tener que preocuparse por la ejecución; sólo debes recordar que un archivo up
contiene una única línea de comando. Entonces, si necesita un script con varias instrucciones, aquí le mostramos cómo hacerlo:
up
. Así es como procedería normalmente para escribir el archivo up
para myapp-log-prepare
:
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/up
:
/etc/s6-overlay/scripts/myapp-log-prepare
/etc/s6-overlay/scripts/myapp-log-prepare
: (debe ser ejecutable)
#! /bin/sh -e
mkdir -p /var/log/myapp
chown nobody:nogroup /var/log/myapp
chmod 02755 /var/log/myapp
La ubicación del script real es arbitraria, solo necesita coincidir con lo que estás escribiendo en el archivo up
.
Pero aquí, da la casualidad de que el script es lo suficientemente simple como para caber completamente en el archivo up
sin hacerlo demasiado complejo o difícil de entender. Por lo tanto, decidimos incluirlo como ejemplo para mostrar que hay más que puede hacer con up
archivos, si así lo desea. Puede leer la documentación completa del lenguaje execline aquí.
(Al final de la sección detallada, haga clic en el triángulo de arriba nuevamente para contraer).
/etc/s6-overlay/s6-rc.d/myapp/dependencies.d/base
: archivo vacío
/etc/s6-overlay/s6-rc.d/myapp-log/dependencies.d/myapp-log-prepare
: archivo vacío
/etc/s6-overlay/s6-rc.d/myapp/type
:
longrun
/etc/s6-overlay/s6-rc.d/myapp/run
:
#! /bin/sh
exec 2>&1
exec mydaemon-in-the-foreground-and-logging-to-stderr
/etc/s6-overlay/s6-rc.d/myapp/producer-for
:
myapp-log
/etc/s6-overlay/s6-rc.d/myapp-log/type
:
longrun
/etc/s6-overlay/s6-rc.d/myapp-log/run
:
#! /bin/sh
exec logutil-service /var/log/myapp
/etc/s6-overlay/s6-rc.d/myapp-log/consumer-for
:
myapp
/etc/s6-overlay/s6-rc.d/myapp-log/pipeline-name
:
myapp-pipeline
/etc/s6-overlay/s6-rc.d/user/contents.d/myapp-pipeline
: archivo vacío
¡Son muchos archivos! Un resumen de lo que significa todo esto es:
myapp | myapp-log
La canalización myapp | myapp-log
recibe un nombre, myapp-pipeline
, y este nombre se declara como parte del paquete user
, por lo que se iniciará cuando se inicie el contenedor.myapp-log-prepare
, myapp-log
y myapp
dependen del paquete base
, lo que significa que solo se iniciarán cuando el sistema esté realmente listo para iniciarlos. Realmente logra las mismas cosas que el método /etc/cont-init.d
más /etc/services.d
, pero es mucho más limpio en el fondo y puede manejar gráficos de dependencia mucho más complejos, por lo que siempre que tenga la oportunidad, le recomendamos se familiarice con la forma s6-rc de declarar sus servicios y sus registradores. La sintaxis completa de un directorio de definición de servicios, incluida la declaración de si su servicio es de larga duración o de una sola vez, la declaración de canalizaciones, la adición de tiempos de espera específicos del servicio si los necesita, etc., se puede encontrar aquí.
Cuando se trata de ejecutar un servicio, sin importar si es un servicio o un registrador, una buena práctica es eliminar privilegios antes de ejecutarlo. s6
ya incluye utilidades para hacer exactamente este tipo de cosas:
En execline
:
#!/command/execlineb -P
s6-setuidgid daemon
myservice
En sh
:
#! /bin/sh
exec s6-setuidgid daemon myservice
Si desea obtener más información sobre estas utilidades, consulte: s6-setuidgid
, s6-envuidgid
y s6-applyuidgid
.
Si desea que su script personalizado tenga entornos de contenedor disponibles: puede usar el asistente with-contenv
, que los insertará todos en su entorno de ejecución, por ejemplo:
/etc/cont-init.d/01-contenv-example
:
#! /command/with-contenv sh
env
Este script generará el contenido de su entorno de contenedor.
Las versiones recientes de Docker permiten ejecutar contenedores con un sistema de archivos raíz de solo lectura. Si su contenedor se encuentra en tal caso, debe configurar S6_READ_ONLY_ROOT=1
para informar a s6-overlay que no debe intentar escribir en ciertas áreas; en su lugar, realizará copias en un tmpfs montado en /run
.
Tenga en cuenta que s6-overlay supone que:
/run
existe y se puede escribir. Si no es así, intentará montar un tmpfs allí./var/run
es un enlace simbólico a /run
, por compatibilidad con versiones anteriores. Si no es así, lo hará. En general, la configuración predeterminada de la ventana acoplable ya debería proporcionar un tmpfs adecuado en /run
.
De alguna manera es posible modificar el comportamiento de s6-overlay proporcionando un conjunto ya predefinido de variables de entorno al contexto de ejecución:
PATH
(predeterminada = /command:/usr/bin:/bin
): esta es la RUTA predeterminada que tendrán todos los servicios en el contenedor, incluido el CMD. Establezca esta variable si tiene muchos servicios que dependen de archivos binarios almacenados en otro directorio, por ejemplo, /usr/sbin
. Tenga en cuenta que /command
, /usr/bin
y /bin
siempre se agregarán a esa ruta si aún no están en la que usted proporciona.S6_KEEP_ENV
(predeterminado = 0): si se establece, el entorno no se restablece y todo el árbol de supervisión ve el conjunto original de variables de entorno. Cambia with-contenv
a nop.S6_LOGGING
(predeterminado = 0):0
: envía todo a stdout/stderr.1
: Utiliza un registrador catch-all
interno y conserva todo lo que contiene, se encuentra en /var/log/s6-uncaught-logs
. Todo lo que se ejecuta como CMD
aún se envía a stdout/stderr.2
: Utiliza un catch-all
interno y conserva todo en él, incluida la salida de CMD
. No se escribe absolutamente nada en stdout/stderr.S6_CATCHALL_USER
(predeterminado = raíz): si está configurado, y si S6_LOGGING
es 1 o 2, entonces el registrador general se ejecuta como este usuario, que debe definirse en el /etc/passwd
de su imagen. Cada pequeña separación de privilegios ayuda un poco con la seguridad.S6_BEHAVIOUR_IF_STAGE2_FAILS
(predeterminado = 0): determina qué debe hacer el contenedor si falla uno de los scripts del servicio. Esto incluye:fix-attrs
/etc/cont-init.d
de estilo antiguo o de estilo nuevo s6-rc oneshot/etc/services.d
de estilo antiguo o s6-rc de larga duración de estilo nuevo está marcado como esperando notificación de preparación y no logra estar listo en el tiempo asignado (consulte S6_CMD_WAIT_FOR_SERVICES_MAXTIME
a continuación). Los valores válidos para S6_BEHAVIOUR_IF_STAGE2_FAILS
son los siguientes:0
: continúa en silencio incluso si falla un script.1
: Continuar pero avisar con un molesto mensaje de error.2
: Detener el contenedor.S6_KILL_FINISH_MAXTIME
(predeterminado = 5000): cuánto tiempo (en milisegundos) debe esperar el sistema, en el momento del apagado, para que un script en /etc/cont-finish.d
finalice naturalmente. Después de esta duración, al script se le enviará un SIGKILL. Tenga en cuenta que los scripts en /etc/cont.finish.d
se ejecutan secuencialmente y la secuencia de apagado potencialmente esperará S6_KILL_FINISH_MAXTIME
milisegundos para cada script.S6_SERVICES_READYTIME
(predeterminado = 50): con los servicios declarados en /etc/services.d
, existe una condición de carrera inevitable entre el momento en que se inician los servicios y el momento en que se puede probar su preparación. Para evitar esa carrera, dormimos un poco de tiempo, por defecto 50 milisegundos, antes de realizar la prueba de preparación. Si su máquina es lenta o está muy ocupada, puede recibir errores como s6-svwait: fatal: unable to s6_svstatus_read: No such file or directory
. En ese caso, debes aumentar el tiempo de sueño, declarándolo (en milisegundos) en la variable S6_SERVICES_READYTIME
. Tenga en cuenta que solo se refiere a /etc/services.d
; s6-rc es inmune a la condición de carrera.S6_SERVICES_GRACETIME
(predeterminado = 3000): cuánto tiempo (en milisegundos) debe esperar s6
, en el momento del apagado, para que los servicios declarados en /etc/services.d
mueran antes de continuar con el resto del apagado.S6_KILL_GRACETIME
(predeterminado = 3000): cuánto tiempo (en milisegundos) debe esperar s6
, al final del procedimiento de apagado cuando todos los procesos hayan recibido una señal TERM, para que mueran antes de enviar una señal KILL
para asegurarse de que estén muertos. .S6_LOGGING_SCRIPT
(predeterminado = "n20 s1000000 T"): este entorno decide qué registrar y cómo, de forma predeterminada, cada línea antepondrá ISO8601, se rotará cuando el archivo de registro actual alcance 1 MB y se archivará, como máximo, con 20 archivos.S6_CMD_ARG0
(predeterminado = no establecido): el valor de esta var env se antepondrá a cualquier argumento CMD
pasado por Docker. Úselo si está migrando una imagen existente a s6-overlay y desea convertirla en un reemplazo directo: establecer esta variable en el valor de un ENTRYPOINT utilizado anteriormente le ayudará en la transición.S6_CMD_USE_TERMINAL
(predeterminado = 0): establezca este valor en 1 si tiene un CMD que necesita un terminal para su salida (normalmente cuando ejecuta su contenedor con docker run -it
) y ha configurado S6_LOGGING
en un valor distinto de cero. Esta configuración hará que su CMD realmente salga a su terminal; el inconveniente es que su salida no se registrará. De forma predeterminada (cuando esta variable es 0 o no está configurada), stdout y stderr de su CMD se registran cuando S6_LOGGING
es distinto de cero, lo que significa que van a una tubería incluso si lo está ejecutando en una terminal interactiva.S6_FIX_ATTRS_HIDDEN
(predeterminado = 0): controla cómo los scripts fix-attrs.d
procesan archivos y directorios.0
: Se excluyen los archivos y directorios ocultos.1
: Se procesan todos los archivos y directorios.S6_CMD_WAIT_FOR_SERVICES
(predeterminado = 0): de forma predeterminada, cuando se inicia el contenedor, se iniciarán los servicios en /etc/services.d
y la ejecución procederá a iniciar el paquete user2
y el CMD, si alguno de estos está definido. Sin embargo, si S6_CMD_WAIT_FOR_SERVICES
no es cero, la secuencia de inicio del contenedor esperará hasta que los servicios en /etc/services.d
estén listos antes de continuar con el resto de la secuencia. Tenga en cuenta que esto solo es significativo si los servicios en /etc/services.d
notifican su preparación a S6.S6_CMD_WAIT_FOR_SERVICES_MAXTIME
(default = 0, es decir, infinito): el tiempo máximo (en milisegundos) los servicios podrían tomar para mencionar antes de procedir a la ejecución de CMD. Establezca esta variable en un valor positivo si tiene servicios que potencialmente pueden bloquear indefinidamente y prefiere que el contenedor falle si no todo está arriba después de un tiempo determinado. Tenga en cuenta que este valor también incluye el tiempo configurando la inicialización del contenedor heredado ( /etc/cont-init.d
) y los servicios ( /etc/services.d
), así que tenga en cuenta eso al calcular un valor adecuado. En versiones de S6-Overlay hasta 3.1.6.2, el valor predeterminado fue de 5000 (cinco segundos), pero causó más fallas de contenedores no deseadas de las cuales resueltos, por lo que ahora no hay tiempo de espera de forma predeterminada: S6-Overlay esperará tanto tiempo como sea necesario para que se publiquen todos los servicios.S6_READ_ONLY_ROOT
(default = 0): cuando se ejecute en un contenedor cuyo sistema de archivos raíz sea de solo lectura, configure este env en 1 para informar la etapa 2 de inicio que debe copiar scripts de inicialización proporcionados por el usuario de /etc
a /run/s6/etc
antes Intenta cambiar los permisos, etc. Consulte el sistema de archivos raíz de solo lectura para obtener más información.S6_SYNC_DISKS
(default = 0): configure este env en 1 para informar la etapa 3 de init que debería intentar sincronizar sistemas de archivos antes de detener el contenedor. Nota: Esto probablemente sincronizará todos los sistemas de archivos en el host.S6_STAGE2_HOOK
(default = None): si esta variable existe, su contenido se interpretará como un extracto de shell que se ejecutará en la etapa inicial 2, antes de que se inicien los servicios. Esto se puede usar, por ejemplo, para parchear dinámicamente la base de datos del servicio en tiempo de ejecución justo antes de que se compilue y ejecute. El valor incorrecto puede evitar que su contenedor ejecute o ponga en peligro su seguridad, así que solo use esto si sabe exactamente lo que está haciendo. En caso de duda, deje esta variable indefinida.S6_VERBOSITY
(predeterminado = 2): controla la verbosidad de S6-RC y potencialmente otras herramientas, en el tiempo de inicio y detención del contenedor. El valor predeterminado, 2, es normalmente verboso: enumerará las operaciones de inicio y detención del servicio. Puede hacer que el contenedor sea más tranquilo disminuyendo este número: 1 solo imprimirá advertencias y errores, y 0 solo imprimirá errores. También puede hacer que el contenedor sea más detallado, es decir, el rastreo de impresión y la información de depuración, aumentando este número hasta 5, pero la salida se volverá muy ruidosa, y la mayoría de las personas no deberían necesitar esto.S6_CMD_RECEIVE_SIGNALS
(predeterminado = 0): decide si las señales enviadas al contenedor deben enviarse al PID 1 del contenedor o al CMD. Por defecto, cuando realiza, por ejemplo, una docker stop
, se enviará una señal de término al PID 1 del contenedor, que activará la secuencia completa de apagado del contenedor, pero si hay un CMD presente, estará entre los últimos procesos que se matarán , solo cuando todo lo demás está inactivo y el contenedor está a punto de salir. Si esta variable es de 1 o más, las señales se desvían del PID 1 al CMD, lo que significa que docker stop
enviará un siglo a la CMD, y el contenedor solo activará su procedimiento de cierre cuando el CMD esté muerto. Tenga en cuenta que solo Sigterm, Sigquit, Sigint, Sigusr1, Sigusr2, Sigpwr y Sigwinch se desvían; Otras señales se ignoran o no pueden ser desviadas y son necesariamente manejadas por el PID 1. Tenga en cuenta que usar esta opción puede evitar que los CMD interactivos funcionen en absoluto; en otras palabras, si está ejecutando un CMD interactivo en una terminal, Don 'T establecer esta variable; Pero eso debería estar bien ya que en este caso ya tiene formas interactivas de detener su CMD. Si el software que se ejecuta en su contenedor requiere syslog, extraiga el syslogd-overlay-noarch.tar.xz
tarball: eso le dará una pequeña emulación de syslogd. Los registros se encontrarán en varios subdirectorios de /var/log/syslogd
, por ejemplo, los mensajes se encontrarán en /var/log/syslogd/messages/
directorio, los últimos registros están disponibles en /var/log/syslogd/messages/current