Как отключить сервер Linux после 60 минут работы?

18

У меня есть сервер, который обычно отключается по соображениям безопасности. Когда я хочу поработать с ним, я включаю его, выполняю свои задачи и снова выключаю. Мои задачи обычно занимают не более 15 минут. Я хотел бы реализовать механизм автоматического выключения через 60 минут.

Я исследовал, как сделать это с помощью cron, но я не думаю, что это правильный путь, потому что cron не учитывает время последнего включения сервера. Я могу только установить периодические шаблоны, но они не принимают эти данные во внимание.

Как я мог сделать эту реализацию?

jmhostalet
источник
4
Посмотрите на at(разовое исполнение).
dirkt
14
Я не сделал этого, но ваш сценарий входа в систему может запустить sudo shutdown -h +60счетчик, который запустит счетчик обратного отсчета 60 минут для процесса выключения (-halt). Если вы хотите отменить его, вы можете sudo shutdown -c (хотя он не использует cron)
guiverc
7
В зависимости от характера ваших задач, возможно, стоит запускать их внутри док-контейнера, поэтому вам не нужно беспокоиться о выключении сервера. Контейнер создан, он выполняет ваши задачи и после этого уничтожается.
Висенте Оливер Риера
6
Не ожидайте от этого реальной выгоды для безопасности. Большинство уязвимостей можно использовать менее чем за секунду, поэтому отключение через час не предотвратит их использование. А злоумышленник, обнаруживший уязвимость, может подождать, пока вы включите компьютер, чтобы выполнить атаку.
Касперд
2
В отношении комментария @kasperd я бы перефразировал его, сказав, что вам нужен точно такой же уровень безопасности на вашем сервере, независимо от того, насколько он мал или фактически находится в сети. Обратите внимание, что это сервер, поэтому он подключен к чему-то, и это означает, что что- то будет знать, когда он включен - автоматические развертки - это не то, о чем вы беспокоитесь, это подключения любого рода, и вы не можете избежать этого, поэтому максимальная безопасность всегда единственный путь.
Стивен

Ответы:

23

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

echo "sudo shutdown -P +60" >> ~/.profile
Дирк Кригсман
источник
11
Время в минутах, а не секундах. Попробуйте shutdown -k -P 3600против shutdown -k -P 60( -kпечатает сообщение на стене, но не имеет другого эффекта)
Себастьян
12
Но попробуйте команду один раз, вы не хотите, чтобы мгновенное отключение было привязано к вашему профилю!
Фабиан Релинг,
17
Я полагаю, что каждый вход в SSH вызовет новый вызов выключения. Будет ли счетчик сбрасываться тогда?
JoL
4
Также стоит упомянуть, что вход в систему не будет разрешен в течение последних 5 минут, как указано на странице завершения работы.
JoL
6
Обратите внимание, что через 60 минут после входа в систему это не то же самое, что через 60 минут после загрузки. Что если вы загрузите компьютер, а затем забудете войти?
Хаген фон Айцен
69

Есть несколько вариантов.

  • Предоставьте время напрямую shutdown -P:

    shutdown -P +60
    

    Обратите внимание, что shutdown справочная страница также указывает:

    Если используется аргумент времени, за 5 минут до выхода из системы создается файл / run / nologin, чтобы гарантировать, что дальнейшие входы в систему не будут разрешены.

  • Используйте atкоманду.

  • Создайте файл модуля systemd или скрипт инициализации, который запускается shutdown -P 60при запуске.

  • Используйте cron @rebootдля запуска команды после загрузки.

    Добавить в (корневой) crontab:

    @reboot shutdown -P +60
    

Для последних двух методов вы также можете использовать sleep 3600 && shutdown -P nowвместо аргумента time, shutdownчтобы отложить выключение на 60 минут. Таким образом, вход в систему возможен до последнего момента перед выполнением выключения.

sebasth
источник
2
Я думаю, что с помощью sleepкоманды вам все еще нужно указать время shutdown- мы бы хотели использовать nowэтот аргумент, если мы уже сделали ожидание (но учтите, что вы не получите слишком много предупреждений, чтобы сохранить свою работу до этого исчезает из-под тебя!).
Тоби Спейт
1
Хотя shutdown -P 60работает это не так, как команда должна быть вызвана. Согласно справочной странице, которую вы должны использовать shutdown -P +60. --- Также отключение без аргумента времени (в примере sleep 3600 && shutdown -P) будет отложено на одну минуту (например shutdown -P +1). Как писал Тоби Спейт, вы, вероятно, захотите использовать shutdown -P now.
Пабук
33

Это похоже на проблему XY .

Мои задачи обычно занимают не более 15 минут. Я хотел бы реализовать механизм автоматического отключения через 60 минут.

Если вы завершите работу через 60 минут, вы рискуете столкнуться с особенно сложной проблемой, и вам просто нужно больше времени. Многие из предыдущих решений не позволили бы отложить остановку.

Если задача не является интерактивной, а представляет собой задачу по сценарию, которая автоматически запускается с другого компьютера, @sdkks предоставил для этого отличное решение ; вам действительно нужно просто поручить машине запустить poweroff, как только скрипт и все его задачи завершатся.

Однако, если ваша задача является интерактивной, я бы предложил вместо нее выполнить обнаружение простоя.

Если вы выполняете свою задачу в графическом интерфейсе (X11), вы можете обнаружить незанятые сеансы графического интерфейса, используя описанный здесь подход: выполните команду, когда система находится в режиме ожидания и снова активна

Если вы выполняете задачу через терминал, вы можете обнаружить зарегистрированных пользователей, используя whoкоманду. Вы можете настроить cronjob, который выключит машину, если whoвернет пустой результат. Обратите внимание, что это будет довольно консервативный подход; система не выключится, если вы оставите консоль подключенной, но не будет работать.

Если вы хотите быть более агрессивным и отключить сеансы бездействующего терминала, вы можете объединить предыдущий подход с автоматическим отключением бездействующих сеансов SSH ClientAliveInterval и ClientAliveCountMax. Другой подход для этого, если у вас нет SSH, но есть сеанс локального терминала, это использовать время простоя терминала, возвращаемое wкомандой.

Ли Райан
источник
2
Это очень важный момент. Что бы вы ни реализовали - в ваших интересах убедиться, что вы также можете отменить отключение.
Shadow
1
Что-то пошло не так, если он все еще работает на 60 м, так что, возможно, просто начните снова. Это может быть очень дорого в облаке. Невозможность обеспечить отключение в одном случае обошлась мне в 4000 долларов.
Маккензм
8

Хотя все предыдущие ответы здесь отвечают требованиям к совершенству, вы также можете выключить машину, как только задачи будут выполнены.

bashсценарии могут быть trapвоспроизведены, что означает, что определенные сигналы могут быть перехвачены и определенные задачи могут быть выполнены при необходимости. EXITявляется одним из сигналов, которые могут быть пойманы в ловушку.

Вы сможете:

  1. Установите trapдля EXITваших сценариев автоматической оболочки, что означает прекращение ваших автоматизированных задач
  2. Установите trapдля себя .bashrc EXIT, то есть, когда вы выходите из этой машины, выключите его.

Вариант № 1 был бы идеальным случаем, если ваши задачи не требуют специального осмотра и ручной оценки.

Вариант № 2 будет охватывать случаи, когда вы забудете выйти из терминала без отключения питания. Есть предостережение, хотя; если у вас открыто несколько терминалов на одной машине, и вы выходите из одной из них, она все равно выключит машину. (Это может быть написано в сценарии, чтобы избежать этого, но я не буду усложнять решение.)

cleanup(){
    # Do some tasks before terminating
    echo oh la la, cleaning is so nice
    echo "See you later, world"
    sudo poweroff & # finally shutdown
}
trap cleanup EXIT

Это может быть в конце .bashrcварианта № 2, в верхней части вашего сценария для варианта № 1.

Почему бы не использовать poweroffв конце сценария?

Я предпочитаю использовать set -eo pipefailв верхней части моих сценариев. Если произойдет какая-либо ошибка, она не потерпит молчания; это остановит выполнение большего количества команд. trapот EXITсигнала должен охватывать случаи , когда скрипт завершается преждевременно из - за ошибки.

Однако для ваших задач это также может означать, что машина выключится, прежде чем они будут завершены.

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

sdkks
источник
Договорились, и чтобы быть уверенным, может быть, время отключения дня от cron. Это тормоз мертвецов.
Маккензм
@ Abigail для сценария, он должен быть выше, потому что .bashrcя бы предпочел основание на случай, если что-то еще перезапишет его. Ваша проблема не ясна, не могли бы вы поделиться примером сниппета на repl.it?
sdkks
@ mckenzm я не понимаю. Можете ли вы поделиться примером кода или более подробным объяснением?
sdkks
5

Конкретизируя @dirkt комментарий, вы можете вставить atкоманду на ваш .bashrcили .profileили любой другой файл , ваша оболочка использует на входе в систему , чтобы запланировать автоматическое отключение через 60 минут после вашего входа в систему .

Что-то вроде:

at now + 60 minutes -f /sbin/halt
Мистер Шунц
источник
Это задание по праву at. Вы также можете увидеть atзадачи в/var/spool/
sdkks
5
Я бы посоветовал не использовать atв этом контексте, потому что он переживает перезагрузки. Если OP войдет в систему, вручную завершит работу и снова войдет в систему в течение часа, он будет выгнан раньше, чем через час после его последнего входа в систему при первом запланированном завершении работы.
Аарон
@ Аарон, это правда. Не думал об этом. Постоянство загрузки является предупреждением для этого решения.
sdkks
5

Следующее выполняется commandс параметрами, и, если оно завершится успешно, оно немедленно выключит окно, предполагая, что пользователь может работать poweroff. Возможно, потребуется использовать sudo poweroff.

command --parameters && poweroff

Принимая во внимание, что следующий просто запускается poweroffсразу после завершения команды:

command --parameters ; poweroff

Если вы думаете, что команде нужно время отдыха после завершения, запустите

command --parameters ; sleep 3600 ; poweroff

Если вы думаете, что команда может работать сверхурочно, вы можете ограничить ее часом:

timeout 1h command --parameters ; poweroff

timeoutявляется частью coreutilsпакета, так что вы, вероятно, уже имеете его.

Criggie
источник
3

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

gogators
источник
2
Повреждение файловой системы?
Xen2050
@ Xen2050 не проблема для любой современной (журналируемой) файловой системы.
Том
1
@ Tom Есть ли у вас источник для принудительного монтирования никогда не приведет к повреждению файловой системы, если есть журналирование? Звучит ново для меня, я хотел бы прочитать об этом. По крайней мере, он должен пометить файловую систему как грязную, заставляя fsck правильно?
Xen2050
1
В большинстве случаев следует просто переиграть журнал и покончить с этим. Выключение питания не должно вызывать повреждение файловой системы в журнализированной файловой системе, хотя нет никаких гарантий, если вы не используете файловую систему, такую ​​как ZFS, которая специально разработана для этого случая.
Том
1
Воспроизведение журнала может завершиться неудачей - пару недель назад у меня была очень трудная сессия fsck после отключения питания на 1/2 секунды на машине без ИБП. Это было использование ext4 с журналом; это не совсем непобедимо!
Тоби Спейт
2

Если вы находитесь в systemdмашине, вы можете использовать монотонный таймер

Блок таймера /etc/systemd/system/shutdown_after_an_hour.timer

[Unit]
Description=shutdown after an hour

[Timer]
OnBootSec=1h

[Install]
WantedBy=timers.target

Блок таймера /etc/systemd/system/shutdown_after_an_hour.service:

[Unit]
Description=shutdown after an hour

[Service]
ExecStart=/sbin/poweroff --force --no-wall
Type=oneshot

Это включено через

# systemctl enable shutdown_after_an_hour.timer

Его состояние (в частности, сколько времени осталось до выключения) доступно через

# systemctl list-timers shutdown_after_an_hour.timer

Он будет работать при следующей перезагрузке, он бесполезен для systemctl startнего во время сеанса, когда он создается, поскольку он либо не будет работать (потому что он не был запущен во время перезагрузки), либо сразу выключит машину, если прошло более часа. Я не знаю, какой из них произойдет на самом деле, я никогда не проверял этот конкретный случай.

WOJ
источник
1

Попробуйте поставить скрипт ( sudo shutdown -P 3600) в/etc/init.d каталог, чтобы он автоматически запускался при запуске.

Или попробуйте использовать anacron, добавив команду в /etc/anacrontabфайл. Я также предлагаю использовать nohupперед командой, чтобы убедиться, что команда все еще работает после выхода из системы.

Saveriofr
источник
1
В зависимости от дистрибутива, он может не выполняться, просто находясь в
init.d
@sdkks, ты прав. Anacron также может рассматриваться. поместите скрипт в / etc / anacrontab, также используемый с nohup в случае выхода из системы.
Saveriofr
1
@Saveriofr Вы можете редактировать свой ответ, чтобы улучшить его качество (лучше, чем публиковать дополнительную информацию в качестве комментария).
Энтони Дж. - правосудие для Моники
1

Используйте файл выхода из вашей оболочки

Если вам нужен только сервер для интерактивных или неинтерактивных задач, запущенных вашим UID, попробуйте поместить свои команды выключения в файл ~ / .bash_logout . Руководство по GNU Bash гласит:

Когда выходит из интерактивной оболочки входа или неинтерактивная оболочка входа выполняет встроенную команду выхода, Bash считывает и выполняет команды из файла ~ / .bash_logout, если он существует.

Таким образом, добавление sudo poweroff или аналогичного файла выхода из системы приведет к отключению сервера, как только вы выйдете из текущего сеанса или когда вызовет неинтерактивный сеанс Bash exit. Вы также можете выбрать для использования в или передать временную задержку выключения , если вы предпочли бы отложить завершение работы.

Для более интерактивного подхода к этому вы можете поместить следующие Bashisms в ваш файл выхода из системы:

# Shutdown unless N or n is pressed within 30 seconds.
shopt -s nocasematch
read -t 30 -N 1 -p 'Shutdown now? (Y/n) '
[[ "$REPLY" =~ n ]] || sudo poweroff

Предостережения

Есть некоторые предостережения, которые вы должны иметь в виду об этом решении:

  • Это, вероятно, будет работать даже в терминале, запущенном X Windows, но, вероятно, не будет работать для сеанса X11, который не был запущен startx или подобным.
  • Если у вас есть неинтерактивные сценарии, которые вызывают exit, вы можете столкнуться с отключениями, которые вы не ожидаете.
  • Ваш файл sudoers может запросить пароль, если вы не указали NOPASSWDкоманды выключения, или если вы не звонили sudo -vдо запуска команды выключения.
  • Возможно, есть и другие крайние случаи, о которых я еще не думал.

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

CodeGnome
источник