У меня есть несколько разделов LVM, каждый из которых содержит установку Ubuntu. Иногда я хочу сделать apt-get dist-upgrade
, чтобы обновить установку до самых последних пакетов. Я делаю это с помощью chroot - процесс обычно выглядит примерно так:
$ sudo mount /dev/local/chroot-0 /mnt/chroot-0
$ sudo chroot /mnt/chroot-0 sh -c 'apt-get update && apt-get dist-upgrade'
$ sudo umount /mnt/chroot-0
[не показано: я также монтирую и размонтирую /mnt/chroot-0/{dev,sys,proc}
как bind-mounts для реального /dev
, /sys
и /proc
, как представляется, dist-upgrade ожидает, что они будут присутствовать]
Однако после точного обновления этот процесс больше не работает - окончательное размонтирование завершится неудачно, поскольку в /mnt/chroot-0
файловой системе еще есть открытые файлы . lsof
подтверждает, что в chroot есть процессы с открытыми файлами. Эти процессы были запущены во время dist-upgrade, я предполагаю, что это потому, что некоторые службы в chroot должны быть перезапущены (например, через service postgresql restart
) после обновления пакета.
Итак, я считаю, что мне нужно сказать upstart, чтобы остановить все службы, работающие в этом chroot. Есть ли способ надежно сделать это?
Я пробовал:
cat <<EOF | sudo chroot /mnt/chroot-0 /bin/sh
# stop 'initctl' services
initctl list | awk '/start\/running/ {print \$1}' | xargs -n1 -r initctl stop
EOF
Где, initctl list
кажется, делает правильные вещи и только список процессов, которые были запущены в этом конкретном корне. Я тоже попытался добавить это, как подсказал Туминоид:
cat <<EOF | sudo chroot /mnt/chroot-0 /bin/sh
# stop 'service' services
service --status-all 2>/dev/null |
awk '/^ \[ \+ \]/ { print \$4}' |
while read s; do service \$s stop; done
EOF
Тем не менее, это, кажется, не все поймать; процессы, которые демонизированы и переназначены в PID 1, не останавливаются. Я также попробовал:
sudo chroot /mnt/chroot-0 telinit 0
Но в этом случае init не различает отдельные корни и выключает всю машину.
Итак, есть ли способ сказать init остановить все процессы в определенном chroot, чтобы я мог безопасно размонтировать файловую систему? Имеет ли upstart какое-либо средство для SIGTERM / SIGKILL всех дочерних процессов (как это было бы сделано при обычном завершении работы) внутри chroot?
Ответы:
Я не доверяю ничему, кроме того, чтобы ядро сохраняло нормальное состояние здесь, поэтому я не использую init для выполнения этой работы, и при этом я не рассчитываю на себя, фактически зная, что смонтировано или нет (некоторые пакеты) может монтировать дополнительные файловые системы, такие как binfmt_misc). Итак, для убоя я использую:
А для размонтирования chroot я использую:
В качестве дополнения я хотел бы указать, что подход к этому вопросу как к проблеме инициализации, вероятно, является неправильным подходом, если только у вас фактически нет инициализации в chroot и отдельного пространства процессов (т. Е. В случае контейнеров LXC). , С одним init (за исключением chroot) и общим пространством процессов это больше не «проблема init», а, скорее, зависит только от вас, чтобы найти процессы, которые имеют неправильный путь, отсюда и вышеприведенный обход процесса.
Из вашего первоначального поста не ясно, являются ли они полностью загружаемыми системами, которые вы просто обновляете извне (как я это прочитал), или они являются chroot-файлами, которые вы используете для таких вещей, как сборки пакетов. Если это последнее, вам также может понадобиться policy-rc.d (например, тот, который был добавлен в mk-sbuild), который просто запрещает запускать задания init, начиная с самого начала. Очевидно, что это не вменяемое решение, если речь идет и о загрузочных системах.
источник
policy-rc.d
выглядит как интересный подход (я мог бы просто удалить его после взаимодействия с chroot). Это влияет как на работу, так/etc/rc*.d
и на/etc/init/*.conf
работу?Вы уже определили проблему самостоятельно: некоторые вещи запускаются
service ...
во время dist-upgrade иservice
не являются частью Upstart, а частьюsysvinit
. Добавьте подобную магию awk,service --status-all
чтобы остановить службы sysvinit, которые вы использовали для служб Upstart.источник
sudo chroot /mnt/chroot-0 service --list-all
иsudo chroot /mnt/chroot-0 initctl list
, которые оба сообщают об отсутствии запущенных сервисов. Тем не менее,/usr/bin/epmd
(от erlang-base) все еще работает.Я знаю, что этот вопрос довольно старый, но я думаю, что он так же актуален сегодня, как и в 2012 году, и, надеюсь, кто-то найдет этот код полезным. Я написал код для чего-то, что я делал, но решил поделиться им.
Мой код отличается, но идеи очень похожи на @infinity (на самом деле - единственная причина, которую я теперь знаю о / proc / * / root, - это его ответ - спасибо @infinity!). Я также добавил несколько классных дополнительных функций
Теперь вы должны сделать 2 вещи, чтобы убедиться, что chroot может быть отключен:
Убейте все процессы, которые могут выполняться в chroot:
Убейте все процессы, которые могут выполняться вне chroot, но мешают ему (например: если ваш chroot / mnt / chroot и dd пишет в / mnt / chroot / testfile, / mnt / chroot не удастся размонтировать)
Примечание. Запустите весь код от имени пользователя root.
Кроме того , для менее сложной версии, замените KILL_PID либо
kill -SIGTERM
илиkill -SIGKILL
источник
jchroot : chroot с большей изоляцией.
После выполнения вашей команды любой процесс, запущенный выполнением этой команды, будет уничтожен, любой IPC будет освобожден, любая точка монтирования будет отключена. Все чисто!
Schroot пока не может этого сделать, но это планируется
Я успешно проверил его в OpenVZ VPS, который не может использовать Docker или LXC.
Пожалуйста, прочитайте блог автора для деталей:
https://vincent.bernat.im/en/blog/2011-jchroot-isolation.html
источник
schroot: у него есть особенность управления сессиями. Когда вы останавливаете сеанс, все его процессы уничтожаются.
https://github.com/dnschneid/crouton/blob/master/host-bin/unmount-chroot : этот сценарий завершает весь процесс chroot и отключает все подключенные устройства.
источник