Проверка, какие сервисы работают без restart-policy и почему это риск
В systemd у каждого сервиса есть параметр:
Он определяет, будет ли сервис автоматически перезапущен, если процесс упал. Если политика не задана (
▪️ Быстрая проверка одного сервиса
Пример:
или
▪️ Проверка всех сервисов. Можно быстро найти юниты без restart-policy:
Скрипт выведет сервисы, которые не перезапускаются автоматически.
▪️ Хорошие варианты restart-policy. Чаще всего используют:
или
Разница:
▪️ Пример настройки. В unit-файле:
RestartSec добавляет паузу перед перезапуском. После изменения:
BashTex📱 #systemd
В systemd у каждого сервиса есть параметр:
Restart=Он определяет, будет ли сервис автоматически перезапущен, если процесс упал. Если политика не задана (
Restart=no), сервис может просто умереть и никто его не поднимет. На продакшене это часто означает: API внезапно недоступен, очередь сообщений остановилась или воркер перестал обрабатывать задачи. И система жива, но функционально мертва.
systemctl show nginx -p Restart
Пример:
Restart=always
или
Restart=no
systemctl list-units --type=service --no-legend | awk '{print $1}' |
while read -r svc; do
policy=$(systemctl show "$svc" -p Restart --value)
[[ "$policy" == "no" ]] && echo "$svc"
done
Скрипт выведет сервисы, которые не перезапускаются автоматически.
Restart=on-failure
или
Restart=always
Разница:
on-failure - перезапуск при ошибкеalways - перезапуск всегда
[Service]
Restart=on-failure
RestartSec=5
RestartSec добавляет паузу перед перезапуском. После изменения:
systemctl daemon-reload
systemctl restart myservice
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Где остаются следы SSH-подключений
Когда вы подключаетесь к серверу по SSH, система оставляет несколько артефактов. Это полезно знать не только с точки зрения безопасности, но и для диагностики и аудита.
Разберем основные места, где фиксируются подключения.
1️⃣ /var/log/auth.log - основной лог SSH. Каждое подключение к SSH фиксируется здесь. Быстро посмотреть успешные входы:
Если система использует journald, записи можно посмотреть так:
2️⃣ /var/log/wtmp - история логинов. Это бинарный лог, где хранится информация о: входах пользователей, IP-адресах, перезагрузках и выключениях системы. Смотреть его можно командой:
Полезный вариант с расширенной информацией:
3️⃣ /var/log/lastlog - последний вход каждого пользователя. Файл хранит последнюю дату входа для каждого системного пользователя. Посмотреть:
Можно быстро увидеть: кто вообще заходил, когда был последний логин и с какого IP.
4️⃣ /var/run/utmp - текущие активные сессии. Пока пользователь подключен, информация о сессии хранится здесь. Посмотреть активные подключения:
5️⃣ /var/log/btmp - неудачные попытки входа. Если кто-то ошибся с логином или паролем, запись попадет сюда. Посмотреть:
Полезно для поиска: ошибок авторизации или сканирования SSH.
6️⃣ ~/.bash_history - история команд. Все команды пользователя обычно сохраняются в файл:
Если не хотите записывать историю в файл (например, во время диагностики), можно временно отключить:
В текущей сессии history будет работать, но после выхода команды не запишутся на диск.
⚠️ Важный момент. Если сервер отправляет логи во внешнее хранилище, то след о подключении появляется сразу в момент логина.
Поэтому в инфраструктурах часто используют: центральный syslog-сервер, systemd-journal-remote и централизованный сбор логов. Это позволяет видеть историю подключений даже если локальные логи были очищены.
BashTex📱 #security
Когда вы подключаетесь к серверу по SSH, система оставляет несколько артефактов. Это полезно знать не только с точки зрения безопасности, но и для диагностики и аудита.
Разберем основные места, где фиксируются подключения.
grep 'Accepted' /var/log/auth.log
Если система использует journald, записи можно посмотреть так:
journalctl -u ssh -r
-r покажет события в обратном порядке (сначала последние).
last
Полезный вариант с расширенной информацией:
last -Faiwx
lastlog
Можно быстро увидеть: кто вообще заходил, когда был последний логин и с какого IP.
who
#или
w
lastb
Полезно для поиска: ошибок авторизации или сканирования SSH.
~/.bash_history
Если не хотите записывать историю в файл (например, во время диагностики), можно временно отключить:
export HISTFILE=/dev/null
В текущей сессии history будет работать, но после выхода команды не запишутся на диск.
Поэтому в инфраструктурах часто используют: центральный syslog-сервер, systemd-journal-remote и централизованный сбор логов. Это позволяет видеть историю подключений даже если локальные логи были очищены.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
tee + process substitution: один поток и несколько получателей
Иногда нужно одновременно: увидеть вывод команды в терминале, записать его в файл и передать на обработку другой программе Если делать это по очереди - потеряется поток данных. Здесь помогает связка tee + process substitution.
▪️ Что делает tee. tee дублирует поток:
вывод остается в терминале и одновременно пишется в
▪️ Несколько получателей. tee может писать сразу в несколько файлов:
Но иногда нужно не просто файл, а другую команду.
▪️ Process substitution. Bash позволяет подставить вывод команды как файл:
Это называется process substitution.
▪️ Комбинируем
Одна копия идет в терминал, а другая в grep. Если найден ERROR, запись попадет в errors.log.
▪️ Более реальный пример. Допустим, идет сбор логов:
Теперь: полный поток остается в терминале, ошибки автоматически сохраняются
▪️ Можно делать несколько обработчиков
Один поток и сразу несколько фильтров.
BashTex📱 #bash #utils
Иногда нужно одновременно: увидеть вывод команды в терминале, записать его в файл и передать на обработку другой программе Если делать это по очереди - потеряется поток данных. Здесь помогает связка tee + process substitution.
command | tee file.log
вывод остается в терминале и одновременно пишется в
file.log
command | tee out1.log out2.log
Но иногда нужно не просто файл, а другую команду.
>(command)
Это называется process substitution.
command | tee >(grep ERROR > errors.log)
command генерирует потокtee дублирует егоОдна копия идет в терминал, а другая в grep. Если найден ERROR, запись попадет в errors.log.
journalctl -f | tee >(grep ERROR >> errors.log)
Теперь: полный поток остается в терминале, ошибки автоматически сохраняются
journalctl -f | tee \
>(grep ERROR >> errors.log) \
>(grep WARN >> warn.log)
Один поток и сразу несколько фильтров.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Работа с exit codes: как правильно строить логику ошибок
В Bash каждая команда возвращает код завершения: 1 - успех, ≠0 - ошибка. И вся логика скрипта строится именно на этом.
▪️ Базовый принцип
Но руками
▪️ && - выполняй, если успешно
▪️ || - выполняй при ошибке
Полезно для fallback-логики.
▪️ Комбинируем
Но тут есть нюанс:
Если
Поэтому для критичной логики лучше:
▪️ set -e - автоматический выход при ошибке
Теперь скрипт завершится при любой ошибке. Но есть подводные камни:
Если grep ничего не найдёт - exit code = 1 и скрипт завершится. Иногда это нормальное поведение, а не ошибка.
▪️ Правильное использование set -e. Обычно пишут так:
Но при этом явно обрабатывают исключения:
Или:
▪️ pipefail - важно для пайпов
Без него:
С pipefail:
▪️ Общие правила:
BashTex📱 #bash
В Bash каждая команда возвращает код завершения: 1 - успех, ≠0 - ошибка. И вся логика скрипта строится именно на этом.
command
echo $?
Но руками
$? почти не используют, есть удобнее способы.
mkdir dir && cd dir
cd выполнится только если mkdir прошел успешно.
command || echo "Ошибка"
Полезно для fallback-логики.
command && echo "OK" || echo "FAIL"
Но тут есть нюанс:
Если
echo "OK" упадет (редко, но возможно), сработает || и ты получишь ложный FAIL.Поэтому для критичной логики лучше:
if command; then
echo "OK"
else
echo "FAIL"
fi
set -e
Теперь скрипт завершится при любой ошибке. Но есть подводные камни:
set -e
grep "foo" file.txt
echo "done"
Если grep ничего не найдёт - exit code = 1 и скрипт завершится. Иногда это нормальное поведение, а не ошибка.
set -euo pipefail
Но при этом явно обрабатывают исключения:
grep "foo" file.txt || true
Или:
if grep -q "foo" file.txt; then
echo "Found"
fi
set -o pipefail
Без него:
false | true
echo $? # → 0
С pipefail:
false | true
echo $? # → ошибка
&& - для цепочек успеха|| - для fallbackif - для сложной логикиset -e - осторожноpipefail - почти всегда включатьBashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Please open Telegram to view this post
VIEW IN TELEGRAM
😁13
Проверка доступности файловых систем (read/write test)
▪️ Базовая проверка записи
Если команда зависает или падает - есть проблемы с файловой системой.
▪️ Проверка с таймаутом
Теперь: если FS зависла - команда завершится по таймауту, скрипт не повиснет
▪️ Измерение latency. Можно измерить время операции:
🛠 Готовый скрипт
▪️ Проверка нескольких точек
BashTex📱 #scripts #filesystem
touch /mnt/data/.test && rm /mnt/data/.test
Если команда зависает или падает - есть проблемы с файловой системой.
timeout 3 bash -c 'touch /mnt/data/.test && rm /mnt/data/.test'
Теперь: если FS зависла - команда завершится по таймауту, скрипт не повиснет
start=$(date +%s%N)
touch /mnt/data/.test && rm /mnt/data/.test
end=$(date +%s%N)
echo $(( (end - start)/1000000 )) ms
Если операция занимает:
<10 ms - нормально
100–500 ms - уже подозрительно
секунды - проблема
#!/usr/bin/env bash
MOUNT="/mnt/data"
TIMEOUT=3
start=$(date +%s%N)
if timeout "$TIMEOUT" bash -c "touch $MOUNT/.test && rm $MOUNT/.test"; then
end=$(date +%s%N)
latency=$(( (end - start)/1000000 ))
echo "OK ($latency ms)"
else
echo "FAIL: FS недоступна или зависла"
fi
for m in /data /backup /nfs; do
echo -n "$m: "
timeout 3 bash -c "touch $m/.test && rm $m/.test" \
&& echo "OK" || echo "FAIL"
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Группировка команд {} против () - в чем реальная разница
В Bash есть два способа сгруппировать команды:
Снаружи выглядят почти одинаково. На практике - это разное поведение.
▪️ Главное отличие
Конструкция, где выполняется
▪️ Пример с переменными
Результат: 5. Теперь с ():
Результат: 0. Переменная изменилась в subshell и пропала.
▪️ Практика: перенаправления. {} удобно для группового редиректа:
Обе команды попадут в один файл.
▪️ Изоляция через (). Subshell полезен, когда нужно временно изменить окружение:
После выполнения ты останешься в текущем каталоге.
▪️ Типичный кейс
Можно заменить:
Без риска забыть вернуться обратно.
BashTex📱 #bash
В Bash есть два способа сгруппировать команды:
{ cmd1; cmd2; } и ( cmd1; cmd2 )Снаружи выглядят почти одинаково. На практике - это разное поведение.
Конструкция, где выполняется
{} - в текущем shell() - в subshell (дочернем процессе)
count=0
{ count=5; }
echo "$count"
Результат: 5. Теперь с ():
count=0
( count=5 )
echo "$count"
Результат: 0. Переменная изменилась в subshell и пропала.
{
echo "line1"
echo "line2"
} > file.txt
Обе команды попадут в один файл.
( cd /tmp && ls )
После выполнения ты останешься в текущем каталоге.
cd /tmp
do_something
cd -
Можно заменить:
( cd /tmp && do_something )
Без риска забыть вернуться обратно.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Как правильно обрабатывать stdin в скриптах
Хороший CLI-скрипт должен уметь принимать данные: из файла, из pipe (|) и из stdin. И делать это предсказуемо.
▪️ Проверка: есть ли stdin
иначе - есть входной поток
▪️ Базовый шаблон
Теперь скрипт работает так:
▪️ Универсальный вариант (stdin + файл)
🤩 Частая ошибка
Она ломает: пробелы, табы и пустые строки
🤩 Правильно
BashTex📱 #scripts #stdin
Хороший CLI-скрипт должен уметь принимать данные: из файла, из pipe (|) и из stdin. И делать это предсказуемо.
if [ -t 0 ]; then
echo "stdin пуст (ввод с терминала)"
else
echo "данные пришли через pipe"
fi
-t 0 - stdin подключен к терминалуиначе - есть входной поток
#!/usr/bin/env bash
if [ -t 0 ]; then
echo "Usage: command < file | pipe"
exit 1
fi
while IFS= read -r line; do
echo ">> $line"
done
Теперь скрипт работает так:
cat file.txt | script.sh
input="${1:-/dev/stdin}"
while IFS= read -r line; do
echo "$line"
done < "$input"
Теперь можно:
script.sh file.txt
cat file.txt | script.sh
for line in $(cat file.txt); do
echo "$line"
done
Она ломает: пробелы, табы и пустые строки
while IFS= read -r line; do
echo "$line"
done < file.txt
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Контроль роста логов systemd по сервисам
Когда
1️⃣ Сколько логов пишет сервис. Пример для nginx:
Получаем объем логов за час (в байтах).
2️⃣ Быстрый топ шумных сервисов
Результат:
Сразу видно, кто генерирует больше всего логов.
3️⃣ Контроль роста. Сохраняем текущее состояние:
Через время:
4️⃣ Скрипт
BashTex📱 #systemd #logs
Когда
/var/log начинает раздуваться, виноват почти всегда один-два шумных сервиса. Но в journald нет привычных файлов - значит нужно считать по-другому. Значит будем брать сервис, считать объем его логов и сравниваем во времени.
journalctl -u nginx --since "1 hour ago" | wc -c
Получаем объем логов за час (в байтах).
systemctl list-units --type=service --no-legend | awk '{print $1}' |
while read -r svc; do
size=$(journalctl -u "$svc" --since "1 hour ago" 2>/dev/null | wc -c)
echo "$size $svc"
done | sort -nr | head
Результат:
12345678 docker.service
9876543 nginx.service
1234567 ssh.service
Сразу видно, кто генерирует больше всего логов.
journalctl -u nginx --since "1 hour ago" | wc -c > /tmp/nginx.size
Через время:
old=$(cat /tmp/nginx.size)
new=$(journalctl -u nginx --since "1 hour ago" | wc -c)
echo "Рост: $((new - old)) байт"
#!/usr/bin/env bash
SINCE="10 min ago"
THRESHOLD=1000000 # 1 MB
systemctl list-units --type=service --no-legend | awk '{print $1}' |
while read -r svc; do
size=$(journalctl -u "$svc" --since "$SINCE" 2>/dev/null | wc -c)
if (( size > THRESHOLD )); then
echo "ALERT: $svc → $size bytes за $SINCE"
fi
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Давно дружим с CORTEL, это ребята про enterprise решения для крупняка. Сейчас они запустили отдельный бренд для аренды VPS/VDS — Serverum.
Это сервис, где можно выбрать VPS, оплатить и сразу начать пользоваться. Подойдёт для dev/stage-сред, тестовых стендов, ботов, pet-проектов, небольших сервисов и других задач, где нужен сервер без лишней возни.
Внутри:
— собственная проприетарная платформа
— отечественные решения
— защищённая инфраструктура
— низкие цены
— живая поддержка от инженерной команды
Сейчас ребята запускают первых пользователей и собирают честную обратную связь от тех, кто реально работает с инфраструктурой.
Можно зайти, потыкать, взять VPS под задачу и написать фидбек.
Please open Telegram to view this post
VIEW IN TELEGRAM
Работа с сигналами: SIGTERM, SIGINT, SIGHUP
Любой процесс в linux можно остановить сигналом. Если скрипт их не обрабатывает - он просто умирает, иногда оставляя: временные файлы, lock-файлы или незавершённые операции
▪️ Основные сигналы
SIGINT - (2) -
Остановка пользователем
SIGTERM (15) - вежливое завершение -
Дает процессу шанс корректно завершиться.
SIGHUP (1) - перечитай конфиг
часто используется для reload
▪️ Обработка сигналов через trap
Теперь скрипт не просто падает, а выполняет cleanup.
▪️ Пример cleanup
▪️ Полный пример
Теперь:
скрипт не оставляет мусор
Не все сигналы можно перехватить. Нельзя поймать: SIGKILL (9)
Если прилетит
BashTex📱 #scripts #utils
Любой процесс в linux можно остановить сигналом. Если скрипт их не обрабатывает - он просто умирает, иногда оставляя: временные файлы, lock-файлы или незавершённые операции
SIGINT - (2) -
Ctrl+CОстановка пользователем
SIGTERM (15) - вежливое завершение -
systemctl stop / killДает процессу шанс корректно завершиться.
SIGHUP (1) - перечитай конфиг
часто используется для reload
trap 'echo "Получен SIGINT"; cleanup; exit 1' INT
trap 'echo "Получен SIGTERM"; cleanup; exit 0' TERM
Теперь скрипт не просто падает, а выполняет cleanup.
cleanup() {
echo "Чистка..."
rm -f /tmp/my.lock
}
#!/usr/bin/env bash
LOCK=/tmp/job.lock
touch "$LOCK"
cleanup() {
echo "Удаляю lock"
rm -f "$LOCK"
}
trap cleanup EXIT
trap 'echo "SIGINT"; exit 1' INT
trap 'echo "SIGTERM"; exit 0' TERM
while true; do
echo "Работаю..."
sleep 2
done
Теперь:
Ctrl+C - корректное завершениеkill - cleanup выполняетсяскрипт не оставляет мусор
Не все сигналы можно перехватить. Нельзя поймать: SIGKILL (9)
Если прилетит
kill -9 - все, без cleanup.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Please open Telegram to view this post
VIEW IN TELEGRAM
😁2
Подготовка к DevOps/SRE интервью с «Troubleshooting Docker и Kubernetes: поиск и устранение проблем»
В программе только важные аспекты:
— troubleshooting Docker и образов
— диагностика сетевых проблем
— настройка readiness/liveness probes
— отладка pod’ов, деплоев и ingress
— анализ логов контейнеров и кластера
— разбор ошибок CrashLoopBackOff, OOMKilled, ImagePullBackOff и других
Собеседования на DevOps/SRE сейчас всё чаще строятся вокруг реальных инцидентов. Данный курс фокусируется именно на таких сценариях и помогает в подготовке к практическим вопросам
48 часов доступен со скидкой 25%
↗️ Пройти курс на Stepik
В программе только важные аспекты:
— troubleshooting Docker и образов
— диагностика сетевых проблем
— настройка readiness/liveness probes
— отладка pod’ов, деплоев и ingress
— анализ логов контейнеров и кластера
— разбор ошибок CrashLoopBackOff, OOMKilled, ImagePullBackOff и других
Собеседования на DevOps/SRE сейчас всё чаще строятся вокруг реальных инцидентов. Данный курс фокусируется именно на таких сценариях и помогает в подготовке к практическим вопросам
48 часов доступен со скидкой 25%
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Когда переменные пропадают
Одна из частых ловушек в bash - переменная изменилась… но снаружи осталась прежней. Причина почти всегда одна - subshell.
▪️ Что такое subshell. Subshell - это дочерний процесс bash. Он получает копию переменных, но изменения не возвращаются назад. Создается, например, здесь:
или в пайпах:
▪️ Классическая проблема
Результат: 0
Почему? Цикл while выполняется в subshell.
▪️ Правильный вариант
Результат: 3
Теперь цикл работает в текущем shell.
▪️ Ещё пример
Результат: 1
Изменение потерялось.
▪️ Когда это полезно. Subshell - это не баг, а инструмент. Например:
внутри меняем каталог, а снаружи остаемся там же
BashTex📱 #scripts
Одна из частых ловушек в bash - переменная изменилась… но снаружи осталась прежней. Причина почти всегда одна - subshell.
( command )
или в пайпах:
command | while read ...
count=0
echo -e "a\nb\nc" | while read -r line; do
((count++))
done
echo "$count"
Результат: 0
Почему? Цикл while выполняется в subshell.
count=0
while read -r line; do
((count++))
done < <(echo -e "a\nb\nc")
echo "$count"
Результат: 3
Теперь цикл работает в текущем shell.
x=1
( x=5 )
echo "$x"
Результат: 1
Изменение потерялось.
( cd /tmp && ls )
внутри меняем каталог, а снаружи остаемся там же
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Файлы удалены, а место не освободилось
Классическая ситуация: удалили большой лог, df все еще показывает, что диск забит.
Ответ: файл удален из файловой системы, но процесс всё ещё держит его открытым.
▪️ Почему так происходит
В linux файл удаляется не сразу. Если процесс держит дескриптор: файл исчезает из каталога, но данные остаются на диске пока процесс не закроет файл
▪️ Как найти такие файлы
Пример вывода:
Это значит: файл удален, но процесс nginx все еще его держит
▪️ Найти самые тяжелые
Так можно быстро увидеть, кто реально съедает место.
▪️ Что делать
Вариант 1 - перезапустить сервис
Процесс закроет файл и место освободится.
Вариант 2 - убить процесс
(если можно безопасно остановить)
Вариант 3 - обнулить файл через
Где:
1234 - PID
10 - дескриптор из lsof
Это освободит место без перезапуска процесса.
BashTex📱 #storage
Классическая ситуация: удалили большой лог, df все еще показывает, что диск забит.
Ответ: файл удален из файловой системы, но процесс всё ещё держит его открытым.
В linux файл удаляется не сразу. Если процесс держит дескриптор: файл исчезает из каталога, но данные остаются на диске пока процесс не закроет файл
lsof | grep deleted
Пример вывода:
nginx 1234 user 10w REG ... /var/log/nginx/access.log (deleted)
Это значит: файл удален, но процесс nginx все еще его держит
lsof -nP | grep deleted | sort -k7 -nr | head
Так можно быстро увидеть, кто реально съедает место.
Вариант 1 - перезапустить сервис
systemctl restart nginx
Процесс закроет файл и место освободится.
Вариант 2 - убить процесс
kill 1234
(если можно безопасно остановить)
Вариант 3 - обнулить файл через
/proc
: > /proc/1234/fd/10
Где:
1234 - PID
10 - дескриптор из lsof
Это освободит место без перезапуска процесса.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2