Helcode | Хелкод | Скрипты и автоматизация
992 subscribers
52 photos
34 links
☎️ Контакты для связи: @helcodeadm
Download Telegram
sshfs — монтируем удалённую файловую систему как локальную

Копировать файлы по scp туда-сюда для редактирования, или открывать их через промежуточный sftp в редакторе - это оверхед. sshfs (SSH Filesystem) позволяет смонтировать удалённую директорию по SSH как обычный локальный диск. Можно редактировать файлы прямо на сервере любым локальным редактором, без синхронизации.

Удалённые файлы не должны чувствоваться удалёнными. Инструменты должны стирать границы.

Вариант 1 (Базовое монтирование): монтируем домашнюю директорию сервера в локальную папку.
sshfs user@server:/home/user /mnt/remote-server


Вариант 2 (Монтирование с ключом и опциями): использование SSH-ключа и сжатия для медленных каналов.
sshfs -o Compression=yes,IdentityFile=~/.ssh/id_rsa user@server:/var/www /mnt/www


Вариант 3 (Автоматическое монтирование при доступе): настройка в /etc/fstab с использованием sshfs (потребуется ключ без пароля или sshpass).
user@server:/remote/path /local/mountpoint fuse.sshfs noauto,x-systemd.automount,_netdev,users,identityfile=/home/user/.ssh/id_rsa,allow_other,reconnect 0 0


Вариант 4 (Размонтирование):
fusermount -u /mnt/remote-server


sshfs - это автоматизация прозрачного доступа к удалённым данным. Он основан на FUSE (Filesystem in Userspace) и использует стандартный SSH-протокол, то есть не требует ничего, кроме работающего SSH-сервера на целевой машине.

Это незаменимая вещь для разработки, когда код лежит на сервере, или для администрирования, когда нужно просматривать/редактировать логи и конфиги в привычном редакторе.

P.S. Будьте осторожны с редактированием бинарных файлов или баз данных через sshfs - возможны проблемы с блокировками. Для конфигов и скриптов - идеально.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍71
nethogs — кто съел весь интернет?

iftop показывает общую нагрузку на интерфейс, nload - графики скорости. Но когда трафик неожиданно вырастает, хочется знать не *сколько*, а *кто* именно. nethogs разбивает трафик по процессам: показывает PID, имя программы и скорость загрузки/отдачи для каждого процесса.

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

Вариант 1 (Базовый запуск): запуск без аргументов показывает все процессы на всех интерфейсах.
sudo nethogs


Вариант 2 (Выбор интерфейса): следим только за внешним интерфейсом.
sudo nethogs eth0


Вариант 3 (Интервал обновления): медленное обновление для длительного наблюдения.
sudo nethogs -d 5 eth0
# -d 5: обновление каждые 5 секунд


Вариант 4 (Режим просмотра): переключение между суммарным и поточным отображением клавишей m.

nethogs - это автоматизация привязки сетевого трафика к конкретным процессам. Он отвечает на вопрос, на который iftop ответить не может: «Какая программа так активно качает?».

Полезно как для серверов (поиск утекшего трафика, подозрительной активности), так и для рабочих станций (почему тормозит интернет, что за процесс обновляется).

P.S. nethogs требует прав root для просмотра процессов других пользователей. Запускайте через sudo.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51🔥1
script — запись сессии терминала для документации или разбора инцидента

Сделали сложную последовательность действий, которая привела к починке системы. Через месяц потребуется повторить, а Вы уже не помните детали. Или нужно показать коллеге точную последовательность команд и их вывод. script записывает всё, что происходит в терминале - и ввод, и вывод - в файл.

Память человека - ненадёжный носитель. Сессия терминала, записанная в файл, - надёжный.

Вариант 1 (Простая запись): запуск script начинает запись, exit завершает.
script session.log
# ... делаем что-то важное ...
exit
# Всё сохранено в session.log


Вариант 2 (Запись с меткой времени): полезно для расследования инцидентов, чтобы понимать, в какой момент что произошло.
script --timing=timing.txt session.log
# Позже можно воспроизвести сессию с реальными задержками
scriptreplay --timing=timing.txt session.log


Вариант 3 (Тихий режим): запись без сообщений о начале и конце.
script -q session.log


Вариант 4 (Дозапись): добавление к существующему логу.
script -a session.log


script - это автоматизация документирования работы в терминале. Он превращает хаотичную сессию администрирования в структурированный лог, который можно:
➤ Приложить к постмортему.
➤ Использовать для обучения новых сотрудников.
➤ Разобрать, чтобы понять, какая именно команда что-то сломала.
➤ Воспроизвести для демонстрации.

P.S. script записывает даже управляющие последовательности (цвета, позиционирование курсора), поэтому файл может содержать "мусор". Для просмотра лучше использовать cat или less -R, чтобы видеть оригинальное форматирование.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥52
shellcheck — статический анализ для ваших bash-скриптов

Bash-скрипт написан, работает... но почему-то падает на пустых переменных или некорректно обрабатывает пробелы в именах файлов. shellcheck - это линтер для shell-скриптов, который находит сотни потенциальных ошибок, уязвимостей и неэффективностей, объясняя, что именно не так и как это исправить.

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

Вариант 1 (Базовая проверка): просто запустить shellcheck на скрипте.
shellcheck deploy.sh


Вариант 2 (Интеграция в редактор): плагины для VS Code, Sublime, Vim подсвечивают проблемы прямо во время написания кода.

Вариант 3 (Интеграция в CI/CD): добавление шага в пайплайн, который проверяет все .sh файлы. Если скрипт содержит ошибки — пайплайн падает.
# Пример для GitLab CI
shellcheck:
script:
- apt-get install -y shellcheck
- shellcheck *.sh


Вариант 4 (Подавление предупреждений): иногда нужно отключить конкретную проверку, если Вы точно знаете, что делаете.
# shellcheck disable=SC2086
some_command $variable # SC2086: Double quote to prevent globbing and word splitting


shellcheck - это автоматизация повышения качества и надёжности скриптов. Он превращает написание bash-скриптов из шаманства в инженерную дисциплину с обратной связью от инструмента.

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

P.S. У shellcheck есть онлайн-версия (shellcheck.net), куда можно скопировать код и мгновенно увидеть все проблемы. Полезно, если нет возможности установить локально.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥82🤔1👌1
systemd: сервисы, которые умеют себя обслуживать

Писать скрипты на Bash для запуска демонов и их перезапуска при падении — это изобретение велосипеда. systemd — это фреймворк для управления жизненным циклом служб со встроенными возможностями самовосстановления.

Скрипт в /etc/init.d/, который не умеет корректно обрабатывать сигналы и логировать, — это наследие прошлого.

➤ Вариант 1 (Базовая устойчивость): простая конфигурация юнита с Restart=on-failure и RestartSec=5 уже делает сервис намного надежнее.

[Service]
ExecStart=/usr/bin/my_daemon
Restart=on-failure
RestartSec=5
StandardOutput=journal


➤ Вариант 2 (Зависимости и порядок): правильное указание After=network.target и Requires=postgresql.service гарантирует, что сервис запустится только когда его зависимости готовы.

➤ Вариант 3 (Ограничение ресурсов): секция [Slice] и MemoryMax позволяют ограничить потребление памяти, предотвращая «проседание» всей системы из-за одной утечки.

systemd — это автоматизация управления процессами на уровне ОС. Он превращает приложение из «просто исполняемого файла» в управляемый, наблюдаемый и устойчивый сервис.

Какие возможности systemd, помимо простого start/stop, Вы используете чаще всего? Мониторинг через journalctl, cgroups или таймеры?

P.S. Споры о systemd — бесконечны, но его распространенность в современном Linux-мире делает его знание обязательным. Это не всегда выбор, но это реальность.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92👌1
Git Hooks: Твой личный робот-помощник

Хотите, чтобы код автоматически прогонял тесты перед каждым коммитом? Или чтобы линтер проверял стиль? Или чтобы скрипт развертывания сам запускался после пушa в main? Пора познакомиться с Git Hooks.

Хуки лежат в папке .git/hooks/. Пример пре-коммит хука (.git/hooks/pre-commit), который не даст закоммитить код, не прошедший линтинг:
#!/bin/sh
echo "Запуск линтера..."
if ! eslint --cache --fix .; then
    echo "Линтер нашел ошибки! Коммит отменен."
    exit 1
fi
git add .  # Добавляем исправления, сделанные линтером

Не забудьте дать файлу права на выполнение: chmod +x .git/hooks/pre-commit

Git Hooks — это скрипты, которые Git запускает в ответ на определенные события (commit, push, rebase и т.д.). Они выполняются локально и позволяют автоматизировать рутину и внедрить контроль качества.

Какой самый полезный или безумный Git Hook Вы когда-либо использовали или хотели бы использовать? Поделитесь идеями!

Настроить pre-commit хук — это как нанять очень принципиального секьюрити, который не пустит Вас на работу в пижаме. Иногда раздражает, но в итоге все только выигрывают.

🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3👌1
Автоматическое резервное копирование: спим спокойно

Бэкапы — это как страховка: все знают, что нужны, но мало кто их делает. Исправим это одним скриптом.

"А у нас есть бэкап?" — самый страшный вопрос, который можно услышать после "система легла". Ручные бэкапы ненадежны и забываются.

Вариант 1 (Bash-скрипт + Cron):
#!/bin/bash
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# Бэкап базы данных
pg_dump mydb > $BACKUP_DIR/mydb_$DATE.sql

# Бэкап важных директорий
tar -czf $BACKUP_DIR/app_$DATE.tar.gz /app/data

# Удаляем старые бэкапы (старше 30 дней)
find $BACKUP_DIR -name "*.sql" -mtime +30 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete


Вариант 2 (Python-скрипт с отправкой в облако):
import boto3
from datetime import datetime

s3 = boto3.client('s3')
backup_file = f"backup_{datetime.now().strftime('%Y%m%d')}.sql"

# Создаем бэкап и загружаем в S3
subprocess.run(['pg_dump', 'mydb', '-f', backup_file])
s3.upload_file(backup_file, 'my-backup-bucket', backup_file)


Disaster Recovery — автоматизируем процессы восстановления после сбоев. Правило 3-2-1: 3 копии данных, на 2 разных носителях, 1 копия off-site.

А как у вас с бэкапами? Ручные, автоматические, или по принципу "если продакшен упадет, просто найдем новую работу"?

P.S. Есть два типа людей: те, кто делают бэкапы, и те, кто еще будет их делать.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72👌2🥱1
Война с плавающим багом в CI

Ваш CI-пайплайн падает раз в два дня из-за плавающего теста, и все делают вид, что не замечают? Сегодня объявляем ему войну. Не игнорируем, а автоматизируем поимку.

Это классика: "У меня работает", "Heisenbug*", который исчезает при попытке отладки. Команда привыкает к красному статусу и перестает ему доверять, что убивает саму идею CI. Ручной перезапуск — это не решение, это признание поражения.

➤ Вариант 1 (Bash + Cron): Пишем скрипт, который дергает API вашего CI (например, Jenkins/GitLab), проверяет последний запуск падающего джоба и в случае ошибки автоматически перезапускает его, отправляя уведомление в Slack.
# Пример для GitLab CI с использованием jq и curl
PIPELINE_STATUS=$(curl -s --header "PRIVATE-TOKEN: <your_token>" "https://gitlab.com/api/v4/projects/<project_id>/pipelines/latest" | jq -r '.status')
if [ "$PIPELINE_STATUS" = "failed" ]; then
curl --request POST --header "PRIVATE-TOKEN: <your_token>" "https://gitlab.com/api/v4/projects/<project_id>/pipelines/latest/retry"
curl -X POST -H 'Content-type: application/json' --data '{"text":"Плавающий тест снова упал. Автоперезапуск...»"}' $SLACK_WEBHOOK
fi


➤ Вариант 2 (GitHub Actions): используем schedule и джоб с условием для автоматического перезапуска только конкретного флаки-теста.
jobs:
retry_flaky_test:
if: failure() && contains(github.event.head_commit.message, 'retry flaky test')
runs-on: ubuntu-latest
steps:
- name: Retry the flaky test suite
run: |
echo "Автоматический ретрай запущен"


Речь об устойчивости и проактивном мониторинге. Система не должна полагаться на бдительность человека. Мы встраиваем механизм самовосстановления для известных, но трудноустранимых проблем. Это тот же принцип, что и в livenessProbe в Kubernetes: если система нездорова, ее нужно перезапустить, прежде чем бить в колокола.

А в вашей команде есть "призрачный" баг? Как вы с ним боретесь: пишете сложные логи, ставите ретраи или просто молитесь?

P.S. Автоматический ретрай — это не починка бага, это костыль. Но лучше автоматический костыль, чем кривые костыли ручных ретраев.


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


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
2👌2🔥1
Мониторинг производительности: от сбора метрик до визуализации

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

Архитектура: 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
👍52🔥1
Сила .gitignore: защита от самого себя

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

Человеческая память ненадежна. Доверить ей решение, что можно коммитить, а что нет — наивно.

➤ Вариант 1 (Глобальный ~/.gitignore_global): для файлов, которые никогда не должны попадать ни в один репозиторий: .DS_Store, Thumbs.db, *.swp, файлы конфигурации Вашего редактора.

# Настройка
git config --global core.excludesfile ~/.gitignore_global


➤ Вариант 2 (Специфичный для языка/инструмента): генерация или использование готовых шаблонов для Python (__pycache__/, *.pyc), Node.js (node_modules/), Java (target/), Go (/vendor/).

➤ Вариант 3 (.gitignore как часть инициализации проекта): автоматическое создание адекватного .gitignore при старте нового проекта через git init или инструменты вроде cookiecutter.

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

Доводилось ли Вам «вычищать» историю репозитория из-за случайно закоммиченного секрета? Или .gitignore всегда стоит на страже?

P.S. Есть сервисы вроде git-secrets или truffleHog, которые сканируют историю на наличие ключей и паролей. Но лучше не допускать их попадания туда.


🌐 @helcode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🔥1
ansible / salt — идемпотентность как религия

Ручное выполнение одних и тех же команд на десятках серверов с риском что-то пропустить или выполнить в разном порядке — это гарантия «дрейфа конфигурации». Инструменты управления конфигурацией (CM) выполняют описание *желаемого состояния* системы, и делают это идемпотентно (повторный запуск не меняет корректно настроенную систему).

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

- Вариант 1 (Простая идемпотентность Ansible): модуль apt установит пакет, только если его нет. Модуль template создаст файл из шаблона, только если он изменился.
- name: Ensure nginx is installed
apt:
name: nginx
state: present

- name: Deploy nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'

- Вариант 2 (Сбор фактов и условия): Ansible сначала собирает информацию о системе (facts), что позволяет выполнять задачи только на определенных ОС или при определенных условиях.
- Вариант 3 (Откат и проверка): многие CM-инструменты имеют режим --check (пробный прогон) и позволяют описывать шаги отката на случай неудачи.

Идемпотентность — это "суперсила" автоматизации. Она превращает настройку инфраструктуры из искусства в предсказуемую инженерную дисциплину, где результат не зависит от начального состояния и количества запусков.

P.S. Главный тест на идемпотентность: запустите плейбук дважды подряд. Во второй раз не должно быть изменений (changed=0). Если это так — Вы на правильном пути.


🌐 @helcode
👍52🔥1
Самолечение для Kubernetes: beyond kubectl get pods

kubectl get pods | grep CrashLoopBackOff - это не диагноз, это крик о помощи. Давайте научим кубер самолечению, чтобы он не просто сообщал о проблеме, а пытался ее исправить.

В сотый раз получаем алерт, что под упал. В сотый раз вручную делаем kubectl delete pod .... Это цифровая "яжемать :)", а не работа инженера. Система должна заботиться о себе сама.

➤ Вариант 1 (Нативные механизмы K8s): livenessProbe и readinessProbe — это основа. Если проба живучести падает, kubelet убивает и пересоздает контейнер.
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10


➤ Вариант 2 (Operator Pattern): для сложных stateful приложений (БД, Kafka). Кастомный контроллер (Operator) следит за состоянием и может делать сложные вещи: делать бэкап, ребалансировать партиции*, увеличивать объем хранилища.

➤ Вариант 3 (Скрипт на Bash/Python + CronJob): если нативных механизмов мало. Например, скрипт, который проверяет логи на наличие конкретной ошибки и выполняет кастомную операцию по ее исправлению.
# Пример: поиск и лечение утечки памяти
if kubectl logs my-pod --since=10m | grep -q "OutOfMemoryError"; then
kubectl rollout restart deployment my-app
fi


Это воплощение принципа "выбирай исправление, а не оповещение". Мы движемся от мониторинга ("что-то сломалось") к автоматическому реагированию ("я уже пытаюсь это починить"). Это краеугольный камень самоцелительных (self-healing) систем.

P.S. Идеал — это когда вы спокойно спите, а ваш кластер ночью сам перезапускает поды, рестартит деплоименты и даже делает кофе. Ну, почти.


* Партиции (или секции) — это отдельные физические или логические части, на которые разбиваются большие наборы данных, например, таблицы в базах данных или разделы в системах обработки данных.


🌐 @helcode
👍41🔥1👌1
Сборка самописных утилит на Go. Когда Bash уже мал.

Ваш bash-скрипт для деплоя разросся до 500 строк и стал похож на" Франкенштейна"? Пора переписать его на Go и получить одну бинарку, которую можно кинуть куда угодно.

Bash отлично справляется с маленькими задачами, но когда нужна сложная логика, работа с HTTP API, парсинг сложного JSON — он становится неуклюжим и трудночитаемым.

➤ Простой пример на Go: утилита, которая ходит в API, проверяет статус и шлет уведомление.
package main

import (
"encoding/json"
"fmt"
"net/http"
"os"
)

func main() {
resp, err := http.Get("https://api.status.io/1.0/status/xyz")
if err != nil {
panic(err)
}
defer resp.Body.Close()

var status Status
json.NewDecoder(resp.Body).Decode(&status)

if status.Status != "operational" {
fmt.Println("Сервис лежит!")
os.Exit(1)
}
fmt.Println("Всё ок!")
}

type Status struct {
Status string `json:"status"`
}


➤ Почему Go? Простая компиляция в один бинарный файл, кросс-компиляция, удобная стандартная библиотека (особенно для сетевых задач), нет зависимостей в рантайме.

Речь о выборе правильного инструмента. Bash — для быстрых, тексто-ориентированных задач. Python — для скриптов, где важна скорость разработки и есть много библиотек. Go — для высокопроизводительных, надежных утилит, которые должны работать без проблем в любом окружении.

P.S. Написание утилит на Go — это как собрать своего робота из Лего: удобно, надежно и невероятно приятно, когда он работает.

🌐 @helcode
👍31🔥1👌1
Война с плавающим багом в CI

Ваш CI-пайплайн падает раз в два дня из-за плавающего теста, и все делают вид, что не замечают? Сегодня объявляем ему войну. Не игнорируем, а автоматизируем поимку.

Это классика: "У меня работает", "Heisenbug*", который исчезает при попытке отладки. Команда привыкает к красному статусу и перестает ему доверять, что убивает саму идею CI. Ручной перезапуск — это не решение, это признание поражения.

➤ Вариант 1 (Bash + Cron): Пишем скрипт, который дергает API вашего CI (например, Jenkins/GitLab), проверяет последний запуск падающего джоба и в случае ошибки автоматически перезапускает его, отправляя уведомление в Slack.
# Пример для GitLab CI с использованием jq и curl
PIPELINE_STATUS=$(curl -s --header "PRIVATE-TOKEN: <your_token>" "https://gitlab.com/api/v4/projects/<project_id>/pipelines/latest" | jq -r '.status')
if [ "$PIPELINE_STATUS" = "failed" ]; then
curl --request POST --header "PRIVATE-TOKEN: <your_token>" "https://gitlab.com/api/v4/projects/<project_id>/pipelines/latest/retry"
curl -X POST -H 'Content-type: application/json' --data '{"text":"Плавающий тест снова упал. Автоперезапуск...»"}' $SLACK_WEBHOOK
fi

➤ Вариант 2 (GitHub Actions): используем schedule и джоб с условием для автоматического перезапуска только конкретного флаки-теста.
jobs:
retry_flaky_test:
if: failure() && contains(github.event.head_commit.message, 'retry flaky test')
runs-on: ubuntu-latest
steps:
- name: Retry the flaky test suite
run: |
echo "Автоматический ретрай запущен"


Речь об устойчивости и проактивном мониторинге. Система не должна полагаться на бдительность человека. Мы встраиваем механизм самовосстановления для известных, но трудноустранимых проблем. Это тот же принцип, что и в livenessProbe в Kubernetes: если система нездорова, ее нужно перезапустить, прежде чем бить тревогу.

P.S. Автоматический ретрай — это не починка бага, это костыль. Но лучше автоматический костыль, чем кривые костыли ручных ретраев.


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

🌐 @helcode
👍41👌1
"Пару слов" про оптимизацию Docker-образов

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

Почему это плохо? Каждый лишний мегабайт в образе - это:
- Медленный пулл на нодах
- Лишнее место в регистри
- Долгий старт подов
- Лишний трафик

Что с этим делать:

Используйте alpine где можно. Базовый образ питона на alpine весит 50 МБ вместо 900 МБ на дебиане. Разница очень ощутима.

Чистите за собой кэши. Если ставите пакеты через apt, не забывайте про apt-get clean && rm -rf /var/lib/apt/lists/*. В том же alpine с apk та же история.

Многослойная сборка. Классика: в одном слое компилируете, во второй кладёте только результат. В итоге в финальном образе нет ни компиляторов, ни исходников, ни временных файлов.

# Билдер
FROM golang:1.20 AS builder
COPY app.go .
RUN go build -o /app app.go

# Финальный образ
FROM alpine:latest
COPY --from=builder /app /app
CMD ["/app"]


Объединяйте RUN-инструкции. Каждый RUN создаёт отдельный слой. Если разнести установку пакетов и чистку по разным RUN, то в промежуточном слое кэши останутся и будут торчать в финальном образе.

# Плохо
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# Хорошо
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean


Не тащите лишние файлы. .dockerignore рулит. Не тащите в образ .git, тесты, документацию и локальные конфиги.

Проверяйте размер своих образов хотя бы раз в месяц. Я обычно смотрю статистику в registry и если вижу, что какой-то образ резко потолстел - иду разбираться. Часто находится что-то неожиданное вроде случайно примонтированных логов или дампов памяти.

🌐 @helcode
3👍3🔥2
Скрипты на bash и их предсказуемость

Поймал себя на мысли, что многие пишут bash-скрипты как придётся. Запустили, оно вроде работает, и ладно. А потом скрипт падает в три часа ночи, потому что переменная оказалась пустой или в названии файла попался пробел.

Есть вещи, которые я всегда добавляю в начало любых скриптов:

#!/bin/bash
set -euo pipefail


➤ Разбор полётов:
- -e — скрипт умирает при первой же ошибке. Без этого флага он продолжит выполнение, даже если команда упала, и вы можете получить кашу.
- -u — если переменная не объявлена, скрипт сразу падает. Без этого флага пустая переменная превратится в пустую строку и может натворить дел (например, rm -rf $UNDEFINED удалит всё, потому что команда превратится в rm -rf).
- -o pipefail — если в пайпе что-то упало, весь пайп считается упавшим. Без этого флага false | true вернёт успех.

Проверка аргументов. Если скрипт требует аргументы, проверяйте их сразу.

if [ -z "${1:-}" ]; then
echo "Ошибка: не указан конфигурационный файл"
exit 1
fi


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

# Плохо
rm -rf $SOME_DIR

# Хорошо
rm -rf "$SOME_DIR"


Проверка на существование. Если скрипт работает с файлами, проверяйте, что они есть.

if [ ! -f "$CONFIG_FILE" ]; then
echo "Файл конфигурации не найден: $CONFIG_FILE"
exit 1
fi


Логирование. Пишите в stdout, что происходит. Это потом спасёт при разборе инцидентов.

echo "[$(date +'%Y-%m-%d %H:%M:%S')] Начинаю бэкап базы данных"


Я иногда смотрю на чужие скрипты и вижу там отсутствие этих простых вещей. В итоге скрипт работает на машине автора, потому что там есть нужные файлы и переменные, но падает на чистой системе. А виноват потом "кривой линух".

У вас были случаи, когда bash-скрипт падал из-за неожиданного пробела в имени файла или незаданной переменной?

🌐 @helcode
🔥9👍32🙏2
Про автоматизацию обновления сертификатов

Каждый, кто админит свои сервера, через это проходил. Просыпаешься утром, а сайт не открывается. Лезешь в логи, а там "SSL certificate expired". Руки чешутся, кофе стынет, сертификат протух ещё неделю назад.

Почему это вообще происходит. Let's Encrypt даёт сертификаты на 90 дней. Это не их прихоть, а стандарт индустрии - короткие сертификаты безопаснее. Но человеческая память короче 90 дней, и ручное обновление рано или поздно проспишь.

➤ 1. Ставим certbot. Он умеет не только получать сертификаты, но и продлевать их.
apt-get install certbot python3-certbot-nginx


➤ 2. Разово получаем сертификат.
certbot --nginx -d example.com -d www.example.com


➤ 3. Настраиваем автоматическое продление. Certbot создаёт systemd-таймер сам при установке. Проверить можно так:
systemctl status certbot.timer
systemctl list-timers | grep certbot


Таймер запускается два раза в день и проверяет, не пора ли обновить сертификаты. Если до истечения осталось меньше 30 дней - обновляет.

➤ 4. Добавляем хуки на перезагрузку. После обновления nginx нужно перезагрузить, чтобы он подхватил новый сертификат.
certbot renew --renew-hook "systemctl reload nginx"


➤ 5. Проверяем, что всё работает.
certbot renew --dry-run


Если вдруг certbot не вариант. Бывает, что сервер в закрытом контуре или используются внутренние CA. Тогда пишется простой скрипт в cron:

#!/bin/bash
# renew-internal-cert.sh

CERT_PATH="/etc/ssl/certs/myapp.crt"
EXPIRY_DAYS=$(openssl x509 -in "$CERT_PATH" -noout -enddate | cut -d= -f2 | xargs -I{} date -d "{}" +%s)
CURRENT=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_DAYS - CURRENT) / 86400 ))

if [ $DAYS_LEFT -lt 7 ]; then
echo "Сертификат скоро истекает ($DAYS_LEFT дней). Запускаю обновление..."
/usr/local/bin/update-internal-cert.sh
systemctl reload nginx
fi


В cron добавляется еженедельный запуск:
0 2 * * 1 /root/renew-internal-cert.sh


Важный момент. Автоматика автоматикой, но я всё равно добавляю мониторинг на дату истечения. Например, в Prometheus можно экспортировать метрику с днями до протухания и настроить алерт, если осталось меньше недели. Тогда даже если автоматика почему-то не сработала, будет время вмешаться вручную.

У кого как организовано обновление сертификатов? Доверяете автоматике или ходите раз в три месяца ручками продлевать?

🌐 @helcode
4👍3🔥1
Коллеги, рад всех приветствовать! Мы закончили миграцию: теперь нас можно читать не только в Телеграм!

Недавно я запускал голосование с вопросом: куда мигрируем на случай блокировки Телеграм? Вы ответили - и довольно однозначно. Спасибо всем, кто участвовал в опросе и оставлял комментарии.

Всё это время я не сидел сложа руки. Была изучена статистика, проанализированы площадки, где присутствует техническая аудитория, проанализировано удобство работы с контентом на различных площадках. Выводы сделаны, инфраструктура настроена.

Что имеем на выходе:

Основной канал как был в Телеграм, так и остается. Сюда я буду писать в первую очередь, здесь же будет основное обсуждение. Никаких "уходим навсегда" не планируется. Также, был переработан формат постов для адекватного репоста в иные соц. сети, весь .md формат (код) уходит в изображение. В ближайшее время мы с ним "познакомимся".

Но теперь у @helcode есть официальные зеркала на двух дополнительных площадках:

VK - для тех, кто привык читать ленту в соцсети и не хочет ставить лишние мессенджеры. Туда уходят все посты синхронно с Телеграм. Минус - в комментарии захожу реже, но читаю.

Boosty - для любителей блог-формата. Там же будет постепенно появляться расширенная версия некоторых материалов, если тема глубокая и не влезает в короткий пост. Об этом буду обязательно оповещать.

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

Резюмирую. Канал жив, контент выходит по плану, темы по автоматизации, Linux и утилитам никуда не делись. Если завтра Телеграм вдруг станет совсем недоступен - вы знаете, где искать. Все "перекрестные" ссылки будут под каждым постом!

🌐 @helcode
👍13👌41🔥1
Коллеги, всех приветствую!

Давно хотел показать что-то действительно полезное и при этом созданное внутри нашего сообщества. Знакомьтесь: DevToolbox Cheats - проект подписчика @boomlavka.

Для тех, кто, как и я, работает в Linux и постоянно ловит себя на мысли: "А какой там флаг у tar...?", "Как правильно смонтировать диск...?", "А как сбросить настройку iptables...?".

Что сделал автор? Он взял и упаковал более 100 готовых шпаргалок (Git, Bash, Docker, RegEx, Ansible и ещё много чего) в удобный интерфейс, который встраивается прямо в панель вашего рабочего стола.

Чем проект цепляет лично меня:
1. Универсальность: неважно, сидите вы в KDE, GNOME, XFCE или даже в голом i3 - утилита сама подстроится и будет выглядеть как родная.
2. Скорость: кэширование отрабатывает так, что список команд появляется быстрее, чем открывается браузер.
3. Копирование в один клик: нашёл команду - ткнул - она уже в буфере. Минимум телодвижений.
4. Умное редактирование: если встроенных шпаргалок вдруг покажется мало, автор продумал сценарий на любой случай. Можно открыть конфиг в любимом редакторе (VS Code, Geany и др.) - скрипт сам определит, что у вас стоит. Если редактор не найден или вы работаете в minimal окружении - файл откроется прямо во всплывающем окошке zenity.

Мы часто обсуждаем автоматизацию на уровне систем и скриптов, но автоматизация личного рабочего процесса - это то, что экономит часы каждую неделю. DevToolbox Cheats - именно про это. Не надо гуглить, не надо лезть в заметки. Просто кликнул на иконку и продолжил работу.

ВАЖНО:

Я знаю, что @boomlavka продолжает развивать проект, и ему, как любому разработчику, важна обратная связь. Если вы покопаетесь в репозитории и найдёте баг, или наоборот - придумаете, как улучшить - не стесняйтесь писать автору или создавать issue на GitHub. Сообщество сильное только тогда, когда Мы помогаем друг другу становиться лучше.

👉 Ссылка на [GitHub](https://github.com/dominatos/devtoolbox-cheats)
Буду благодарен, если поставите звёздочку тем, кто зайдёт. Автору будет приятно, а каналу - почётно, что наши коллеги делают полезные инструменты.

P.S. Если у кого-то тоже есть свои проекты или полезные наработки - смело пишите в личку (@helcodeadm). Покажем, обсудим, поддержим.

🌐 @helcode
6🤔3
Helcode | Хелкод | Скрипты и автоматизация pinned «Коллеги, рад всех приветствовать! Мы закончили миграцию: теперь нас можно читать не только в Телеграм! Недавно я запускал голосование с вопросом: куда мигрируем на случай блокировки Телеграм? Вы ответили - и довольно однозначно. Спасибо всем, кто участвовал…»
Ansible: миф об идемпотентности и как не прострелить себе ногу

Ansible позиционируется как идемпотентный инструмент: можно запустить плейбук сто раз, и система будет в одном и том же состоянии. В теории - красиво, на практике - не всегда. Главная боль возникает, когда вы начинаете писать собственные сценарии с модулями command или shell. Они по умолчанию не идемпотентны. Запустите их дважды - они выполнятся дважды.

Чтобы побороть это, используют параметры creates и removes (проверка наличия файла-маркера), changed_when и failed_when (тонкая настройка условий изменения и ошибки). Но это всё костыли. Если вы ловите себя на том, что часто используете shell вместо специализированных модулей (copy, template, file, lineinfile, package), значит, вы пишете не декларативный код, а процедурный скрипт на bash внутри Ansible.

Стоит помнить: Ansible хорош ровно настолько, насколько хорошо вы используете его модули. Если задача сложная и требует логики, может быть, проще написать скрипт на Python и вызвать его через модуль script, сохранив идемпотентность на уровне внешнего скрипта.

🌐 @helcode
👍9🤔32