Оглавление
CMD
s6-overlay — это простой в установке (просто извлеките один или два архива!) набор скриптов и утилит, позволяющий использовать существующие образы Docker, одновременно используя s6 в качестве pid 1 для вашего контейнера и супервизора процессов для ваших сервисов.
Создайте следующий файл Dockerfile и попробуйте его:
# 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
Если вы переходите с предыдущей версии s6-overlay ( v2 ) на новую версию ( v3 ), вам может потребоваться внести некоторые изменения в свои службы или способ использования s6-overlay, чтобы все работало гладко. В этом документе делается попытка дать точное описание того, как работает версия 3, но у нас есть отдельная страница, на которой перечислены основные различия и вещи, которые вы, вероятно, заметите. Пожалуйста, прочитайте это, если вы находитесь в такой ситуации!
Проект преследует следующие цели:
cont-init.d
), финализация ( cont-finish.d
) и свои собственные службы с зависимостями между ними.PID 1
s6
и s6-portable-utils
. Они включают в себя удобные и компонуемые утилиты, которые делают нашу жизнь намного проще.logutil-service
, который использует s6-log
под капотом.USER
Docker для запуска всего дерева процессов от имени конкретного пользователя. Совместимо не со всеми функциями, подробности в разделе примечаний. Одна из часто повторяемых мантр Docker — «один процесс на контейнер», но мы с этим не согласны. Нет ничего плохого в запуске нескольких процессов в контейнере. Наша политика — более абстрактная «одна вещь на контейнер» — контейнер должен делать что-то одно, например «запускать чат-сервис» или «запускать gitlab». Это может включать несколько процессов, и это нормально.
Другая причина, по которой авторы изображений избегают супервайзеров процессов, заключается в том, что они считают, что супервизор процессов должен перезапустить отказавшие сервисы, а это означает, что контейнер Docker никогда не умрет.
Это фактически нарушает экосистему Docker — большинство образов запускают один процесс, который завершается в случае ошибки. Выходя при ошибке, вы позволяете системному администратору обрабатывать сбои так, как он предпочитает. Если ваш образ никогда не выйдет из строя, теперь вам нужен альтернативный метод восстановления ошибок и уведомления о сбоях.
Наша политика такова: если «вещь» выходит из строя, то и контейнер тоже должен выйти из строя. Мы делаем это, определяя, какие процессы могут перезапуститься, а какие должны отключить контейнер. Например, в случае сбоя cron
или syslog
ваш контейнер, скорее всего, сможет перезапустить его без каких-либо вредных последствий, но если ejabberd
завершится сбоем, контейнер должен завершить работу, чтобы системный администратор мог принять меры.
Наша интерпретация «Пути Docker» такова:
и наша система инициализации предназначена именно для этого. Ваши изображения будут вести себя как другие изображения Docker и вписываться в существующую экосистему изображений.
Подробную информацию об остановке «этой штуки» см. в разделе «Написание дополнительного сценария завершения» в разделе «Использование».
Наш оверлейный инициализатор правильно настроен для правильной работы в контейнерных средах. В этом разделе кратко объясняется, как работают этапы, но если вы хотите узнать, как должна работать полная система инициализации, вы можете прочитать эту статью: Как запустить s6-svscan как процесс 1.
/etc/cont-init.d
./etc/s6-overlay/s6-rc.d
, следуя зависимостям./etc/services.d
) во временный каталог и попросите s6 запустить (и контролировать) их./etc/cont-finish.d
.TERM
. В любом случае оставшихся процессов быть не должно.KILL
. Затем контейнер выходит. s6-overlay представляет собой набор архивов, которые вы можете извлечь в свое изображение. Нужные вам архивы зависят от используемого вами изображения; большинству людей понадобятся первые два, а остальные — дополнительные, которые вы можете использовать по своему усмотрению.
s6-overlay-noarch.tar.xz
: этот архив содержит сценарии, реализующие наложение. Мы называем его «noarch», потому что он не зависит от архитектуры: он содержит только сценарии и другие текстовые файлы. Каждому, кто хочет запустить s6-overlay, необходимо распаковать этот архив.s6-overlay-x86_64.tar.xz
: замените x86_64
архитектурой вашей системы. Этот архив содержит все необходимые двоичные файлы из экосистемы s6, все они связаны статически и не мешают двоичным файлам вашего образа. Если вы точно не уверены, что ваш образ уже содержит все пакеты, содержащие двоичные файлы, используемые в наложении, вам необходимо извлечь этот архив.s6-overlay-symlinks-noarch.tar.xz
: этот архив содержит символические ссылки на сценарии s6-overlay, поэтому они доступны через /usr/bin
. Обычно в этом нет необходимости, все сценарии доступны через переменную среды PATH, но если у вас есть старые пользовательские сценарии, содержащие шебанги, такие как #!/usr/bin/with-contenv
, установка этих символических ссылок заставит их работать.s6-overlay-symlinks-arch.tar.xz
: этот архив содержит символические ссылки на двоичные файлы из экосистемы s6, предоставленные вторым архивом, чтобы сделать их доступными через /usr/bin
. Обычно это не требуется, но если у вас есть старые пользовательские скрипты, содержащие шебанги, такие как #!/usr/bin/execlineb
, установка этих символических ссылок заставит их работать.syslogd-overlay-noarch.tar.xz
: этот архив содержит определения службы syslogd
. Если вы используете демоны, которые не могут выполнять вход в поток stderr, чтобы воспользоваться преимуществами инфраструктуры журналирования s6, но жестко запрограммировали использование старого механизма syslog()
, вы можете извлечь этот архив, и ваш контейнер запустит облегченную эмуляцию демона syslogd
, поэтому ваши журналы системного журнала будут собраны и сохранены на диске.Чтобы установить эти архивы, добавьте в Dockerfile строки, соответствующие функциям, которые вы хотите установить. Например, большинство людей будут использовать следующее:
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
Обязательно сохраните права доступа к файлу при извлечении (т. е. используйте опцию -p
для tar
.)
Проект распространяется в виде набора стандартных файлов .tar.xz, которые вы извлекаете в корень вашего образа. (Вам понадобится пакет xz-utils для tar
, чтобы понимать файлы .tar.xz
; он доступен в каждом дистрибутиве, но не всегда в образах контейнеров по умолчанию, поэтому вам может потребоваться apt install xz-utils
или apk add xz
, или эквивалент, прежде чем вы сможете расширить архивы.)
После этого установите для ENTRYPOINT
значение /init
.
Прямо сейчас мы рекомендуем использовать директиву ADD
Docker вместо запуска wget
или curl
в директиве RUN
— Docker может обрабатывать URL-адрес https, когда вы используете ADD
, тогда как ваш базовый образ может не иметь возможности использовать https или даже не иметь его. wget
или curl
вообще установлены.
Отсюда у вас есть несколько вариантов:
CMD
вашего изображения.CMD
Использование CMD
— удобный способ воспользоваться преимуществами наложения. Ваш CMD
может быть указан во время сборки в Dockerfile или во время выполнения в командной строке, в любом случае это нормально. Он будет запущен как обычный процесс в среде, настроенной s6; в случае сбоя или выхода контейнер полностью отключится и выйдет. Вы можете запускать интерактивные программы таким образом: только CMD получит вашу интерактивную команду, процессы поддержки не будут затронуты.
Например:
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 $
Другой способ использовать контейнер с s6-overlay — сделать ваши сервисы контролируемыми. Вы можете контролировать любое количество услуг; обычно это просто службы поддержки для основного демона, который вы запускаете как CMD, но если вы этого хотите, ничто не мешает вам иметь пустой CMD и запускать основной демон в качестве контролируемой службы. В этом случае демон будет перезапущен s6 при каждом выходе; контейнер остановится только тогда, когда вы прикажете ему это сделать, либо с помощью команды docker stop
, либо изнутри контейнера с помощью команды /run/s6/basedir/bin/halt
.
Существует два способа создания контролируемого сервиса. Старый способ, который все еще поддерживается, — создать служебный каталог «чистого s6». Создайте каталог с именем вашего сервиса в /etc/services.d
и поместите в него исполняемый файл run
; это файл, в который вы поместите выполнение долгоживущего процесса. Для получения подробной информации о контроле над служебными каталогами и о том, как настроить, как s6 обрабатывает ваш демон, вы можете просмотреть документацию servicedir. Простой пример будет выглядеть так:
/etc/services.d/myapp/run
:
#!/command/execlineb -P
nginx -g "daemon off;"
Новый способ — создать каталог определения источника s6-rc в каталоге /etc/s6-overlay/s6-rc.d
и добавить имя этого каталога в user
пакет, т. е. создать пустой файл с тем же именем. в каталоге /etc/s6-overlay/s6-rc.d/user/contents.d
. Формат каталога определения источника описан на этой странице. Обратите внимание, что вы можете определить longruns , то есть демоны, которые будут контролироваться s6, как и в случае с методом /etc/services.d
, а также oneshots , то есть программы, которые будут запускаться один раз и завершаться. Ваш основной сервис, вероятно, долгосрочный , а не одноразовый : вам, вероятно, понадобится демон, который будет постоянно работать.
Преимущество этого нового формата в том, что он позволяет определять зависимости между сервисами: если B зависит от A , то A запустится первым, затем B запустится, когда A будет готов, и когда контейнеру будет приказано выйти, B остановится. сначала, затем А. Если у вас сложная архитектура, в которой различные процессы зависят друг от друга или вам просто приходится смешивать однократные и долгосрочные проекты в точном порядке, это может подойти вам.
Пример выше можно было бы переписать следующим образом:
/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
: пустой файл. (Это добавляет myapp
к набору служб, которые s6-rc запустит при загрузке контейнера.)
/etc/s6-overlay/s6-rc.d/myapp/dependencies.d/base
: пустой файл. (Это указывает s6-rc запускать myapp
только тогда, когда все базовые службы готовы: это предотвращает условия гонки.)
Мы рекомендуем вам перейти на новый формат, но если вам не нужны его преимущества, вы можете использовать обычные каталоги служб в /etc/services.d
, это будет работать так же хорошо.
Если вы запускаете свою основную службу как CMD, вам нечего делать: когда ваш CMD завершает работу или когда вы запускаете docker stop
, контейнер естественным образом завершает работу с тем же кодом завершения, что и ваша служба. (Однако имейте в виду, что в случае docker stop
ваша служба получит SIGTERM, и в этом случае код выхода будет полностью зависеть от того, как ваша служба его обрабатывает - он может перехватить его и выйти из 0, перехватить его и выйти из чего-то еще. , или не перехватывать его и позволить оболочке завершить для него собственный код — обычно 130.)
Однако если вы запускаете свою основную службу как контролируемую службу, все происходит по-другому, и вам нужно указать контейнеру, с каким кодом следует выйти, когда вы отправляете ему команду docker stop
. Для этого вам нужно написать скрипт finish
:
/etc/services.d
, вам понадобится исполняемый скрипт /etc/services.d/myapp/finish
./etc/s6-overlay/s6-rc.d/myapp/finish
содержащий ваш скрипт (файл может быть исполняемым, а может и не быть). Этот сценарий finish
будет запущен при выходе из службы и будет принимать два аргумента:
В finish
скрипте нужно прописать нужный вам код выхода контейнера в файл /run/s6-linux-init-container-results/exitcode
— и всё.
Например, сценарий finish
для приведенной выше службы myapp
может быть примерно таким:
#! /bin/sh
if test " $1 " -eq 256 ; then
e= $(( 128 + $2 ))
else
e= " $1 "
fi
echo " $e " > /run/s6-linux-init-container-results/exitcode
Когда вы отправляете команду docker stop
в свой контейнер, служба myapp
будет завершена и будет запущен этот скрипт; он запишет либо код завершения myapp
(если myapp
улавливает сигнал TERM), либо 130 (если myapp
не улавливает сигнал TERM) в специальный файл /run/s6-linux-init-container-results/exitcode
, который будет быть прочитано s6-overlay в конце процедуры выключения контейнера, и ваш контейнер выйдет с этим значением.
В этом разделе описываются функциональные возможности версий s6-overlay, предшествующих v3. fix-attrs все еще поддерживается в версии 3, но считается устаревшим по нескольким причинам: одна из них заключается в том, что динамическая смена владельца обычно не является хорошей политикой, когда это можно сделать статически. Другая причина в том, что он не работает с контейнерами USER. Вместо fix-attrs мы теперь рекомендуем вам позаботиться о правах собственности и разрешениях на монтирование хоста в автономном режиме, прежде чем запускать контейнер . Это следует сделать в вашем Dockerfile, когда у вас есть вся необходимая информация.
Тем не менее, вот то, что мы написали для предыдущих версий, и это применимо и сегодня (но, пожалуйста, перестаньте зависеть от этого):
Иногда интересно исправить права собственности и разрешения, прежде чем продолжить, потому что, например, вы смонтировали/сопоставили папку хоста внутри своего контейнера. Наше наложение позволяет решить эту проблему с помощью файлов в /etc/fix-attrs.d
. Это формат шаблона, за которым следуют файлы fix-attrs:
path recurse account fmode dmode
path
: путь к файлу или каталогу.recurse
: (установите значение true
или false
). Если папка найдена, выполните рекурсивный просмотр всех содержащихся в ней файлов и папок.account
: Целевая учетная запись. По умолчанию можно использовать резервный uid:gid
если учетная запись не найдена. Например, nobody,32768:32768
сначала попытается использовать учетную запись nobody
, а затем вместо этого вернется к uid 32768
. Если, например, учетная запись daemon
имеет UID=2
и GID=2
, это возможные значения для поля 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
: режим целевого файла. Например, 0644
.dmode
: режим целевого каталога/папки. Например, 0755
.Вот несколько рабочих примеров:
/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
Вот старый способ сделать это:
После исправления атрибутов (через /etc/fix-attrs.d/
) и перед запуском пользовательских сервисов (через s6-rc или /etc/services.d
) наш оверлей выполнит все скрипты, найденные в /etc/cont-init.d
, например:
/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
Этот способ все еще поддерживается. Однако теперь есть более общий и эффективный способ сделать это: записать свои одноразовые задачи инициализации и финализации в виде сервисов s6-rc, добавив каталоги определения сервисов в /etc/s6-overlay/s6-rc.d
, сделав их частью user
пакета (поэтому они фактически запускаются при загрузке контейнера) и делают их зависимыми от base
пакета (чтобы они запускались только после base
).
Всю информацию о s6-rc можно найти здесь.
При запуске контейнера операции выполняются в таком порядке:
/etc/fix-attrs.d
./etc/cont-init.d
выполняются последовательно.user
пакете запускаются s6-rc в порядке, определяемом зависимостями. Службы могут быть одноразовыми (задачи инициализации) или длинными (демонами, которые будут работать на протяжении всего срока службы контейнера). Если службы зависят от base
, они гарантированно запустятся в этот момент, а не раньше; в противном случае они могли быть запущены раньше, что может вызвать состояние гонки, поэтому рекомендуется всегда делать их зависимыми от base
./etc/services.d
.user2
с правильной зависимостью запускаются. (Большинству людей это не обязательно использовать; если вы не уверены, придерживайтесь user
пакета.)Когда контейнер остановлен, либо из-за того, что администратор отправил команду остановки, либо из-за выхода из CMD, операции выполняются в обратном порядке:
user2
с правильной зависимостью остановлены./etc/services.d
остановлены.down
в каталоге определения источника; именно так s6-rc может выполнять задачи финализации./etc/cont-finish.d
выполняются последовательно. Цель пакета user2
— разрешить запуск пользовательских служб, объявленных в нем, после служб /etc/services.d
; но для этого каждая служба в user2
должна объявить зависимость от legacy-services
. Другими словами, чтобы сервис foobar
запускался поздно, нужно:
/etc/s6-overlay/s6-rc.d/foobar
как и любой другой сервис s6-rc./etc/s6-overlay/s6-rc.d/foobar/dependencies.d/legacy-services
/etc/s6-overlay/s6-rc.d/user2/contents.d/foobar
. Это гарантирует, что foobar
запустится после всего, что находится в /etc/services.d
.
По умолчанию службы, созданные в /etc/services.d
автоматически перезапускаются. Если служба должна отключить контейнер, вам, вероятно, следует запустить ее как CMD; но если вы предпочитаете запускать его как контролируемую службу, вам нужно будет написать сценарий finish
, который будет запускаться, когда служба не работает; чтобы остановить контейнер, необходимо вызвать команду /run/s6/basedir/bin/halt
. Вот пример скрипта завершения:
/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
Первая строка сценария записывает 0
в файл /run/s6-linux-init-container-results/exitcode
. Вторая строка останавливает контейнер. Когда вы останавливаете контейнер с помощью команды /run/s6/basedir/bin/halt
, запускаемой изнутри контейнера, считывается /run/s6-linux-init-container-results/exitcode
, и его содержимое используется в качестве кода выхода для команда docker run
, которая запустила контейнер. Если файл не существует или контейнер остановлен из-за docker stop
или по другой причине, этот код выхода по умолчанию равен 0.
В сценарии завершения можно выполнять более сложные операции. Например, вот скрипт, который отключает службу только при выходе из ненулевого состояния:
/etc/services.d/myapp/finish
:
#!/command/execlineb -S1
if { eltest ${1} -ne 0 -a ${1} -ne 256 }
/run/s6/basedir/bin/halt
Обратите внимание, что в целом сценарии завершения следует использовать только для локальной очистки после смерти демона. Если служба настолько важна, что контейнер должен останавливаться после ее выхода из строя, мы настоятельно рекомендуем запускать ее как CMD.
У каждого сервиса может быть свой специальный регистратор. Регистратор — это служба s6, которая автоматически считывает стандартный вывод вашей службы и записывает данные в автоматически вращаемый файл в нужном вам месте. Обратите внимание, что демоны обычно регистрируются на stderr, а не на stdout, поэтому вам, вероятно, следует запустить сценарий запуска вашей службы с помощью exec 2>&1
в оболочке или с fdmove -c 2 1
в execline, чтобы перехватить stderr .
s6-overlay предоставляет утилиту logutil-service
, которая является оболочкой программы s6-log
. Этот помощник делает следующее:
S6_LOGGING_SCRIPT
nobody
(по умолчанию 65534:65534
если он не существует) s6-log будет работать вечно, считывая данные из вашего сервиса и записывая их в каталог, указанный вами в logutil-service
.
Пожалуйста, обрати внимание:
s6-setuidgid
nobody
из пользователейnobody
. Вы можете создавать папки журналов в сценариях cont-init.d
или в виде снимков s6-rc. Вот пример зарегистрированного сервиса myapp
реализованного старым способом:
/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
А вот тот же сервис myapp, реализованный в s6-rc.
/etc/s6-overlay/s6-rc.d/myapp-log-prepare/dependencies.d/base
: пустой файл
/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
(Начало подробного раздела.)
Итак, файлы up
и down
особенные: это не сценарии оболочки, а отдельные командные строки, интерпретируемые execlineb. Вам не придется беспокоиться об эксеклайне; вам следует только помнить, что файл up
содержит одну командную строку. Итак, если вам нужен скрипт с несколькими инструкциями, вот как это сделать:
up
. Вот как вы обычно пишете файл up
для 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
: (должен быть исполняемым)
#! /bin/sh -e
mkdir -p /var/log/myapp
chown nobody:nogroup /var/log/myapp
chmod 02755 /var/log/myapp
Местоположение фактического скрипта произвольное, оно просто должно совпадать с тем, что вы пишете в файле up
.
Но здесь так уж получилось, что сценарий достаточно прост и может полностью поместиться в файл up
, не делая его слишком сложным или трудным для понимания. Итак, мы решили включить его в качестве примера, чтобы показать, что с файлами up
можно сделать больше, если вы того желаете. Полную документацию по языку execline можно прочитать здесь.
(Конец подробного раздела. Еще раз щелкните треугольник выше, чтобы свернуть его.)
/etc/s6-overlay/s6-rc.d/myapp/dependencies.d/base
: пустой файл
/etc/s6-overlay/s6-rc.d/myapp-log/dependencies.d/myapp-log-prepare
: пустой файл
/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
: пустой файл
Это много файлов! Краткое изложение того, что все это означает:
myapp | myapp-log
Конвейеру myapp | myapp-log
присвоено имя myapp-pipeline
, и это имя объявлено как часть user
пакета, поэтому оно будет запущено при запуске контейнера.myapp-log-prepare
, myapp-log
и myapp
зависят от base
пакета, что означает, что они будут запущены только тогда, когда система действительно будет готова к их запуску. На самом деле он выполняет те же задачи, что и метод /etc/cont-init.d
плюс метод /etc/services.d
, но внутри он намного чище и может обрабатывать гораздо более сложные графы зависимостей, поэтому всякий раз, когда у вас появляется такая возможность, мы рекомендуем вы ознакомитесь со способом объявления своих сервисов и регистраторов в s6-rc. Полный синтаксис каталога определения службы, включая объявление о том, является ли ваша служба долгосрочной или одноразовой, объявление конвейеров, добавление таймаутов для конкретной службы, если они вам нужны, и т. д., можно найти здесь.
Когда дело доходит до выполнения службы, независимо от того, служба это или средство ведения журнала, хорошей практикой является отказ от привилегий перед ее выполнением. s6
уже включает в себя утилиты для выполнения именно таких действий:
В execline
:
#!/command/execlineb -P
s6-setuidgid daemon
myservice
В sh
:
#! /bin/sh
exec s6-setuidgid daemon myservice
Если вы хотите узнать больше об этих утилитах, ознакомьтесь с: s6-setuidgid
, s6-envuidgid
и s6-applyuidgid
.
Если вы хотите, чтобы в вашем пользовательском сценарии были доступны контейнерные среды: вы можете использовать помощник with-contenv
, который перенесет все это в вашу среду выполнения, например:
/etc/cont-init.d/01-contenv-example
:
#! /command/with-contenv sh
env
Этот скрипт выведет содержимое вашей контейнерной среды.
Последние версии Docker позволяют запускать контейнеры с корневой файловой системой, доступной только для чтения. Если ваш контейнер находится в таком случае, вам следует установить S6_READ_ONLY_ROOT=1
, чтобы сообщить s6-overlay, что он не должен пытаться записывать в определенные области — вместо этого он будет выполнять копии в tmpfs, смонтированный в /run
.
Обратите внимание, что s6-overlay предполагает, что:
/run
существует и доступен для записи. Если это не так, он попытается смонтировать туда tmpfs./var/run
— символическая ссылка на /run
для совместимости с предыдущими версиями. Если это не так, то оно так и сделает. В общем, ваши настройки докера по умолчанию уже должны обеспечивать подходящий tmpfs в /run
.
Можно каким-то образом настроить поведение s6-overlay, предоставив уже предопределенный набор переменных среды в контекст выполнения:
PATH
(по умолчанию = /command:/usr/bin:/bin
): это PATH по умолчанию, который будет иметь все службы в контейнере, включая CMD. Установите эту переменную, если у вас много служб, которые зависят от двоичных файлов, хранящихся в другом каталоге, например /usr/sbin
. Обратите внимание, что /command
, /usr/bin
и /bin
всегда будут добавляться к этому пути, если они еще не находятся в том, который вы указали.S6_KEEP_ENV
(по умолчанию = 0): если установлено, то среда не сбрасывается, и все дерево контроля видит исходный набор переменных окружения. Он переключается with-contenv
на no.S6_LOGGING
(по умолчанию = 0):0
: выводит все на стандартный вывод/stderr.1
: использует внутренний catch-all
регистратор и сохраняет в нем все, он находится в /var/log/s6-uncaught-logs
. Все, что выполняется как CMD
, по-прежнему выводится на стандартный вывод/stderr.2
: использует внутренний catch-all
регистратор и сохраняет в нем все, включая выходные данные CMD
. В stdout/stderr абсолютно ничего не записывается.S6_CATCHALL_USER
(по умолчанию = root): если установлен, и если S6_LOGGING
равен 1 или 2, то универсальный регистратор запускается от имени этого пользователя, который должен быть определен в файле /etc/passwd
вашего образа. Каждое разделение привилегий немного помогает в обеспечении безопасности.S6_BEHAVIOUR_IF_STAGE2_FAILS
(по умолчанию = 0): определяет, что должен делать контейнер в случае сбоя одного из сценариев службы. Это включает в себя:fix-attrs
/etc/cont-init.d
старого стиля или нового стиля s6-rc не удался/etc/services.d
-rc старого стиля или s6-rc нового стиля помечен как ожидающий уведомления о готовности и не может быть готов в течение отведенного времени (см. S6_CMD_WAIT_FOR_SERVICES_MAXTIME
ниже). Допустимые значения для S6_BEHAVIOUR_IF_STAGE2_FAILS
следующие:0
: Продолжать тихо, даже если сценарий завершился неудачно.1
: Продолжить, но выдать раздражающее сообщение об ошибке.2
: Остановить контейнер.S6_KILL_FINISH_MAXTIME
(по умолчанию = 5000): Как долго (в миллисекундах) система должна ждать во время завершения работы сценария в /etc/cont-finish.d
для естественного завершения. По истечении этого времени скрипту будет отправлен SIGKILL. Имейте в виду, что сценарии в /etc/cont.finish.d
выполняются последовательно, и последовательность завершения работы потенциально будет ожидать миллисекунд S6_KILL_FINISH_MAXTIME
для каждого сценария.S6_SERVICES_READYTIME
(по умолчанию = 50): для служб, объявленных в /etc/services.d
, существует неизбежная ситуация гонки между моментом запуска служб и моментом, когда их можно проверить на готовность. Чтобы избежать этой гонки, мы немного спим, по умолчанию 50 миллисекунд, прежде чем проверять готовность. Если ваша машина работает медленно или очень занята, вы можете получить ошибки, похожие на s6-svwait: fatal: unable to s6_svstatus_read: No such file or directory
. В этом случае вам следует увеличить время ожидания, объявив его (в миллисекундах) в переменной S6_SERVICES_READYTIME
. Обратите внимание, что это касается только /etc/services.d
; s6-rc невосприимчив к состоянию гонки.S6_SERVICES_GRACETIME
(по умолчанию = 3000): Как долго (в миллисекундах) s6
должен ждать во время завершения работы служб, объявленных в /etc/services.d
, прежде чем продолжить остальную часть завершения работы.S6_KILL_GRACETIME
(по умолчанию = 3000): Как долго (в миллисекундах) s6
должен ждать в конце процедуры завершения работы, когда все процессы получили сигнал TERM, чтобы они умерли, прежде чем отправлять сигнал KILL
, чтобы убедиться, что они мертвы. .S6_LOGGING_SCRIPT
(по умолчанию = «n20 s1000000 T»): этот env решает, что и как регистрировать, по умолчанию каждая строка будет добавляться к ISO8601, чередоваться, когда текущий файл журнала достигает 1 МБ, и архивироваться максимум с 20 файлами.S6_CMD_ARG0
(по умолчанию = не установлено): значение этой переменной env будет добавлено к любым аргументам CMD
передаваемым докером. Используйте его, если вы переносите существующее изображение в s6-overlay и хотите сделать его заменой: установка этой переменной значения ранее использованного ENTRYPOINT поможет вам осуществить переход.S6_CMD_USE_TERMINAL
(по умолчанию = 0): установите это значение равным 1, если у вас есть CMD, которому нужен терминал для вывода (обычно, когда вы запускаете контейнер с помощью docker run -it
), и вы установили для S6_LOGGING
ненулевое значение. Этот параметр позволит вашему CMD фактически выводиться на ваш терминал; недостатком является то, что его вывод не будет протоколироваться. По умолчанию (когда эта переменная равна 0 или не установлена) стандартный вывод и стандартный вывод вашего CMD регистрируются, когда S6_LOGGING
не равно нулю, что означает, что они передаются в канал, даже если вы запускаете его в интерактивном терминале.S6_FIX_ATTRS_HIDDEN
(по умолчанию = 0): управляет тем, как сценарии fix-attrs.d
обрабатывают файлы и каталоги.0
: Скрытые файлы и каталоги исключаются.1
: Обрабатываются все файлы и каталоги.S6_CMD_WAIT_FOR_SERVICES
(по умолчанию = 0): по умолчанию при запуске контейнера запускаются службы в /etc/services.d
, и выполнение переходит к запуску пакета user2
и CMD, если какой-либо из них определен. Однако, если S6_CMD_WAIT_FOR_SERVICES
, однако, начальная последовательность контейнера будет ждать, пока службы в /etc/services.d
будут готовы , прежде чем продолжить оставшуюся часть последовательности. Обратите внимание, что это важно только в том случае, если услуги в /etc/services.d
уведомит их готовность к S6.S6_CMD_WAIT_FOR_SERVICES_MAXTIME
(default = 0, то есть Infinite): максимальное время (в миллисекундах), которые Услуги могли бы взять на себя, чтобы поднять перед процедурой выполнения CMD. Установите эту переменную на положительное значение, если у вас есть сервисы, которые могут блокировать неопределенный срок, и вы предпочитаете, чтобы контейнер не удастся, если не все встал через данный момент. Обратите внимание, что это значение также включает в себя инициализацию устаревшего контейнера ( /etc/cont-init.d
) и службы ( /etc/services.d
), поэтому примите это во внимание при вычислении подходящего значения. В версиях S6-Overlay до 3,1.6.2 по умолчанию было 5000 (пять секунд), но это вызвало больше нежелательных сбоев контейнеров, чем он решил проблемы, так что теперь нет тайм-аута по умолчанию: S6-Overlay будет ждать, пока необходимо для того, чтобы все услуги были подняты.S6_READ_ONLY_ROOT
(default = 0): при запуске в контейнере, чья корневая файловая система только что считывается, установите эту ENV на 1 , чтобы сообщить этап 2 INIT, что он должен скопировать сценарии инициализации, предоставленные пользователем, из /etc
/run/s6/etc
Он пытается изменить разрешения и т. Д. См. Для получения дополнительной информации, см. только для чтения корневой файловой системы.S6_SYNC_DISKS
(по умолчанию = 0): установите эту ENV на 1, чтобы сообщить о этапе 3 INIT, что он должен попытаться синхронизировать файловые системы, прежде чем остановить контейнер. Примечание. Это, вероятно, синхронизируется все файловые системы на хосте.S6_STAGE2_HOOK
(default = none): если эта переменная существует, ее содержимое будет интерпретироваться как выдержка из оболочки, которая будет выполнена на ранней стадии 2 до начала службы. Это может быть использовано, например, для динамического исправления базы данных служб во время выполнения прямо перед тем, как она будет скомпилирована и запускается. Неправильное значение может предотвратить работу вашего контейнера или опасности вашей безопасности, поэтому используйте это только в том случае, если вы точно знаете, что вы делаете. Если вы сомневаетесь, оставьте эту переменную неопределенной.S6_VERBOSITY
(по умолчанию = 2): управляет сложности S6-RC и потенциально других инструментов, при запуске контейнера и времени остановки. По умолчанию, 2, обычно является словесным: он перечисляет операции начала и остановки службы. Вы можете сделать контейнер тише, уменьшив этот номер: 1 будет печатать только предупреждения и ошибки, а 0 будет только печатать ошибки. Вы также можете сделать контейнер более многословным, т.е. отслеживание печати и информацию отладки, увеличив этот номер до 5, но результаты быстро станут очень шумными, и большинству людей это не нужно.S6_CMD_RECEIVE_SIGNALS
(по умолчанию = 0): решает, следует ли отправлять сигналы, отправленные в контейнер в PID 1 или CMD. По умолчанию, когда вы выполняете, например, docker stop
, на PID 1 контейнера будет отправлен сигнал термина, что запустит полную последовательность выключения контейнера - но если CMD присутствует, он будет среди последних процессов, которые будут убиты , только когда все остальное не работает и контейнер собирается выйти. Если эта переменная составляет 1 или более, сигналы переносятся от PID 1 к CMD, что означает, что docker stop
будет отправлять SIGTRY в CMD, а контейнер запустит свою процедуру выключения только тогда, когда CMD будет мертв. Обратите внимание, что только Sigterm, Sigquit, Sigint, Sigusr1, Sigusr2, Sigpwr и Sigwinch перенаправлены; Другие сигналы либо игнорируются, либо не могут быть отвлечены и обязательно обрабатываются PID 1. Пожалуйста, имейте в виду, что использование этой опции может помешать интерактивным CMD вообще работать - другими словами, если вы запускаете интерактивный CMD в терминале, Don 't Установите эту переменную; Но это должно быть хорошо, так как в этом случае у вас уже есть интерактивные способы остановки вашего CMD. Если программное обеспечение, работающее в вашем контейнере, требует системного журнала, извлеките syslogd-overlay-noarch.tar.xz
Tarball: Это даст вам небольшую эмуляцию Syslogd. Журналы будут обнаружены в различных подкатариях /var/log/syslogd
, например, сообщения о сообщениях /var/log/syslogd/messages/
messages, новейшие журналы доступны в /var/log/syslogd/messages/current
Сообщения /var/log/syslogd/messages/current