Helcode | Хелкод | Скрипты и автоматизация
993 subscribers
52 photos
34 links
☎️ Контакты для связи: @helcodeadm
Download Telegram
Мониторим изменения в файлах inotifywait

Нужно отслеживать изменения в файлах или директориях и автоматически выполнять действия (перезагружать сервис, запускать тесты и т.д.)?

inotifywait - утилита для отслеживания событий файловой системы

# Установка
sudo apt install inotify-tools

# Мониторим изменения в JS файлах
inotifywait -m -e modify,create,delete --format "%w%f" ./src/*.js |
while read file; do
echo "Файл $file изменен, перезагружаем сервер..."
pkill -f "node server.js"
node server.js &
done


🛠 Варианты использования:
- Автоперезагрузка dev-сервера
- Синхронизация файлов при изменении
- Запуск тестов при изменении кода

🌐 @helcode | #bash
👍2
Анализируем логи с awk

Нужно быстро проанализировать логи и получить статистику?

awk для сложной обработки текста

# Топ IP-адресов в access.log
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10

# Статистика HTTP-статусов
awk '{print $9}' access.log | sort | uniq -c | sort -nr

# Средний размер ответа по URL
awk '{sum[$7] += $10; count[$7]++} END {for (url in sum) print url, sum[url]/count[url]}' access.log


Преимущества:
➤ Работает с огромными файлами
➤ Гибкие условия фильтрации
➤ Можно считать суммы, средние, группировать

🌐 @helcode | #bash
👍4
Работаем с CSV в командной строке

Нужно быстро обработать CSV файл без открытия Excel?

Комбинация утилит для работы с CSV

# Установка csvkit для удобной работы
pip install csvkit

# Просмотр структуры
csvstat data.csv

# Фильтрация строк
csvgrep -c "status" -m "active" data.csv

# Выбор колонок
csvcut -c "name,email,phone" data.csv

# Сортировка
csvsort -c "date" -r data.csv

# А если нет csvkit - используем awk:
awk -F',' '$3 > 1000 {print $1 "," $3}' data.csv


Идеально для быстрого анализа данных, подготовки данных для скриптов

🌐 @helcode | #bash
👍3
Шифруем файлы с GPG

Нужно безопасно передать конфиденциальные файлы или хранить пароли?

Шифрование с помощью GPG

# Генерация ключевой пары
gpg --full-generate-key

# Шифрование файла для получателя
gpg --encrypt --recipient alice@company.com secret_document.txt

# Расшифровка
gpg --decrypt secret_document.txt.gpg > decrypted.txt

# Шифрование симметричным ключом (только пароль)
gpg --symmetric --cipher-algo AES256 file.txt


🛠 Лучшие практики:

➤ Используйте надежные парольные фразы
➤ Храните закрытый ключ в безопасном месте
➤ Для конфигов используйте симметричное шифрование

🌐 @helcode | #bash
👍2
Работа с API через curl

Нужно протестировать API или автоматизировать запросы?

curl с правильными заголовками и аутентификацией

# Базовый GET запрос
curl -X GET "https://api.example.com/users" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN"

# POST с JSON телом
curl -X POST "https://api.example.com/users" \
-H "Content-Type: application/json" \
-d '{"name": "John", "email": "john@example.com"}'

# Загрузка файла
curl -X POST "https://api.example.com/upload" \
-F "file=@document.pdf" \
-F "description=Important document"

# Сохраняем cookies для сессии
curl -c cookies.txt -X POST "https://api.example.com/login" \
-d "username=user&password=pass"


Полезные флаги:

-v для verbose вывода
--retry 3 для повторения при ошибках
--max-time 10 для таймаута

🌐 @helcode | #bash
👍3
Docker: оптимизация образов

Docker образы слишком большие и медленно собираются?

Многоступенчатая сборка и оптимизация слоев

# Многоступенчатая сборка для Python
FROM python:3.9-slim as builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

FROM python:3.9-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .

ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]


🛠 Советы по оптимизации:

➤ Используйте .dockerignore
➤ Объединяйте RUN команды
➤ Копируйте requirements.txt отдельно для кеширования
➤ Используйте легковесные базовые образы (alpine, slim)

🌐 @helcode | #docker
👍3
Продвинутый grep с контекстом

Нужно найти ошибку в логе и понять, что происходило до/после

grep с контекстом и дополнительными флагами

# Ищем ошибку с 5 строками контекста после
grep -A 5 "ERROR" application.log

# Контекст до и после
grep -B 3 -A 3 "NullPointerException" server.log

# Рекурсивный поиск с исключением директорий
grep -r "deprecated" ./src --include="*.js" --exclude-dir="node_modules"

# Поиск по шаблону в архивах
zgrep "login failed" /var/log/auth.log.*.gz

# Инвертированный поиск (строки БЕЗ шаблона)
grep -v "DEBUG" application.log


Экспорт результатов:
# Сохраняем с номерами строк
grep -n "critical" app.log > critical_errors.txt

# С цветным выводом в файл
grep --color=always "warning" app.log > warnings.txt


🌐 @helcode | #bash
👍61
Как мы настраивали кеширование в боте: TTLCache, ошибки и итоговый код

Рад всех приветствовать! В недавнем посте я показывал, как кешировать запросы к медленному API в Redis. Спасибо за ваши комментарии и реакции! Что ж, выполняю обещание - делюсь нашей историей.

Как и в том примере с Redis, наша задача была проста: не дёргать постоянно одни и те же данные, если они уже были получены. Но в нашем случае речь шла о внутренних операциях бота - результатах выполнения скриптов, поисковых запросах и списке категорий. Использовать для этого отдельный Redis-сервер показалось избыточным, и мы выбрали кеширование в оперативной памяти с помощью библиотеки cachetools.

Начало: идеальный план и первая ошибка...

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

Мы обрадовались, найдя простой и элегантный инструмент - TTLCache. Это как словарь, который автоматически удаляет старые записи по истечении их времени жизни (TTL).

Первый код был таким:

from cachetools import TTLCache

# Один кеш на всё (а кто знает, как оно себя поведёт, да?)
cache = TTLCache(maxsize=100, ttl=3600)


Ошибка №1: один кеш на все типы данных. Мы начали складывать в него и результаты скриптов, и поисковые выдачи, и списки категорий. Всё бы ничего, пока... пока мы не обновили список категорий. Новые категории не появляются, всё остается прежним после изменений. А всё потому, что бот отдавал устаревшие данные из кеша, который очищался только через час. Мы не могли просто взять и очистить весь кеш, потому что это убило бы и производительность поиска.

Решение: "разделяй и властвуй"

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

from cachetools import TTLCache

CACHE_SIZE = 500 # При увеличении скриптов установить значение ("1000" (5-10МБ RAM))
CACHE_TTL = 3600 # В случае редких изменений БД установить значение ("86400")

# Отдельные кеши
script_cache = TTLCache(maxsize=CACHE_SIZE, ttl=CACHE_TTL)
search_cache = TTLCache(maxsize=CACHE_SIZE, ttl=CACHE_TTL)
categories_cache = TTLCache(maxsize=CACHE_SIZE, ttl=CACHE_TTL)


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

Ошибка №2: "а оно нам надо?"

Первоначально мы выставили CACHE_TTL = 3600 (1 час) для всего, не задумываясь о реальной частоте изменений данных.

Проблема вот в чём: данные скриптов и категорий меняются очень редко - при обновлении функционала, то есть раз в несколько недель или месяцев. А мы заставляли память хранить их всего час и снова делать запросы к БД.

Решение: мы добавили комментарии в код, которые служат нам шпаргалкой. Теперь любой разработчик, глядя на константы, понимает: «Ага, скрипты стали реже обновляться, можно смело ставить TTL на сутки (86400), чтобы еще реже ходить в базу». Костыль? Полнейший, даже не спорю.

Финальный код и ещё один костыльный выход из ситуации

Вот наш финальный модуль cache.py, который живет в проекте:

from cachetools import TTLCache

CACHE_SIZE = 500 # при увеличении скриптов установить значение ("1000" (5-10МБ RAM))
CACHE_TTL = 3600 # в случае редких изменений БД установить значение ("86400")

script_cache = TTLCache(maxsize=CACHE_SIZE, ttl=CACHE_TTL)
search_cache = TTLCache(maxsize=CACHE_SIZE, ttl=CACHE_TTL)
categories_cache = TTLCache(maxsize=CACHE_SIZE, ttl=CACHE_TTL)

def clear_all_caches():
script_cache.clear()
search_cache.clear()
categories_cache.clear()


А эта функция clear_all_caches - спасение на тот случай, если нужно сбросить всё и сразу (например, после глобального обновления данных). Фактически, после крупных изменений, одна кнопка админском меню бота - и всё сбрасывается в ноль.

🌐 @helcode
👍41
Стоит, наверное, подвести небольшие итоги:

1. Инструмент: TTLCache - действительно хорошее решение для in-memory кеширования внутри приложения. Просто, эффективно, легко внедряется.
2. Тактика: не используйте один кеш для разнородных данных. Разделение кешей дает гибкость.
3. Время жизни: всегда анализируйте, как часто меняются ваши данные. TTL в 5 минут, час и сутки - это три огромные разницы.
4. Память: не забывайте следить за размером кеша (maxsize), особенно если храните много крупных объектов.

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

А у вас были интересные кейсы с кешированием? Сталкивались с неочевидными ошибками? Делитесь опытом в комментариях!

🌐 @helcode
👍3
Дрессируем терминал: история о том, как я приручил автодополнение

Представьте, Вы печатаете длинные пути вручную, как средневековый переписчик. А ведь терминал можно научить понимать вас с полуслова!

# Волшебная строка в ~/.inputrc
echo "set show-all-if-ambiguous on" >> ~/.inputrc
echo "set completion-ignore-case on" >> ~/.inputrc

# Теперь работает:
cd /u/sh/app [TAB] → cd /usr/share/applications
git ch[TAB] → git checkout
docker p[TAB] → docker ps


Живой пример:
"Раньше я тратил 10 секунд на ввод cd /var/log/nginx/. Теперь просто cd /v/l/n/[TAB] — и я уже там! За день экономлю 5-10 минут чистого времени."

Твоя задача: Добавь эти настройки и почувствуй себя волшебником терминала!

🌐 @helcode | #bash
👍64
Детективная история: как я нашел утечку памяти с помощью /proc

Сервер медленно умирал. Оперативка исчезала как деньги перед зарплатой. Виновник - загадочный процесс, пожирающий память.

# Расследование начинается:
cat /proc/meminfo # Общая картина преступления
ps aux --sort=-%mem | head -10 # Подозреваемые процессы

# Глубокий анализ подозреваемого:
ls -la /proc/1234/fd # Какие файлы открыл процесс?
cat /proc/1234/status # Подробное досье
cat /proc/1234/maps # Карта памяти процесса


Оказалось, скрипт на Python бесконечно добавлял данные в список и никогда их не очищал. lsof -p 1234 показал тысячи открытых файловых дескрипторов.

/proc - это детективное агентство для расследования проблем с процессами.

🌐 @helcode | #bash
🔥5👎1
Машина времени для данных: история о том, как btrfs спас мой проект

Сценарий: "Я случайно удалил папку с недельной работой. Руки дрожали, пот выступил на лбу. Но потом я вспомнил про btrfs..."

# Создаем снапшот:
btrfs subvolume snapshot /data /data/snapshots/backup_$(date +%Y%m%d)

# Список снапшотов:
btrfs subvolume list /data

# Возвращаемся во времени:
btrfs subvolume delete /data/work # Удаляем испорченное
btrfs subvolume snapshot /data/snapshots/backup_20240115 /data/work


Результат: все данные вернулись за 2 секунды! Теперь я делаю снапшоты перед любыми рискованными операциями.

Твоя очередь: если используешь btrfs - начни делать снапшоты. Если нет - возможно, пора перейти? 🕰

🌐 @helcode
👍2🗿2
Снайперская точность: как научиться убивать процессы по шаблону

Можно использовать killall как дробовик - стрелять по площади. Но зачастую это будет опасно:

# Дробовик (опасно!):
killall python # Убьет ВСЕ python процессы

# Более точно:
pkill -f "python data_processor.py" # Только конкретный скрипт

# Еще точнее — с проверкой:
pgrep -f "python data_processor.py" | xargs kill -TERM # Вежливая просьба :)
sleep 5
pgrep -f "python data_processor.py" | xargs kill -KILL # Принудительно :(


История из жизни: на продакшн-сервере killall java остановил не только проблемное приложение, но и три критичных сервиса. Минутная паника научила меня точности...

Всегда проверяй что убиваешь: pgrep -fl "pattern" покажет список целей.

🌐 @helcode | #bash
🔥7👌2
Цирк с конвейерами: обработка логов

Начальник попросил "быстро посчитать статистику по логам"? Коллеги судорожно открывают Excel? Сделаем это в терминале:

# Анализ access.log:
cat access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -10

# Топ-10 самых частых ошибок:
grep "ERROR" app.log | awk -F']' '{print $2}' | sort | uniq -c | sort -nr | head -10

# Время ответа по процентам
cat access.log | awk '{print $NF}' | sort -n |
awk '{
data[NR] = $1
} END {
print "50%: " data[int(NR*0.5)]
print "95%: " data[int(NR*0.95)]
print "99%: " data[int(NR*0.99)]
}'


Комбинируйте grep, awk, sort, uniq, это значительно ускорит и упростит работу с логами!

🌐 @helcode | #bash
👍51
Гадалка для сервера: как предсказывать проблемы до их появления

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

#!/bin/bash
# crystal_ball.sh - мой хрустальный шар

# Предсказание дисковых проблем:
df -h | awk '$5 > 80 {print "ВНИМАНИЕ: " $6 " заполнен на " $5}'

# Предсказание нехватки памяти:
free -h | grep Mem | awk '{if ($3/$2 * 100 > 85) print "Скоро закончится память!"}'

# Предсказание сетевых проблем:
netstat -an | grep :80 | wc -l |
awk '{if ($1 > 1000) print "Слишком много подключений к порту 80"}'

# Предсказание перегруза CPU:
uptime | awk '{if ($(NF-2) > 5.0) print "Система перегружена! Load average: " $(NF-2)}'


Кейс из жизни: подобная "гадалка" предупредила о заполнении диска за 2 для до "катастрофы". Вовремя почистили логи и избежали простоя.

🌐 @helcode | #bash
👍9❤‍🔥1
Театр одного актера: автоматизируем рутину с tmux

Зачем судорожно переключаться между 10 терминалами. Глянем на tmux:

# Создаем рабочее пространство:
tmux new-session -s "monitoring" -d
tmux new-window -t "monitoring:1" -n "logs"
tmux new-window -t "monitoring:2" -n "metrics"

# Настраиваем панели:
tmux split-window -h -t "monitoring:logs"
tmux split-window -v -t "monitoring:logs.0"

# Запускаем команды в панелях:
tmux send-keys -t "monitoring:logs.0" "tail -f /var/log/nginx/access.log" Enter
tmux send-keys -t "monitoring:logs.1" "htop" Enter
tmux send-keys -t "monitoring:logs.2" "docker ps -a" Enter

# Подключаемся к сессии:
tmux attach -t "monitoring"


Одно подключение по SSH - и все нужные окна уже работают. Выход из сервера - сессия сохраняется. Возвращение - всё на своих местах!

🌐 @helcode | #bash
👍5🥰1
"Шпионские страсти": как я отлаживал таинственные сетевые проблемы

Приложение периодически "зависало". Логи чистые. Что происходит?

# Прослушивание сети (требует прав):
tcpdump -i any -w capture.pcap host 192.168.1.100 and port 5432

# Анализ трафика:
tcpflow -r capture.pcap -C

# Или проще - в реальном времени:
ngrep -d any port 8080

# Мониторинг конкретного процесса:
strace -f -p 1234 -e trace=network

# Проверка DNS:
dig @8.8.8.8 myapi.com # Обход локального кеша


Оказалось, приложение раз в 5 минут делало DNS-запрос, который иногда таймаутился на 30 секунд! strace показал вызовы connect(), которые висели подозрительно долго.

Когда логи молчат - слушаем сеть!

🌐 @helcode | #bash
🔥6👍2🥰1
Искусство седа

Представим, что необходимо обработать 1000 CSV файлов, а именно: удалить столбцы, переименовать заголовки, фильтровать строки. Ручной труд = недели работы, а с sed - вполне реализуемо за 1 вечер.

# Удаляем столбцы 2 и 4 из CSV:
sed -i 's/^\([^,]*\),[^,]*,\("[^"]*"\|[^,]*\),[^,]*/\1,\3/' file.csv

# Переименовываем заголовки:
sed -i '1s/old_name/new_name/g; 1s/another_old/another_new/g' *.csv

# Фильтруем строки по дате:
sed -n '/2024-01-15/p' large_file.log > filtered.log

# Массовая замена в файлах проекта:
find . -name "*.py" -exec sed -i 's/MySQL/PostgreSQL/g' {} +


Бонусный "трюк":
# Конвертируем JSON в CSV (упрощенно):
echo '{"name":"John","age":30}' | sed 's/{//g; s/}//g; s/":"/,/g; s/","/\n/g'


sed - это не просто "замена текста", это полноценный текстовый трансформер!

🌐 @helcode | #bash
👍121
Защита SSH: практические меры безопасности

Коллеги, хочу попробовать новый "формат" постов, аля "практический кейс". Следующие 4 поста будут подобны данному, в качестве эксперимента. Буду рад получить обратную реакцию по подобному "формату"! Приступим...

Цель: повысить безопасность SSH-доступа к серверам

Проблема: стандартные настройки SSH уязвимы для брут-форс атак и несанкционированного доступа

Решение: многоуровневая защита SSH

# 1. Смена порта и ограничение доступа
# /etc/ssh/sshd_config
Port 58222 # Нестандартный порт
PermitRootLogin no
PasswordAuthentication no # Только по ключам
MaxAuthTries 3
ClientAliveInterval 300

# 2. Настройка fail2ban для блокировки атак
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 58222
maxretry = 3
bantime = 3600

# 3. Ограничение доступа по IP
iptables -A INPUT -p tcp --dport 58222 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 58222 -j DROP

# 4. Двухфакторная аутентификация (Google Authenticator)
# Установка и настройка:
sudo apt install libpam-google-authenticator
google-authenticator # Следуйте инструкциям

# Добавить в /etc/ssh/sshd_config:
AuthenticationMethods publickey,keyboard-interactive


Проверка настроек:
# Тестирование конфигурации
sshd -t
systemctl reload sshd

# Мониторинг подключений
netstat -tulpn | grep :58222
fail2ban-client status sshd


Рекомендации:
- Регулярно обновлять SSH-ключи
- Использовать ключи длиной не менее 4096 бит
- Настроить мониторинг неудачных попыток входа

🌐 @helcode | #bash
8👍6
Мониторинг производительности: от сбора метрик до визуализации

Цель: настроить полноценную систему мониторинга серверной инфраструктуры

Архитектура: Node Exporter + Prometheus + Grafana

Установка Node Exporter
# Скачивание и установка
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
tar xzf node_exporter-*.tar.gz
sudo mv node_exporter-*/node_exporter /usr/local/bin/

# Создание systemd сервиса
sudo cat > /etc/systemd/system/node_exporter.service << EOF
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=multi-user.target
EOF

# Запуск
sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter


Настройка Prometheus
# prometheus.yml
global:
scrape_interval: 15s

scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['node1:9100', 'node2:9100']
metrics_path: /metrics


Дашборды Grafana
# Импорт готовых дашбордов
# Node Exporter Full: id 1860
# Kubernetes cluster monitoring: id 315


Полезные запросы PromQL:
# Использование CPU
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# Доступная память
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100

# Использование диска
100 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} * 100)


🌐 @helcode
1👍1