linux + записывать в журнал как стандартный вывод, так и стандартную ошибку и для консоли

В решении этой проблемы решающее значение имела информация, представленная на http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml. Однако, это руководство относится к очень старой версии RHEL, и различная информация была устаревшей.

Приведенные ниже инструкции предназначены для работы с CentOS 7, но они должны быть достаточно легко переносимы на любой дистрибутив, в котором работает systemd. Все команды выполняются от имени root.

  1. Убедитесь, что система находится в стабильном состоянии

    Убедитесь, что никто больше не использует ее и не происходит ничего важного. Возможно, хорошей идеей будет остановить такие предоставляющие сервисы устройства, как httpd или ftpd, просто для того, чтобы внешние соединения не нарушили работу в середине.

    systemctl stop httpd
    systemctl stop nfs-server
    # и так далее....
    
  2. Размонтируйте все неиспользуемые файловые системы

    umount -a
    

    Это выведет несколько предупреждений 'Target is busy', для самого корневого тома и для различных временных/системных ФС. На данный момент их можно проигнорировать. Важно то, что ни одна файловая система на диске не остается смонтированной, кроме самой корневой файловой системы. Проверьте это:

    # mount сам по себе предоставляет информацию, но column делает возможным чтение
    mount | column -t
    

    Если вы видите, что файловые системы на диске все еще смонтированы, значит, что-то все еще работает, чего не должно быть. Проверьте, что это, используя fuser:

    #, если необходимо:
    yum install psmisc
    # затем:
    fuser -vm 
    systemctl stop 
    umount -a
    # повторите по мере необходимости...
    
  3. Сделайте временного корня

    mkdir /tmp/tmproot
    mount -t tmpfs none /tmp/tmproot
    mkdir /tmp/tmproot/{proc,sys,dev,run,usr,var,tmp,oldroot}
    cp -ax /{bin,etc,mnt,sbin,lib,lib64} /tmp/tmproot/
    cp -ax /usr/{bin,sbin,lib,lib64} /tmp/tmproot/usr/
    cp -ax /var/{account, empty, lib, local, lock, nis, opt, preserve, run, spool, tmp, yp} /tmp/tmproot/var/
    

    Это создает очень минимальную корневую систему, что нарушает (среди прочего) просмотр manpage (нет /usr/share), настройки на уровне пользователя (нет /root или /home) и так далее. Это сделано намеренно, так как является стимулом не оставаться в такой придуманной корневой системе дольше, чем это необходимо.

    На этом этапе вы также должны убедиться, что все необходимое программное обеспечение установлено, поскольку это также наверняка приведет к поломке менеджера пакетов. Просмотрите все шаги и убедитесь, что у вас есть необходимые исполняемые файлы.

  4. Поворот в корень

    mount --make-rprivate / # необходимо для работы pivot_root
    pivot_root /tmp/tmproot /tmp/tmproot/oldroot
    for i in dev proc sys run; do mount --move /oldroot/$i /$i; done
    

    systemd заставляет монтирование разрешать совместное использование поддеревьев по умолчанию (как в mount --make-shared), и это вызывает ошибку pivot_root. Следовательно, мы отключаем это глобально с помощью mount --make-rprivate /. Системная и временная файловые системы оптом перемещаются в новый корень. Это необходимо для того, чтобы система вообще работала; сокеты для связи с systemd, среди прочего, живут в /run, и поэтому нет способа заставить запущенные процессы закрыть его.

  5. Обеспечение удаленного доступа пережило переключение

    systemctl restart sshd
    systemctl status sshd
    

    После перезапуска sshd убедитесь, что вы можете войти в систему, открыв другой терминал и снова подключившись к машине по ssh. Если вы не можете, устраните проблему, прежде чем двигаться дальше.

    Убедившись, что вы можете снова подключиться, выйдите из оболочки, которую вы сейчас используете, и подключитесь снова. Это позволит оставшемуся форку sshd выйти и гарантирует, что новый форк не удерживает /oldroot.

  6. Закройте все, что все еще использует старый root

    fuser -vm /oldroot
    

    Это выведет список процессов, которые все еще держатся за старый корневой каталог. В моей системе он выглядел так:

     USER PID ACCESS COMMAND
    /oldroot: root kernel mount /oldroot
     root 1 ...e. systemd
     root 549 ...e. systemd-journal
     root 563 ...e. lvmetad
     root 581 f...e. systemd-udevd
     root 700 ...e. auditd
     root 723 ...e. NetworkManager
     root 727 ...e. irqbalance
     root 730 F...e. tuned
     root 736 ...e. smartd
     root 737 F...e. rsyslogd
     root 741 ...e. abrtd
     chrony 742 ...e. chronyd
     root 743 ...e. abrt-watch-log
     libstoragemgmt 745 ...e. lsmd
     root 746 ...e. systemd-logind
     dbus 747 ...e. dbus-daemon
     root 753 ...ce. atd
     root 754 ...e. crond
     root 770 ...e. agetty
     polkitd 782 ...e. polkitd
     root 1682 F.ce. master
     postfix 1714 ...ce. qmgr
     postfix 12658 ..ce. pickup
    

    Вам нужно разобраться с каждым из этих процессов, прежде чем вы сможете размонтировать /oldroot. Грубый подход - просто убить $PID для каждого, но это может все сломать. Чтобы сделать это более мягко:

    systemctl | grep running
    

    Это создаст список запущенных служб. Вы должны быть в состоянии соотнести его со списком процессов, хранящихся в /oldroot, а затем выполнить systemctl restart для каждого из них. Некоторые службы откажутся запускаться во временном корне и перейдут в состояние отказа; в данный момент это не имеет значения.

    Если корневой диск, размер которого вы хотите изменить, является диском LVM, вам также может понадобиться перезапустить некоторые другие запущенные службы, даже если они не отображаются в списке, созданном командой fuser -vm /oldroot. Если вы обнаружили, что не можете изменить размер диска LVM в шаге 7, попробуйте systemctl restart systemd-udevd.

    С некоторыми процессами нельзя справиться с помощью простого systemctl restart. У меня это был auditd (который не любит быть убитым через systemctl, и поэтому просто хотел kill -15). С ними можно разобраться по отдельности.

    Последним процессом, который вы обнаружите, обычно является systemd. Для этого выполните systemctl daemon-reexec.

    После этого таблица должна выглядеть так:

     USER PID ACCESS COMMAND
    /oldroot: root kernel mount /oldroot
    
  7. Размонтируйте старый root

    umount /oldroot
    

    На этом этапе вы можете выполнить любые необходимые манипуляции. В исходном вопросе требовался простой вызов resize2fs, но здесь вы можете делать все, что захотите; еще один случай использования - перенос корневой файловой системы с простого раздела на LVM/RAID/что угодно.

  8. Перенос корня назад

    mount  /oldroot
    mount --make-rprivate / # снова
    pivot_root /oldroot /oldroot/tmp/tmproot
    for i in dev proc sys run; do mount --move /tmp/tmproot/$i /$i; done
    

    Это прямое изменение шага 4.

  9. Удалите временный корень

    Повторите шаги 5 и 6, только вместо /tmp/tmproot используйте /oldroot. Затем:

    umount /tmp/tmproot
    rmdir /tmp/tmproot
    

    Поскольку это tmpfs, в этот момент временный корень растворяется в эфире, чтобы никогда больше не появиться.

  10. Верните все на свои места

    Снова смонтируйте файловые системы:

    mount -a
    

    На этом этапе вам также следует обновить /etc/fstab и grub.cfg в соответствии с любыми корректировками, сделанными на шаге 7.

    Перезапустите все неработающие службы:

    systemctl | grep failed
    systemctl restart 

    Снова разрешите общие поддеревья:

    mount --make-rshared /
    

    Запустите остановленные блоки обслуживания - вы можете использовать эту единственную команду:

    systemctl isolate default.target
    

И все готово.

Большое спасибо Andrew Wood, который отработал эту эволюцию на RHEL4, и steve, который предоставил мне ссылку на первую версию.

0
24.04.2018, 16:02
1 ответ

Вероятно, есть менее подробные способы сделать это, но классическим решением будет что-то вроде:

#!/bin/bash

trap 'rm $TMP' 0
TMP=$(mktemp)
rm $TMP
mkfifo $TMP
tee < $TMP ${log:-/tmp/log.txt} &
exec > $TMP 2>&1

Само собой разумеется, что здесь есть серьезные проблемы с безопасностью и надежностью, поскольку любой другой процесс может читать или записывать из или в FIFO. Если вы хотите сделать что-то подобное, вам лучше использовать простую оболочку, которая направляет вывод вашего скрипта в tee.

0
28.01.2020, 04:24

Теги

Похожие вопросы