Mam wiele partycji LVM, z których każda zawiera instalację Ubuntu. Czasami chcę to zrobić apt-get dist-upgrade
, aby zaktualizować instalację do najnowszych pakietów. Robię to za pomocą chroot - proces ten zwykle przypomina:
$ 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
[nie pokazano: montuję i odmontowuję także /mnt/chroot-0/{dev,sys,proc}
jako bind-mounty do rzeczywistych /dev
, /sys
a /proc
ponieważ dist-upgrade wydaje się oczekiwać, że będą obecne]
Jednak po aktualizacji do dokładności ten proces już nie działa - końcowy umount zakończy się niepowodzeniem, ponieważ w /mnt/chroot-0
systemie plików nadal są otwarte pliki . lsof
potwierdza, że w chroot są procesy z otwartymi plikami. Procesy te zostały uruchomione podczas aktualizacji dist, zakładam, że dzieje się tak, ponieważ niektóre usługi w chroot muszą zostać zrestartowane (np. Poprzez service postgresql restart
) po aktualizacji pakietu.
Tak więc, myślę, że muszę powiedzieć upstart, aby zatrzymać wszystkie usługi uruchomione w tym chroot. Czy istnieje sposób, aby to zrobić niezawodnie?
Próbowałem:
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
Gdzie initctl list
wydaje się, że robi to dobrze i wyświetla listę procesów, które zostały uruchomione w tym konkretnym katalogu głównym. Próbowałem też dodać to, jak sugeruje Tuminoid:
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
Nie wydają się one jednak łapać wszystkiego; procesy, które zostały zdemonizowane i ponownie powiązane z PID 1, nie zostają zatrzymane. Próbowałem też:
sudo chroot /mnt/chroot-0 telinit 0
Ale w tym przypadku init nie rozróżnia oddzielnych korzeni i zamyka całą maszynę.
Czy jest więc jakiś sposób, aby powiedzieć initowi, aby zatrzymał wszystkie procesy w konkretnym chroocie, abym mógł bezpiecznie odmontować system plików? Czy upstart ma jakieś możliwości SIGTERM / SIGKILL wszystkich procesów potomnych (tak jak w przypadku regularnego wyłączania) w chroot?
Odpowiedzi:
Nie ufam nic poza jądrem, aby utrzymać tutaj rozsądny stan, więc nie używam init do wykonania tej pracy, ani nie liczę na to, że wiem, co jest zamontowane, a co nie (niektóre pakiety może montować dodatkowe systemy plików, takie jak binfmt_misc). Do uboju procesowego używam:
A do montowania chrootów używam:
Jako uzupełnienie wskazałbym, że podejście do tego jako problemu z inicjacją jest prawdopodobnie niewłaściwym sposobem patrzenia na ten problem, chyba że faktycznie masz inicjację w chroot i oddzielną przestrzeń procesu (tj. W przypadku kontenerów LXC) . Z jednym inicjatorem (poza chroot) i wspólną przestrzenią procesową, nie jest to już „problem inicjacyjny”, ale raczej od ciebie zależy znalezienie procesów, które mają ścieżkę obrażającą, stąd powyższy proces.
Z pierwszego postu nie jest jasne, czy są to systemy w pełni rozruchowe, które aktualizujesz tylko zewnętrznie (tak to czytam), czy też chrooty, których używasz do takich rzeczy jak kompilacje pakietów. Jeśli jest to drugie, możesz także chcieć mieć policy-rc.d (takie jak ten, który został dodany przez mk-sbuild), który po prostu zabrania inicjowania zadań rozpoczynających się w pierwszej kolejności. Oczywiście nie jest to rozsądne rozwiązanie, jeśli mają one być również systemami rozruchowymi.
źródło
policy-rc.d
wyglądają na ciekawe podejście (mógłbym je po prostu usunąć po interakcji z chrootem). Czy wpływa to zarówno na pracę, jak/etc/rc*.d
i na/etc/init/*.conf
styl?Już sam zidentyfikowałeś problem: niektóre rzeczy działają
service ...
podczas aktualizacji systemu iservice
nie są częścią Upstart, ale częściąsysvinit
. Dodaj podobną magię awk,service --status-all
aby zatrzymać usługi sysvinit, tak jak w przypadku usług Upstart.źródło
sudo chroot /mnt/chroot-0 service --list-all
isudo chroot /mnt/chroot-0 initctl list
, które nie zgłaszają żadnych uruchomionych usług. Jednak/usr/bin/epmd
(z erlang-base) nadal działa.Wiem, że to pytanie jest dość stare, ale myślę, że jest tak samo aktualne jak w 2012 roku i mam nadzieję, że ktoś uzna ten kod za przydatny. Napisałem kod do czegoś, co robiłem, ale pomyślałem, że się nim podzielę.
Mój kod jest inny, ale pomysły są bardzo podobne do @infinity (w rzeczywistości - jedynym powodem, dla którego teraz wiem o / proc / * / root, jest jego odpowiedź - dzięki @infinity!). Dodałem też kilka fajnych dodatkowych funkcji
Teraz zrobiłbyś 2 rzeczy, aby upewnić się, że chroot można odmontować:
Zabij wszystkie procesy, które mogą być uruchomione w chroot:
Zabij wszystkie procesy, które mogą być uruchomione poza chrootem, ale przeszkadzają w nim (np. Jeśli twój chroot to / mnt / chroot, a dd pisze do / mnt / chroot / testfile, / mnt / chroot nie odmontuje się)
Uwaga: Uruchom cały kod jako root
Ponadto w przypadku mniej złożonej wersji zamień KILL_PID na jeden
kill -SIGTERM
lubkill -SIGKILL
źródło
jchroot : chroot z większą izolacją.
Po wykonaniu polecenia, każdy proces rozpoczęty przez wykonanie tego polecenia zostanie zabity, każdy IPC zostanie zwolniony, każdy punkt podłączenia zostanie odmontowany. Wszystko czyste!
schroot nie jest jeszcze w stanie tego zrobić, ale jest to planowane
Przetestowałem to z powodzeniem w OpenVZ VPS, które nie mogą używać dokera ani lxc.
Szczegółowe informacje można znaleźć na blogu autora:
https://vincent.bernat.im/en/blog/2011-jchroot-isolation.html
źródło
schroot: Ma funkcję zarządzania sesjami. Po zatrzymaniu sesji wszystkie procesy zostają zabite.
https://github.com/dnschneid/crouton/blob/master/host-bin/unmount-chroot : Skrypty te zabijają cały proces chroot i odmontowują wszystkie zamontowane urządzenia.
źródło