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

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

Учиться у нас: https://proglib.io/w/25874ec4

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

РКН: https://gosuslugi.ru/snet/6798b4e4509aba56522d1787
Download Telegram
👨‍💻 npm install в CI/CD это риск

Атака на axios в марте 2025 года показала простую вещь: если ваш пайплайн использует npm install, он каждый раз ходит в живой реестр npm и разрешает диапазоны версий заново. Это открывает окно для подмены пакета.

Если в package.json написано "axios": "^1.7.9", npm install может поставить 1.14.1 — версию, которой не было в вашем lockfile. Вредоносную версию, опубликованную 31 марта, многие поставили именно так.

Почему npm ci безопаснее

npm ci устанавливает ровно то, что записано в package-lock.json. Если lockfile расходится с package.json — упадёт с ошибкой. В реестр за новыми версиями не ходит. Новый вредоносный пакет попасть не может, пока вы сами не обновите lockfile.

Как заменить в CI/CD:
# Было
- name: Install dependencies
run: npm install

# Стало
- name: Install dependencies
run: npm ci


Бонус — скорость

npm ci удаляет node_modules и ставит заново, без попытки согласовать существующее состояние. Это быстрее на 20–40% по сравнению с npm install.

Это одно изменение — и ваш пайплайн уже не подхватит внезапно опубликованную вредоносную версию. Lockfile при этом нужно хранить в репозитории и обновлять осознанно, а не позволять CI делать это автоматически.

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

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

#арсенал_инженера
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
⚙️ Гарантированная очистка даже после краша

Скрипт упал с ошибкой, а временный файл остался. Или соединение не закрылось. Или lock-файл завис. Это классика и trap решает её в одну строчку.

Что делает trap

Регистрирует функцию, которая запустится при выходе из скрипта — неважно, нормальном или аварийном.

Вы один раз описываете логику очистки и забываете об этом:
#!/bin/bash
set -euo pipefail

tmpfile=$(mktemp)

cleanup() {
rm -f "$tmpfile"
echo "Cleaned up temporary files"
}

trap cleanup EXIT # сработает при любом выходе

# Основная работа
echo "Processing..." > "$tmpfile"
cat "$tmpfile"


EXIT это сигнал, который bash отправляет при завершении скрипта. Функция cleanup удалит временный файл, даже если скрипт упал на середине.

Что можно убирать через trap

Временные файлы и директории, lock-файлы, открытые соединения с базой, фоновые процессы, которые скрипт запустил сам.

Почему это лучше, чем rm в конце скрипта

rm в конце не выполнится, если скрипт упадёт раньше. trap cleanup EXIT выполнится всегда — это гарантия на уровне интерпретатора.

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

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

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
6
😎 Топ-вакансий для девопсов за неделю

Junior DevOps engineer — от 100 000 ₽, удалёнка

Middle/Senior DevOps Engineer — до 4 500 €, гибрид в Алматы или Белграде

DevOps — до 400 000 ₽, удалёнка

➡️ Еще больше топовых вакансий — в нашем канале Devops Jobs

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

#вакансия_недели
Please open Telegram to view this post
VIEW IN TELEGRAM
😢1
⚙️ Защита от случайного удаления

Вы хотя бы раз случайно удаляли не тот файл через rm -rf? Это случается даже с опытными разработчиками. Один неверный путь и данные пропали.

Простая обёртка над rm решает эту проблему без установки сторонних утилит:
rm() {
ls -FCsd -- "$@"
read -p 'Delete? [y/N] ' ans
if [ "$ans" = "y" ]; then
command rm -rf -- "$@"
fi
}


Функция перехватывает вызов rm, показывает список файлов и спрашивает подтверждение. Если не ответить y, то ничего не удалится.

Добавьте функцию в ~/.bashrc или ~/.zshrc и перезагрузите конфиг:
source ~/.bashrc


Подтверждение помогает, но файлы всё равно удаляются сразу. Если хочется подстраховаться ещё раз, можно сделать подобие корзины: перемещать файлы во временную папку вместо немедленного удаления:
rm() {
local trash="/tmp/.trash"
mkdir -p "$trash"
ls -FCsd -- "$@"
read -p 'Move to trash? [y/N] ' ans
if [ "$ans" = "y" ]; then
mv -- "$@" "$trash"
echo "Moved to $trash"
fi
}


Файлы будут лежать в /tmp/.trash до следующей перезагрузки или ручной очистки. Это даёт время одуматься.

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

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

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🌎 Фиксируйте версии зависимостей

Многие думают, что package-lock.json уже дает воспроизводимые сборки. На практике npm install может подтянуть новые версии из диапазонов ^ и ~, если кто-то запустит команду в неподходящий момент.

Было:
{
"dependencies": {
"axios": "^1.7.9", // любой 1.x.x
"express": "~4.18.0", // только 4.18.x
"react": "^19.0.0" // любой 19.x.x
}
}


Стало:
{
"dependencies": {
"axios": "1.7.9",
"express": "4.18.2",
"react": "19.0.0"
}
}


Безопасность патчей

"А как же security updates?" Лучше получать их осознанно через PR, чем во время сборки. Автоматические обновления приносят не только фиксы, но и риски сломать проект.

Dependabot или Renovate создают pull request с обновлениями. Команда проверяет diff, прогоняет тесты, мерджит вручную.

Что делать

1. Убрать все ^ и ~ из package.json
2. Зафиксировать точные версии (npm i package@x.y.z)
3. Настроить Dependabot/Renovate
4. Проверять все обновления тестами

Такая схема убирает магию из сборки. Проще дебажить релизы и ловить настоящие баги.

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

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

#арсенал_инженера
Please open Telegram to view this post
VIEW IN TELEGRAM
🧑‍💻 Скрипт молчит и это проблема

Каждый раз, когда команда завершается в Linux, она возвращает число от 0 до 255. Это единственный способ скрипта сказать миру: «всё окей» или «что-то пошло не так».

0 это успех. Всё остальное — ошибка.

Что происходит без системы

Скрипт упал с кодом 1. Что это значит? Непонятно. Другой скрипт упал с 1. Тоже непонятно и это уже другой скрипт. CI/CD pipeline ловит ошибку и не знает, что делать дальше. Дебаггинг превращается в угадайку.

Как сделать нормально: диапазоны

Разбейте коды на логические группы:
0       -> успех
1-9 -> общие ошибки
10-19 -> плохие аргументы / входные данные
20-29 -> ошибки файловой системы
30-39 -> сеть
40-49 -> права доступа
50-99 -> внутренние ошибки


Коды 126-255 зарезервированы системой. Не трогайте.

Дайте кодам имена

Не пишите exit 20. Напишите так:
EXIT_FILE_NOT_FOUND=20
EXIT_PERMISSION_DENIED=40
EXIT_NETWORK_FAIL=30


Скрипт становится самодокументируемым. Через полгода вы скажете себе спасибо.

Вынесите коды в отдельный файл

Если скриптов несколько, то создайте exit_codes.sh и подключайте его через source exit_codes.sh.

Всегда проверяйте внешние команды:
cp file1 file2
if [ $? -ne 0 ]; then
echo "Копирование не удалось" >&2
exit $EXIT_FILE_WRITE_ERROR
fi


Никогда не игнорируйте статус выхода внешних команд. Молчаливые ошибки это худшие ошибки.

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

Маленькая деталь, которая отличает скрипт на коленке от production-ready инструмента.

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

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

#арсенал_инженера
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
⚡️ Три полезных алиаса для сети

Эти bash-алиасы упрощают проверку IP и портов. Добавьте их в ~/.bashrc или ~/.zshrc, перезапустите терминал.

Внешний IP одним словом:
myip() {
curl -s ifconfig.me
}


IP домена быстро:
ipinfo() {
dig +short "$1"
}


Открытые порты:
ports() {
ss -tuln
}


Скопируйте функции в файл настроек. Теперь myip, ipinfo google.com и ports работают из коробки.

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

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

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
⚙️ Теперь можно объяснить системе, почему она ошибается

Вышел APT 3.2. Главная новость не в истории транзакций, хотя и она там есть, а в двух новых командах, которых не хватало годами.

apt why <пакет> показывает, почему пакет установлен: кто его потянул, через какую цепочку зависимостей, какой solver принял решение.

apt why-not <пакет> объясняет, почему пакет не ставится: какой конфликт мешает, какое ограничение блокирует.

Пять новых команд для работы с прошлыми операциями:

apt history-list — список всех транзакций
apt history-info — детали конкретной
apt history-undo / apt history-redo — отменить или повторить
apt history-rollback — откат к более раннему состоянию системы

Solver3 стал умнее: доработаны backtracking, обработка провайдеров и логика выбора пакетов при апгрейде. Добавлена поддержка вариантов архитектуры CPU (amd64v2, amd64v3, amd64v4) - через поле Architecture: или настройку APT::Architecture-Variants. В файлах .sources появились поля Include и Exclude для фильтрации компонентов репозитория. Система больше не засыпает во время работы dpkg.

➡️ Источник

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

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

#пульс_индустрии
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
✏️ Вопрос с собеса по Kubernetes

Что
даёт RollingUpdate с maxUnavailable: 0 и maxSurge: 1 в Deployment

strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1


Два параметра, которые вместе определяют как именно Kubernetes будет катить обновление. maxUnavailable говорит сколько подов может быть недоступно в процессе, maxSurge говорит сколько лишних подов можно поднять сверх желаемого количества.

Ответ: спрятали тут

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

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

#задача_со_звёздочкой
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
👨‍💻 Убить процесс на порту одной командой

Знакомая ситуация: запускаем дев-сервер и получаем address already in use, идём гуглить как найти и убить процесс.

port-kill
решает это в одну команду:
# Убить что угодно на порту 3000
port-kill 3000

# Сразу несколько
port-kill 3000 5000 8080

# С подтверждением
port-kill 3000 --safe


Инструмент вырос далеко за пределы «убить порт». Умный рестарт запоминает команду, которой запустился процесс, и может поднять его снова:
port-kill --restart 3000
port-kill --show-restart-history


Обнаружение сервисов само находит npm-скрипты, docker-compose, Procfile и Python-приложения в текущем проекте:
port-kill --detect
port-kill --start npm:dev
port-kill --start docker:web


Установить:
curl -fsSL portkill.com/install | bash


➡️ Репозиторий

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

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

#арсенал_инженера
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
🔄 Новая директива, совместимость с OpenSSL 4.0 и два бага

Вышел nginx 1.29.8. Посмотрим что нового.

Добавлена директива max_headers. Она ограничивает максимальное количество HTTP-заголовков в запросе. При превышении лимита сервер возвращает 400 Bad Request. Идея пришла из FreeNginx.

Добавлена совместимость с OpenSSL 4.0, альфа которого вышла недавно.

Директива include внутри блока geo теперь поддерживает wildcards.

Починили обработку HTTP-ответов с кодом 103 от проксируемых бэкендов. Исправлена недоступность переменных $request_port и $is_request_port в субзапросах.

➡️ Источник

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

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

#пульс_индустрии
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Разрабатываете ИИ-агентов, но всё ещё не уверены в их стабильности и прогнозируемости?

Мы поговорили с десятками разработчиков ИИ-агентов и сделали отдельный курс по AgentOps.

🧠 На нём вы узнаете:

– как оптимизировать траты на токены;
– как на практике оценить качество работы агента;
– как «докручивать» RAG-системы без потери качества;
– как обеспечить устойчивость агента к сбоям внешних сервисов без падения всей системы и про многое-многое другое.

📅 Старт: 19 мая.

👥 Спикеры — практики с опытом в AI и Data Science в крупных IT-компаниях, таких как Яндекс, Huawei, МТС и др.

Длительность: 6-12 недель в зависимости от тарифа.


🔗 Программа курса и другие подробности
⭐️ Little Snitch вышел для Linux

Авторы macOS-файрвола Little Snitch выпустили версию для Linux. Инструмент показывает, какие процессы и куда подключаются, и позволяет блокировать соединения в один клик.

Перехват трафика реализован через eBPF на уровне ядра. Основной код написан на Rust, интерфейс сделан как веб-приложение.

Little Snitch для Linux не является инструментом безопасности в полном смысле. eBPF имеет ограничения, и обойти файрвол технически возможно.

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

➡️ Источник | Инструмент

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

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

#арсенал_инженера
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🔄 Релизная неделя

Вспоминаем и освежаем все релизы недели

GNU nano 9.0

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

GParted Live 1.8.1-3

Релиз построен на свежем снапшоте Debian Sid от 4 апреля и включает ядро Linux 6.19.10-1. Из заметного: исправлена ложная детекция ZFS на целых дисках через blkid, починены контрольные суммы файлов внутри live-системы: вместо sha256 теперь используется b3sum.

SQLite 3.53.0

Главное в этом релизе: исправление серьёзного бага повреждения базы в режиме WAL, который появился ещё в 3.51.

Linux 7.0 уже скоро

Вышел APT 3.2

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

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

#дайджест_недели
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯 Представьте, что ваш AI-агент работает так же предсказуемо, как обычный микросервис. Звучит утопически, но это именно то, к чему должна прийти разработка в 2026 году.

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

Наш обновлённый курс «Разработка AI-агентов» научит, как приручить этот хаос с помощью Python и современных фреймворков. Мы не будем учить «общаться» с нейросетью, мы будем строить из неё надёжный инструмент.

Что вы получите:


— понимание того, как управлять логикой агента на уровне кода;
— навыки работы с LangChain и библиотеками оркестрации;
— готовые паттерны для обработки ошибок и галлюцинаций;
— опыт создания систем, которые реально экономят время.

Есть пара мест со скидкой до завтра, решайтесь 👈🏻
😁1
🛠 Одна функция вместо десяти команд

Каждый раз, когда нужно распаковать архив, начинается одно и то же. Это tar.gz или tar.bz2? Какие там флаги у unrar? А 7z вообще как запускается? Приходится лезть в документацию или историю команд. Самописная функция extract() решает именно эту проблему.

Скопируйте функцию в ~/.bashrc или ~/.zshrc:

extract() {
if [ -f "$1" ]; then
case "$1" in
*.tar.bz2) tar xjf "$1" ;;
*.tar.gz) tar xzf "$1" ;;
*.bz2) bunzip2 "$1" ;;
*.rar) unrar x "$1" ;;
*.gz) gunzip "$1" ;;
*.tar) tar xf "$1" ;;
*.tbz2) tar xjf "$1" ;;
*.tgz) tar xzf "$1" ;;
*.zip) unzip "$1" ;;
*.7z) 7z x "$1" ;;
*) echo "unknown archive" ;;
esac
fi
}


Потом применяете изменения:
source ~/.bashrc


Функция определяет тип архива по расширению файла и сама выбирает нужную команду. Вы просто пишете extract имя_файла и получаете распакованное содержимое. Без флагов, без гугления, без ошибок из-за опечатки в параметрах.

Поддерживаемые форматы: tar.gz, tar.bz2, bz2, rar, gz, tar, tbz2, tgz, zip, 7z.

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

Что можно добавить

Базовая версия уже полезна, но её можно немного доработать. Например, добавить проверку, что нужная утилита вообще установлена, или выводить имя команды перед запуском. Вот расширенный вариант:
extract() {
if [ ! -f "$1" ]; then
echo "'$1' не найден"
return 1
fi

case "$1" in
*.tar.bz2) tar xjf "$1" ;;
*.tar.gz) tar xzf "$1" ;;
*.bz2) bunzip2 "$1" ;;
*.rar) unrar x "$1" ;;
*.gz) gunzip "$1" ;;
*.tar) tar xf "$1" ;;
*.tbz2) tar xjf "$1" ;;
*.tgz) tar xzf "$1" ;;
*.zip) unzip "$1" ;;
*.7z) 7z x "$1" ;;
*) echo "Формат не поддерживается: '$1'" ; return 1 ;;
esac
}


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

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

#root_prompt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
👨‍💻 Минимум, который должен быть в каждом репозитории

Ручная проверка изменений в зависимостях не работает при любом серьёзном темпе разработки. Когда в PR меняется lockfile на тысячу строк, никто не будет вручную проверять каждый пакет. Именно так проскакивают вредоносные версии.

Минимальная настройка

• Dependabot для GitHub

Включите в настройках репозитория: Settings → Security → Dependabot. Потом добавьте конфиг:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "security"


Dependabot будет создавать PR с обновлениями раз в неделю и автоматически помечать их нужными лейблами.

• npm audit в CI

Добавьте шаг в пайплайн и запускайте его до тестов, а не после:
- name: Security audit
run: npm audit --audit-level=high


Флаг --audit-level=high завалит сборку только при уязвимостях уровня high и critical. Мелкие предупреждения не будут блокировать работу, но серьёзные проблемы не пройдут незамеченными.

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

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

#арсенал_инженера
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
23 апреля в 18:30 (мск) пройдёт офлайн-митап MWS Cloud Platform «Под капотом: инфраструктура». Также будет онлайн-трансляция. В программе доклады инженеров, которые ежедневно решают нетривиальные задачи при работе над инфраструктурными сервисами облака. 

Вы сможете:

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

После основной части — нетворкинг и угощения. Регистрируйтесь на митап! Это возможность обсудить нюансы, которые всплывают только в продакшене, и будут полезны на практике.

🗓23 апреля, начало в 18:30
📍Москва, Дом Культур, ул. Сретенка, 25

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

Зарегистрироваться
1🤔1
🎮 DOOM прямо в терминале через curl

Кто-то сделал DOOM, который запускается через curl и рендерится в терминале ANSI-символами. Никаких зависимостей, никакого GUI — только браузер терминала и HTTP.

Как запустить:
curl -sL http://localhost:3000 | bash


Есть и второй вариант: без bash, чистым curl. Но тут придётся вручную переключить терминал в raw mode, иначе curl не увидит нажатие клавиши до Enter:
stty -echo -icanon min 1 time 0 && curl -sN -X POST -T - localhost:3000/play


После игры терминал нужно починить командой reset.

Сессии без активности удаляются через 60 секунд. Игра стартует сразу с E1M1 на сложности «Hurt me plenty», без меню.

➡️ Репозиторий

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

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

#пульс_индустрии
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2