Библиотека девопса | DevOps, SRE, Sysadmin
10.4K subscribers
2.04K photos
83 videos
13 files
3.51K links
Все самое полезное для девопсера в одном канале.

Наши курсы: https://clc.to/ZJ7Z1w

По рекламе: @proglib_adv

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/6798b4e4509aba56522d1787
Download Telegram
🔒 Принцип минимальных прав для секретов в CI/CD

Украденный секрет опасен ровно настолько, насколько широки его права доступа. В большинстве CI/CD-пайплайнов права выдаются с запасом, ведь так проще настроить, но это и есть главная проблема.

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

Разделите секреты по ролям:

• Задача сборки (build) компилирует код. Ей не нужны никакие облачные креды вообще. Если они там есть — уберите.

• Задача тестирования (test) работает с тестовыми данными. Она не должна видеть продовые креды. Заведите отдельные credentials для тест-окружения с доступом только на чтение к тестовой базе.

• Задача деплоя (deploy) — единственная, которой нужны продовые секреты. И только те, что нужны именно для деплоя, ничего лишнего.

Раз в квартал проводите аудит секретов. Удаляйте всё, что не используется ни одной задачей прямо сейчас.

Пример для GitHub Actions

GitHub Actions позволяет привязать секреты к конкретным environments. Продовые секреты становятся доступны только при деплое в production, а не во всех задачах подряд:
jobs:
test:
runs-on: ubuntu-latest
# Продовых секретов здесь нет
# Тесты используют моки или тестовую базу
env:
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}

deploy:
runs-on: ubuntu-latest
environment: production # Отдельный scope секретов + требует подтверждения
needs: test # Запускается только после успешных тестов
env:
# Продовые секреты доступны только здесь
AWS_ROLE_ARN: ${{ secrets.PROD_AWS_ROLE_ARN }}


Ключевой момент: параметр environment: production не просто логическая метка. Он изолирует секреты этого environment от других задач и, по умолчанию, требует ручного подтверждения перед запуском деплоя.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🥱1
🔒 Включите двухфакторку на npm

Атака на axios сработала потому, что злоумышленник получил долгоживущий классический токен npm от аккаунта мейнтейнера. Если бы была включена 2FA, одного токена не хватило бы для публикации новой версии пакета.

Как включить 2FA

Для личного аккаунта:
npm profile enable-2fa auth-and-writes


Режим auth-and-writes требует второй фактор и при входе, и при публикации. Это сильнее, чем auth-only, который защищает только вход, но не публикацию.

Для организации нужны права администратора:
npm access 2fa-required --otp=ВАШ_КОД your-org


Либо через интерфейс: Organisation Settings > Security > Require two-factor authentication.

Что ещё стоит сделать

Классические токены npm живут вечно и дают широкий доступ. В 2022 году появились гранулярные токены. Они ограничены конкретными пакетами и позволяют задать режим read-only или publish-only. Переходите на них.

Классические токены, которые существуют больше 90 дней, стоит проверить и пересоздать. Найти их можно в Account Settings > Access Tokens.

Если разработчик ушёл из команды, то сразу отзывайте его доступ к публикации. npm не делает это автоматически, права сохраняются бессрочно.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
1
👨‍💻 Автоматические бэкапы MySQL через cron и mysqldump

Ручной mysqldump работает ровно до того момента, пока кто-то не забыл его запустить. Для продакшна нужен автоматический запуск по расписанию.

Скрипт с ротацией и сжатием

Создаём файл /opt/scripts/mysql-backup.sh:
#!/bin/bash
BACKUP_DIR="/opt/backups/mysql"
CONTAINER="mysql-container"
DB_USER="root"
DB_PASS="yourpassword"
DATABASE="mydatabase"
RETENTION_DAYS=7

mkdir -p "$BACKUP_DIR"
FILENAME="$BACKUP_DIR/${DATABASE}_$(date +%Y%m%d_%H%M%S).sql.gz"

docker exec "$CONTAINER" mysqldump \
-u "$DB_USER" -p"$DB_PASS" \
--single-transaction \
--routines \
--triggers \
"$DATABASE" | gzip > "$FILENAME"

if [ $? -eq 0 ]; then
echo "Backup completed: $FILENAME"
else
echo "Backup failed!" >&2
exit 1
fi

find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete


Флаг --single-transaction снимает дамп без блокировки таблиц — важно для InnoDB в продакшне. --routines и --triggers включают в дамп хранимые процедуры и триггеры, которые по умолчанию не экспортируются. find в конце удаляет файлы старше RETENTION_DAYS дней.

Добавляем в cron. Запуск каждый день в 4 утра:
0 4 * * * /opt/scripts/mysql-backup.sh >> /var/log/mysql-backup.log 2>&1


Ограничения

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

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

Файлы хранятся локально. Если сервер упадёт или диск сгорит, бэкапы уйдут вместе с данными. Для надёжности нужен вывод в S3 или другое внешнее хранилище.

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

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

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
3
☕️ Java и лимиты

Запускаете Java-приложение и через час получаете звонок, что сервер лежит? Знакомо.

По умолчанию JVM берёт столько памяти и CPU, сколько захочет. На проде это боль. Разберёмся, как это починить.

Память

Два главных флага:

-Xms512m — сколько памяти выделить сразу при старте
-Xmx2g — максимум, выше которого heap не вырастет

java -Xms512m -Xmx2g -jar app.jar


Ставьте -Xmx всегда. Без него JVM может решить, что ей нужна половина RAM сервера и будет права по своей логике.

CPU / потоки

Ограничить количество потоков GC и компилятора:
-XX:ActiveProcessorCount=2


Особенно актуально в Docker/Kubernetes, ведь JVM видит все ядра хоста, а не контейнера. Без этого флага она создаст лишние потоки и будет драться за ресурсы.

Если запускаете в контейнере

Начиная с Java 11+ JVM умеет читать cgroup-лимиты контейнера автоматически. Но лучше явно включить:
-XX:+UseContainerSupport


И добавьте -Xmx через переменную окружения, чтобы удобно менять без пересборки:
JAVA_OPTS="-Xms256m -Xmx1g -XX:ActiveProcessorCount=2"
java $JAVA_OPTS -jar app.jar


📌 Итого: минимальный набор для продакшена
-Xms256m
-Xmx1g
-XX:ActiveProcessorCount=2
-XX:+UseContainerSupport


Дальше смотрите на метрики и подкручивайте под своё приложение.

➡️ Больше про Java без воды в канале. Подписывайтесь, там научат делать Java-Java

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🧑‍💻 Kernel Panic при загрузке: находим причину и чиним

Сервер не поднимается после перезагрузки. Экран с kernel panic, и всё. Это одна из тех ситуаций, когда важно действовать методично, а не наугад.

Что обычно ломается

Три самые частые причины:

• Повреждённый /etc/fstab. Если UUID раздела не совпадает с тем, что прописано в файле, система не может смонтировать диск и падает на старте.

• Проблемы с GRUB. После обновления ядра или ручной правки конфига загрузчик может потерять путь к системе.

• Аппаратные сбои. Отказ диска или памяти тоже проявляется как panic при загрузке, поэтому железо стоит проверить сразу.

Как чинить

Загружаемся в recovery mode. В меню GRUB выбираем Advanced options и строку с (recovery mode). Получаем root-шелл без монтирования основной системы.

Проверяем диск:
fsck -f /dev/sda1


fsck найдёт и исправит ошибки файловой системы. Флаг -f запускает проверку даже если диск помечен как чистый.

Сверяем UUID в /etc/fstab:
blkid


Вывод покажет реальные UUID всех разделов. Открываем /etc/fstab и проверяем, что значения совпадают. Расхождение в одном символе — и система не загрузится.

Если проблема в GRUB, переустанавливаем его:
grub-install /dev/sda
update-grub


/dev/sda — диск, не раздел. Убедитесь, что указываете устройство без цифры на конце.

Как не попасть в это снова

Перед любыми правками в /etc/fstab или конфигах загрузчика делаем бэкап:
cp /etc/fstab /etc/fstab.bak


Изменения в загрузочной конфигурации тестируем на staging-окружении. Продакшн-сервер — плохое место для экспериментов с GRUB.

Если инфраструктура позволяет, настраиваем снапшоты перед каждым обновлением ядра. Откатиться за 30 секунд гораздо приятнее, чем чинить вручную в 3 ночи.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥2🌚1
📎 Дублируем root

В Linux права определяются не именем пользователя, а его UID. У root всегда UID=0. Если создать пользователя с тем же UID=0, система будет воспринимать его как root со всеми вытекающими правами.

Добавляем запись напрямую в /etc/passwd. Открываем файл:
sudo vipw


Добавляем строку в конец файла:
superadmin:x:0:0:Super Admin:/root:/bin/bash


Ставим пароль новому пользователю:
sudo passwd superadmin


Проверяем, что всё работает:
id superadmin
#uid=0(root) gid=0(root) groups=0(root)


Альтернатива через useradd

Команда useradd не позволяет напрямую задать UID=0, но можно создать пользователя и потом поправить запись:
sudo useradd -o -u 0 -g 0 -d /root -s /bin/bash superadmin
sudo passwd superadmin


Флаг -o разрешает дублирование UID. Без него команда завершится с ошибкой.

Если вы используете sudo, убедитесь что новый пользователь тоже может его вызывать. Добавьте строку в /etc/sudoers через visudo:
superadmin ALL=(ALL:ALL) ALL


Такой подход используют в нескольких сценариях: аварийный доступ при утере основного пароля, автоматизация через отдельный сервисный аккаунт с полными правами, или командная работа где нескольким людям нужен root без общего пароля.

Два аккаунта с UID=0 означают двойную поверхность атаки. Следите за тем, кому и зачем открываете такой доступ и включайте аудит действий через auditd или аналоги.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🚮 Drop правила для фильтрации мусорных логов
 
Если вы используете Grafana Cloud Logs, скорее всего, часть логов там вообще не нужна. Health check каждые 5 секунд, DEBUG-записи из забытого сервиса, многословный INFO из batch-джобы — всё это идёт в хранилище и увеличивает счёт.
 
Раньше убрать этот мусор было неудобно. Нужно было лезть в конфиги, договариваться с командами, менять пайплайн. Теперь в Adaptive Logs появились drop rules — правила, которые отфильтровывают ненужные логи до записи в хранилище.
 
Что делают drop rules
 
Правило задаёт условие: какие логи отбрасывать и с какой долей. Можно указать лейбл сервиса, уровень лога, строку в теле — или всё вместе. Поддерживается частичный дроп: например, оставить 10% от потока, а остальное не сохранять.
 
Несколько сценариев, где это полезно:
 
Если payment-service в продакшне шлёт DEBUG-логи, которые никто не смотрит:
service_name = payment-service
log_level = DEBUG
drop rate = 100%

 
Batch-джоба пишет одно и то же тысячи раз в день. Оставляем 10% для выборки:
service_name = batch-processor
drop rate = 90%

 
Выбросить конкретный паттерн. Сервис пишет GET /healthz 200 каждые несколько секунд. Указываем строку в теле лога и дропаем 100%.
 
Как это работает внутри
 
Каждый входящий лог проходит три шага по порядку:
 
1. Exemptions — если лог попадает под исключение, он записывается без изменений.

2. Drop rules — правила применяются по приоритету. Первое совпавшее правило задаёт процент дропа.

3. Patterns — к оставшимся логам применяются рекомендации от самого Adaptive Logs на основе анализа 15 дней запросов.

Exemptions нужны для логов, которые нельзя терять ни при каких условиях, — аудит, ошибки из критичных сервисов. Drop rules — для того, что точно не нужно. Patterns — для всего остального, что Grafana сама определит как малоценное.
 
Как начать
 
Функция доступна в public preview в Grafana Cloud. Нужна роль plugins:grafana-adaptivelogs-app:admin — по умолчанию она есть у Grafana Admin и Org Admin.
 
Путь в интерфейсе:
Adaptive Telemetry → Adaptive Logs → Drop rules → Create a new drop rule
 
Управлять правилами также можно через CLI gcx если нужна автоматизация или интеграция с агентами.
 
➡️ Репозиторий

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
📎 Только имя пода и образ

Иногда нужен простой список подов и их образов. Без лишних колонок, без шума. kubectl get pods -o wide выдаёт слишком много данных, которые в этот момент не нужны.

Для таких случаев есть флаг -o custom-columns. Он позволяет выбрать только те поля, которые важны прямо сейчас.

Чтобы получить таблицу с именем пода и образом контейнера, достаточно одной команды:
kubectl get pods -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[*].image'


Результат — чистая таблица без лишнего. [*] в пути означает, что команда учитывает все контейнеры в поде, включая сайдкары.

Формат колонки строится по простому правилу: сначала заголовок, потом путь к полю в JSON-структуре объекта. Любое поле из kubectl get pod -o json можно вытащить таким же способом.

Это особенно удобно в скриптах и CI, где важна предсказуемость вывода. Никаких сюрпризов при обновлении версии kubectl.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
🧑‍💻 5 базовых команд девопса

➡️ Команда wc -l считает строки в файле или в пайпе. Одна из тех вещей, которые используешь каждый день. Логи, CSV, исходники, конфиги.

Везде, где нужно быстро понять объём:
$ wc -l server.log
4821 server.log


Набирать wc -l несложно, но можно сделать ещё проще. Создаём алиас lc (line count) и добавляем в конфиг шелла:
# Добавьте в ~/.bashrc или ~/.zshrc, затем: source ~/.bashrc
alias lc='wc -l'


Теперь вместо wc -l пишем просто lc:
$ lc server.log
4821 server.log


Работает и с пайпами:
$ cat access.log | grep "500" | lc
37


37 пятисотых ошибок. Быстро и понятно.

➡️ du -sh * — сколько весит каждая папка

Когда заканчивается место на диске, первым делом хочется понять, кто его съел.

du -sh * покажет размер каждого элемента в текущей директории в человекочитаемом формате:
$ du -sh *
1.2G node_modules
4.0K README.md
256M dist
12K src


node_modules на первом месте. Как обычно.

Если нужно отсортировать по размеру, добавляем sort:
$ du -sh * | sort -rh
1.2G node_modules
256M dist
12K src
4.0K README.md


Флаг -r сортирует по убыванию, -h понимает суффиксы K, M, G.

➡️ xargs — передать результат одной команды как аргументы другой

xargs берёт строки из stdin и подставляет их как аргументы. Например, найти все .log файлы и удалить их:
$ find /tmp -name "*.log" | xargs rm


Если в именах файлов есть пробелы, безопаснее использовать разделитель через null:
$ find /tmp -name "*.log" -print0 | xargs -0 rm


Ещё полезный приём. Посчитать общее количество строк во всех Python файлах проекта:
$ find . -name "*.py" | xargs wc -l


➡️ column -t — превратить текст в ровную таблицу

Вывод многих команд выглядит как каша из слов, разделённых пробелами. column -t выравнивает столбцы и делает вывод читаемым:
$ cat data.txt
name age city
alice 30 berlin
bob 25 munich

$ column -t data.txt
name age city
alice 30 berlin
bob 25 munich


Хорошо работает с CSV, если указать разделитель:
$ column -t -s',' users.csv


➡️ watch — повторять команду каждые N секунд

watch запускает любую команду с заданным интервалом и обновляет вывод в терминале. По умолчанию интервал 2 секунды:
$ watch df -h


Эта команда будет каждые 2 секунды показывать состояние дисков. Удобно, когда ждёте, пока освободится место, или следите за каким-то процессом.

Можно изменить интервал через -n:
$ watch -n 5 kubectl get pods


Каждые 5 секунд обновляет статус подов. Проще, чем жать стрелку вверх и Enter раз за разом.

Все эти команды работают в любом Linux и macOS из коробки. Ничего ставить не нужно.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍5
📎 Ловим drift в Terraform автоматически

Кто-то поправил инфраструктуру руками через консоль. Terraform об этом ничего не знает. При следующем terraform apply начинаются конфликты, откаты и разбор полётов. Это называется drift. Состояние инфраструктуры разошлось с тем, что описано в коде.

Terraform сам по себе drift не отслеживает. Но у него есть инструмент, который помогает это делать.

Как обнаружить drift

У terraform plan есть флаг -detailed-exitcode. Он возвращает разные коды выхода в зависимости от результата.
terraform plan -detailed-exitcode


Код 0 означает, что изменений нет. Код 1 говорит об ошибке. А вот код 2 сигнализирует, что план нашёл расхождения между стейтом и реальной инфраструктурой. Именно код 2 и есть индикатор drift.

Проверять это вручную каждый раз неудобно. Гораздо надёжнее встроить проверку в CI. Например, в GitHub Actions это можно сделать так:
name: Drift Detection
on:
schedule:
- cron: '0 9 * * 1'

jobs:
detect-drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform plan -detailed-exitcode
continue-on-error: true
id: plan
- run: echo "Drift detected!"
if: steps.plan.outcome == 'failure' && steps.plan.outputs.exitcode == '2'


Этот воркфлоу запускается раз в неделю по понедельникам. Если plan вернул код 2, значит, кто-то менял инфру в обход Terraform. Аналогичную логику можно настроить и в Jenkins через проверку $? после выполнения команды.

Drift неизбежен в командах, где инфраструктурой занимается больше одного человека. Регулярная автоматическая проверка через CI помогает поймать расхождения до того, как они превратятся в проблему на проде.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32
🧑‍💻 su и sudo — в чём разница и когда что использовать

su и sudo дают доступ к привилегиям суперпользователя, но работают по-разному.

Что делает su

su (substitute user) переключает текущую сессию на другого пользователя. По умолчанию — на root. При вызове команда запрашивает пароль того пользователя, на которого вы переключаетесь.

После ввода пароля root вы получаете полноценную root-сессию. Все последующие команды выполняются от имени суперпользователя до тех пор, пока вы не выйдете через exit.

Если нужно переключиться с загрузкой окружения целевого пользователя, используйте форму с дефисом:
su -

Это загрузит переменные окружения, $HOME, $PATH и профиль root так, как если бы вы залогинились напрямую.

Что делает sudo

sudo (superuser do) выполняет одну конкретную команду с повышенными привилегиями. Пароль запрашивается ваш собственный, а не пароль root.

sudo apt update


Команда отработает от имени root, после чего вы вернётесь в свою обычную сессию. Никакого переключения пользователя не происходит.

Список пользователей, которым разрешено использовать sudo, и допустимые для них команды задаются в файле /etc/sudoers. Редактировать его нужно только через visudo, чтобы избежать синтаксических ошибок, которые могут заблокировать доступ.

Ключевые отличия

su требует знать пароль root. sudo требует только ваш пароль и запись в sudoers. Это принципиальная разница с точки зрения безопасности.

Раздавать пароль root нескольким администраторам — плохая практика. С sudo каждый работает под своей учёткой, а все действия логируются с привязкой к конкретному пользователю.

su открывает постоянную root-сессию. Забыли выйти — любая случайная команда выполнится с максимальными правами. sudo работает точечно, на одну команду, что снижает риск случайного повреждения системы.

Когда что использовать

sudo подходит для большинства задач администрирования. Обновить пакеты, перезапустить сервис, отредактировать конфиг — всё это удобнее и безопаснее делать через sudo.

su оправдан, когда нужно выполнить серию команд от root подряд, и переключение в полноценную root-сессию экономит время. Но даже в этом случае можно заменить его на:
sudo -i


Эта команда открывает интерактивную root-сессию через механизм sudo, без необходимости знать пароль root.

В современных дистрибутивах sudo стал стандартом. Ubuntu, например, по умолчанию вообще отключает вход под root и предлагает использовать только sudo.

Это безопаснее, прозрачнее для аудита и не требует распространения root-пароля. Используйте su только если точно понимаете, зачем вам полная root-сессия.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤‍🔥22
🛠 Переключение namespace в kubectl одной командой

Если вы работаете с Kubernetes, то наверняка устали дописывать -n my-namespace к каждой команде. Это раздражает, отнимает время и рано или поздно приводит к ошибке — забыли флаг, команда ушла в default, получили не тот результат.

Проблема решается одной строкой:
kubectl config set-context --current --namespace=<namespace>


Эта команда меняет namespace по умолчанию в текущем контексте вашего kubeconfig. После выполнения все последующие вызовы kubectl будут работать с указанным namespace без дополнительных флагов.

Допустим, вы работаете с namespace staging:
kubectl config set-context --current --namespace=staging


Теперь kubectl get pods покажет поды именно из staging. Не нужно писать kubectl get pods -n staging каждый раз.

Как проверить текущий namespace

Убедиться, какой namespace сейчас выставлен, можно так:
kubectl config view --minify --output 'jsonpath={..namespace}'


Если команда ничего не вернула, значит, используется default.

Что важно понимать

Настройка сохраняется в файле ~/.kube/config и действует не только на текущую сессию терминала. Она будет активна до тех пор, пока вы не переключитесь на другой namespace или не смените контекст.

Для тех, кто переключает namespace часто, есть утилита kubens из пакета kubectx. Она делает то же самое, но короче:
kubens staging


Мелочь, но экономит десятки лишних символов в день.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
👩‍💻 Bash-скрипт для мониторинга сервисов

Полноценный мониторинг вроде Zabbix или Prometheus не всегда оправдан, особенно на небольших проектах или dev-серверах. Иногда достаточно простого скрипта, который проверит список сервисов и скажет, что именно не работает.

Ниже готовый скрипт с проверкой через systemctl и отправкой уведомлений в Telegram.

Базовая версия

Создаём файл:
nano check_services.sh


Содержимое:
#!/bin/bash
SERVICES=("nginx" "postgresql" "redis" "ssh")

echo "===== СТАТУС СЕРВИСОВ ====="
echo ""

for SERVICE in "${SERVICES[@]}"; do
STATUS=$(systemctl is-active "$SERVICE" 2>/dev/null)
if [ "$STATUS" = "active" ]; then
echo "[OK] $SERVICE"
else
echo "[УПАЛ] $SERVICE"
fi
done


Даём права и запускаем:
chmod +x check_services.sh
./check_services.sh


Массив SERVICES правите под свой стек. Вывод будет примерно таким:

===== СТАТУС СЕРВИСОВ =====

[OK] nginx
[OK] postgresql
[УПАЛ] redis
[OK] ssh


Версия с уведомлением в Telegram

Базовая версия показывает результат в консоли. Но если скрипт работает по cron, вы его вывод не увидите. Добавим отправку сообщения в Telegram при обнаружении упавшего сервиса.

Для этого понадобится бот и chat_id. Бота создаёте через @BotFather, chat_id получаете через @userinfobot или из API бота после отправки ему любого сообщения.

#!/bin/bash
SERVICES=("nginx" "postgresql" "redis" "ssh")

BOT_TOKEN="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
CHAT_ID="987654321"

FAILED=""

for SERVICE in "${SERVICES[@]}"; do
STATUS=$(systemctl is-active "$SERVICE" 2>/dev/null)
if [ "$STATUS" != "active" ]; then
FAILED="${FAILED} ${SERVICE}\n"
fi
done

if [ -n "$FAILED" ]; then
HOSTNAME=$(hostname)
MESSAGE=" Проблема на ${HOSTNAME}\n\nУпавшие сервисы:\n${FAILED}"
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="$(echo -e "$MESSAGE")" \
-d parse_mode="HTML" > /dev/null
fi


Скрипт отправляет сообщение только когда что-то упало. Если все сервисы работают, он молчит и не спамит в чат.

Добавляем в cron

Открываем crontab:
crontab -e


Добавляем строку для проверки каждые 5 минут:
*/5 * * * * /path/to/check_services.sh


Что можно доработать

Скрипт намеренно простой, но его легко расширить. Например, добавить автоматический перезапуск упавшего сервиса через systemctl restart "$SERVICE" прямо в блоке проверки. Или писать результаты в лог-файл для истории. Если серверов несколько, можно запускать скрипт удалённо через ssh в цикле по списку хостов.

Для продакшена с десятками сервисов и серверов лучше смотреть в сторону полноценных решений. Но для пары серверов этот скрипт закрывает задачу за пять минут настройки.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82
🛠 Один файл, который избавит от рутины. Часть 1

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

Файл ~/.ssh/config решает эту проблему. Он позволяет описать все параметры подключения один раз и обращаться к серверу по короткому имени. Но это только начало. Через тот же файл настраиваются jump-хосты, автовыбор ключей, переиспользование соединений и многое другое.

В первой части разберём основы: алиасы, шаблоны и ProxyJump.

Как это устроено

~/.ssh/config читается при каждом вызове ssh, scp, sftp или rsync. Файл состоит из блоков Host, каждый из которых задаёт параметры для конкретного хоста или группы хостов по шаблону.

Если файла ещё нет, создайте его:
mkdir -p ~/.ssh
touch ~/.ssh/config
chmod 600 ~/.ssh/config


Структура простая:
Host staging
HostName 203.0.113.50
User ubuntu
Port 2222
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes


Теперь вместо длинной команды с кучей флагов достаточно написать:
ssh staging


То же самое работает с scp и rsync:
scp staging:/var/log/app.log ./
rsync -avz staging:/var/www/html/ ./backup/


Шаблоны и подстановки

Блок Host поддерживает wildcards. Например, чтобы задать настройки для всех продакшн-серверов:
Host *.prod.example.com
User ec2-user
IdentityFile ~/.ssh/id_ed25519_prod
ServerAliveInterval 60


Символ ? работает как подстановка одного символа. Host web-? совпадёт с web-1, web-a, но не с web-10.

Можно указать несколько имён в одном блоке:
Host web db cache
User ubuntu
IdentityFile ~/.ssh/id_ed25519_work


А через ! исключить конкретный хост:
Host * !bastion.prod.example.com
ServerAliveInterval 30


Блок Host * применяется ко всем подключениям и удобен для общих настроек. Важный момент: SSH читает файл сверху вниз и применяет первое совпавшее значение для каждой директивы. Поэтому конкретные блоки размещайте выше общих.

ProxyJump. Прозрачный доступ через bastion

Продакшн-серверы обычно закрыты от прямого доступа. Подключение идёт через bastion-хост. Без конфига это два шага: сначала SSH на bastion, потом оттуда на целевой сервер. С конфигом всё прозрачно:
Host bastion
HostName bastion.prod.example.com
User ubuntu
IdentityFile ~/.ssh/id_ed25519_prod

Host *.prod.internal
User ubuntu
IdentityFile ~/.ssh/id_ed25519_prod
ProxyJump bastion


Теперь ssh db.prod.internal автоматически пойдёт через bastion. Работает и с scp, и с rsync.

Для цепочки из нескольких jump-хостов перечислите их через запятую:
Host deep.internal
ProxyJump bastion.example.com,internal-gateway.example.com


В старых конфигах можно встретить ProxyCommand ssh -W %h:%p bastion.example.com. Это делает то же самое, но ProxyJump короче и понятнее. Для новых конфигов используйте его.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101
🛠 SSH Config. Ключи, производительность и отладка. Часть 2

В первой части мы разобрали алиасы, шаблоны и ProxyJump. Теперь — автовыбор ключей, переиспользование соединений и отладка.

Управление ключами

Если у вас несколько SSH-ключей, конфиг сам подберёт нужный:
Host *.work.example.com
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes

Host github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes


IdentitiesOnly yes запрещает SSH перебирать все ключи из агента. Без этой директивы можно получить отказ на серверах с низким MaxAuthTries.

Если на одной машине два GitHub-аккаунта, создайте алиасы github-personal и github-work с HostName github.com и разными ключами. В remote репозитория укажите алиас вместо github.com:
git remote set-url origin git@github-work:org/repo.git


Общие настройки

ControlMaster переиспользует открытое TCP-соединение вместо нового хендшейка. Keepalive не даёт файрволам закрывать неактивные сессии. ConnectTimeout ограничивает ожидание при подключении к недоступному хосту. Для медленных каналов (VPN, мобильный интернет) добавьте Compression yes.
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h:%p
ControlPersist 4h
ServerAliveInterval 60
ServerAliveCountMax 3
ConnectTimeout 10


Не забудьте mkdir -p ~/.ssh/sockets.

Отладка

ssh -G staging покажет итоговую конфигурацию без подключения. ssh -vvv staging выдаст подробный лог с информацией о том, какой блок совпал и какой ключ используется.

Частые проблемы: конфиг игнорируется из-за прав 644 вместо 600, SSH берёт не тот ключ без IdentitiesOnly yes, ControlMaster падает из-за несуществующей директории для сокетов. Правильные права:
chmod 700 ~/.ssh/
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/id_*


~/.ssh/config окупается за полчаса настройки. Этот файл стоит хранить в dotfiles-репозитории и обновлять при изменениях в инфраструктуре. По сути это рабочая документация о том, как устроен доступ к вашим серверам.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🛠 jq — инструмент, который экономит часы работы с JSON

Вместо поиска нужных полей через grep, awk и sed можно использовать jq.

🔤 Получить список подов:


bash kubectl get pods -o json | jq -r '.items[].metadata.name'


🔤 Найти поды не в статусе Running:


bash kubectl get pods -o json | jq -r ' .items[] | select(.status.phase != «Running») | .metadata.name'


🔤 Посчитать количество подов:


bash kubectl get pods -o json | jq '.items | length'


🔤 Вытащить значение поля:


bash echo '{"version»:"1.25"}' | jq -r '.version'


⚠️ Флаг -r убирает JSON-кавычки и часто спасает shell-скрипты от неожиданных ошибок.

Если работаете с Kubernetes, API или автоматизацией — jq быстро становится одной из самых полезных утилит в терминале

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥3👍2🎉1
📢 Навигация по каналу

Чтобы не теряться в потоке постов, собрали удобную навигацию по рубрикам:

#root_prompt — полезные команды, CLI-лайфхаки, однострочники и практические приёмы, которые можно сразу применять в работе

#архитектура_на_салфетке — схемы, диаграммы и инфографика по DevOps, Kubernetes, сетям, CI/CD и облачным технологиям

#разбор_полётов — анализ реальных инцидентов, постмортемов, крупных сбоев и технических кейсов с выводами

#пульс_индустрии — важные новости из мира DevOps, Cloud Native и платформенной инженерии с кратким разбором и контекстом

#арсенал_инженера — инструменты, сервисы, плагины и скрытые возможности Docker, Kubernetes, Git, Terraform, Ansible и других технологий

#локализация — переводы и краткие выжимки свежих зарубежных материалов, исследований и технических статей

#холиварня — опросы, дискуссии и вечные споры инженеров: Vim или VS Code, Kubernetes или Nomad, монолит или микросервисы

#dev_null — вопросы подписчиков, обсуждение рабочих ситуаций и обмен опытом внутри сообщества

#задача_со_звёздочкой — задачи с собеседований, практические кейсы и инженерные головоломки

#дайджест_недели — главные публикации канала, полезные ссылки и материалы за неделю в одном посте

#пятничный_деплой — мемы, юмор, забавные скриншоты и истории из жизни DevOps-инженеров

🔈 Используйте рубрики для быстрого поиска материалов и оставайтесь в курсе всего, что происходит в мире DevOps.

🐸 Библиотека devops'a
Please open Telegram to view this post
VIEW IN TELEGRAM
4🔥2
🔒 Запустите контейнер с минимально необходимыми правами


docker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
nginx


🔴 --cap-drop ALL отключает все Linux Capabilities.

🔴 --cap-add NET_BIND_SERVICE возвращает только право слушать привилегированные порты (<1024).

Чем меньше привилегий у контейнера — тем меньше потенциальная поверхность атаки.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt #docker #security
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2
Cron запускает скрипт повторно? Добавьте блокировку

Если задача по cron ещё не завершилась, а уже стартовал следующий запуск, можно получить несколько одновременно работающих экземпляров скрипта. Это приводит к конфликтам, лишней нагрузке и непредсказуемому поведению.

Решить проблему поможет lckdo из пакета moreutils

🔜 Установка:


sudo apt install moreutils


🔜 Запуск с блокировкой:


lckdo /tmp/my-script.lock /usr/local/bin/script.sh


Если предыдущий экземпляр ещё работает, новый запуск завершится сразу.

🔜 Чтобы дождаться освобождения блокировки, используйте:

```
lckdo -w /tmp/my-script.lock /usr/local/bin/script.sh```

💡 Частый сценарий — защита cron-задач:


* * * * * lckdo /tmp/backup.lock /usr/local/bin/backup.sh


Теперь новый запуск начнётся только после завершения предыдущего.

⚠️ Файл блокировки сам по себе ничего не блокирует. Блокировку удерживает процесс, который его открыл. После завершения процесса она автоматически снимается, даже если файл остаётся на диске.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
📍 Шпаргалка по циклам в Bash

Чтобы не держать в голове всю синтаксическую магию, собрали удобные примеры: for, while, until, диапазоны, чтение файлов и даже управление потоком с break и continue.

🈂️ Цикл for в Bash:


for i in /etc/*; do
echo $i
done

# То же самое (альтернативный синтаксис), также работает с другими видами циклов
for i in /etc/*
do
echo $i
done


🈂️ Цикл for, как в C:


for ((i = 0; i < 100; i++)); do
echo $i
done

# альтернативный синтаксис
for ((i = 0; i < 100; i++))
do
echo $i
done


🈂️ Цикл for с диапазонами:


for i in {1..10}; do
echo "Number: $i"
done

# С шагом
# ⇒ {НАЧАЛО..КОНЕЦ..ШАГ}
for i in {5..50..5}; do
echo "Number: $i"
done


🈂️ Цикл while в Bash:


# увеличение значения
i=1
while [[ $i -lt 4 ]]; do
echo "Number: $i"
((i++))
done

# уменьшение значения
i=3
while [[ $i -gt 0 ]]; do
echo "Number: $i"
((i--))
done


🈂️ Цикл while true:


# длинная форма while true
while true; do
# TODO
# TODO
done

# или короткая запись
while :; do
# TODO
# TODO
done


🈂️ Чтение файлов:


# использование пайпов
cat file.txt | while read line
do
echo $line
done

# ИЛИ использование перенаправления ввода
while read line; do
echo $line
done < "/path/to/txt/file"


🈂️ Оператор continue:


# команда seq может использоваться для генерации диапазонов
for number in $(seq 1 3); do
if [[ $number == 2 ]]; then
continue
fi
echo "$number"
done


🈂️ Оператор break:


for number in $(seq 1 3); do
if [[ $number == 2 ]]; then
# Пропустить оставшуюся часть цикла или выйти из цикла
break
fi
# Здесь выведется только 1
echo "$number"
done


🈂️ Цикл until:


# увеличение значения
count=0
until [ $count -gt 10 ]; do
echo "$count"
((count++))
done

# уменьшение значения
count=10
until [ $count -eq 0 ]; do
echo "$count"
((count--))
done


📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека devops'a

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉43🔥2