Навыки реальных инженеров: практические практики из .agents
Практическое руководство по навыкам реальных инженеров, взятые из .agents: Docker, Kubernetes, Proxmox, ZFS, Ansible и другие инструменты для надежной инфраструктуры.
Основные принципы инженерии в реальном мире
Системный подход к решению задач
Реальный инженер не «гасит пожар», а сначала формирует карту состояния.
Он собирает логи, проверяет зависимости и только потом ищет причину сбоя.
Пример диагностики сетевого сервиса
bash# убедиться, что порт 443 свободен
ss -tlnp | grep :443
# посмотреть последние записи журнала systemd
journalctl -u nginx -n 20 --no-pager
Если сервис не отвечает, проверяем стек зависимостей:
bash# список загруженных модулей nginx
systemctl list-units --type=service | grep nginx
Для изоляции проблем удобно использовать Docker‑Compose, чтобы запустить «чистый» экземпляр без влияния хоста:
yamlversion: "3.8"
services:
nginx:
image: nginx:1.25-alpine
ports:
- "8443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
Запуск:
bashdocker compose up -d
Такой подход позволяет воспроизводить окружение на любой машине и быстро проверять гипотезы.
Предсказуемость конфигураций
Предсказуемость достигается, когда конфигурация хранится в версии‑контроле, проверяется тестами и применяется одинаково на всех узлах.
Системаd‑unit для автоматического старта сервиса
ini[Unit]
Description=My custom service
After=network.target
[Service]
ExecStart=/usr/local/bin/my-service --config /etc/my-service.conf
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Помещаем файл в /etc/systemd/system/my-service.service, затем:
bashsystemctl daemon-reload
systemctl enable my-service
systemctl start my-service
ZFS‑снимок перед изменением
bash# создать снимок pool/volume@pre_change
zfs snapshot pool/volume@pre_change
# при необходимости откатиться
zfs rollback pool/volume@pre_change
Proxmox‑конфиг ноды (пример VM‑настроек)
ini# /etc/pve/nodes/node1/qemu.conf
maxdisks: 10
onstart: stop
Такой файл гарантирует, что параметры узла не изменятся «на коленке», а применяются одинаково при каждом запуске виртуальной машины.
В итоге, системный подход и предсказуемость конфигураций позволяют построить инфраструктуру, которая работает стабильно годами, а не «по‑настоящему» каждый раз по‑своему.
Контейнеризация и оркестрация: Docker и Kubernetes
Docker Compose для микросервисов
Во-первых, Docker Compose — удобный инструмент для описания и запуска нескольких контейнеров, которые взаимодействуют через сети и общие тома. На примере небольшого проекта «веб‑сайт + БД + кеш» покажем, как быстро собрать стек в домашней лаборатории.
yaml# docker-compose.yml
version: "3.9"
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./web:/usr/share/nginx/html:ro
depends_on:
- db
environment:
- DB_HOST=db
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: demo
volumes:
- pg_data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
pg_data:
Команды для работы с Compose:
bash# запуск стека в фоне
docker compose up -d
# проверка статуса контейнеров
docker compose ps
# остановка и удаление контейнеров, сетей и томов
docker compose down -v
Практическая точка зрения: если требуется изменить конфигурацию веб‑сервера, достаточно отредактировать файл ./web/index.html и перезапустить контейнер web через docker compose restart web. Docker Compose автоматически подхватит изменения без полной перезагрузки стека.
Для ARM‑платформ (например, Raspberry Pi) используйте теги с указанием архитектуры, например nginx:alpine — образ уже содержит нужный набор инструкций.
k3s: лёгкий кластер на Raspberry Pi
k3s — это серверный пакет Kubernetes, оптимизированный для небольших ресурсов и простого развертывания. Он подходит для домашней лаборатории, где нужен кластер из нескольких нод без излишней сложности.
Установка k3s на первой ноде (мастер)
bash# Подготовка системы
sudo apt-get update && sudo apt-get install -y curl
# Запуск k3s (используется системныйd service)
curl -sfL https://get.k3s.io | sh -
# Проверка статуса
sudo systemctl status k3s
k3s автоматически использует встроенный контейнерный runtime (containerd), поэтому отдельный Docker не требуется.
Добавление агентов (worker‑нод)
На каждой дополнительной Raspberry Pi выполняем:
bashcurl -sfL https://get.k3s.io | K3S_URL=https://<MASTER_IP>:6443 K3S_TOKEN=<TOKEN> sh -
После этого в kubectl можно проверить наличие агентов:
bashkubectl get nodes
Пример простого манифеста
yaml# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Применяем манифест:
bashkubectl apply -f nginx-deployment.yaml
Проверяем, что поды запустились и сервис доступен:
bashkubectl get pods kubectl get svc
Практическая точка зрения: k3s обеспечивает предсказуемую работу кластера за счёт минимального набора зависимостей и автоматического управления systemd‑юнитами. Это позволяет сосредоточиться на самом приложении, а не на настройке инфраструктуры.
Таким образом, Docker Compose упрощает локальный запуск отдельных микросервисов, а k3s дает возможность масштабировать их в надёжный кластер, сохраняя при этом лёгкость и предсказуемость.
Виртуализация и хранилище: Proxmox, ZFS, TrueNAS
Виртуализация и хранилище: Proxmox, ZFS, TrueNAS
Proxmox VE: настройка кластера из трёх нод
Во-первых, убедитесь, что все три машины работают под одинаковой версией Proxmox VE (на момент написания — 8.1). Рекомендую использовать одинаковый ядро и одинаковый набор пакетов, иначе будет «непредсказуемость» при миграции виртуальных машин.
Сначала подготовьте сеть: статическая IP‑адресация, одинаковый подnet (например, 192.168.10.0/24) и свободный порт 3890 для коммуникации между узлами. Откройте его в фаерволе, если он включён:
bash# на всех узлах
iptables -A INPUT -p tcp --dport 3890 -j ACCEPT
iptables -A INPUT -p udp --dport 3890 -j ACCEPT
Далее, на первом узле (назовём его pnx01) создаём кластер:
bashpvecm create mycluster
На втором узле (pnx02) добавляем первый узел в кластер:
bashpvecm add pnx01:3890
На третьем узле (pnx03) повторяем ту же команду, указав IP первого узла:
bashpvecm add pnx01:3890
Проверить состояние кластера можно командой:
bashpvecm status
Если всё в порядке, вы увидите список всех узлов и их роль (master, slave).
Практическая точка зрения: после создания кластера разместите основные контейнеры или виртуальные машины на узле‑мастер, а резервные копии — на остальные. Это повышает отказоустойчивость и упрощает балансировку нагрузки.
Пример /etc/hosts (на всех узлах):
text192.168.10.10 pnx01 192.168.10.11 pnx02 192.168.10.12 pnx03
После настройки кластера включите Ceph или ZFS‑based storage, если планируете использовать общий диск.
ZFS на TrueNAS: резервное копирование и сжатие
Справедливо, ZFS — это не просто файловая система, а набор функций, которые делают её идеальной для долгосрочного хранения. На TrueNAS вы получаете готовый UI, но при работе с консолью удобно использовать несколько команд.
Сжатие
Включить сжатие можно уже при создании dataset. Рекомендую алгоритм lz4 — он обеспечивает хорошее соотношение «скорость‑компактность» без значительного нагрузки на CPU.
bashzfs create -o compression=lz4 -o atime=off tank/data
Параметр atime=off отключает запись времени доступа к файлам, что экономит I/O и усиливает предсказуемость работы.
Резервное копирование
Самый простой способ — периодические snapshot‑ы и их репликация на второй TrueNAS (или внешний диск).
- Создание snapshot (например, ежедневно в 02:00):
bash0 2 * * * /sbin/zfs snapshot tank/data@$(date +\%Y\%m\%d)
- Отправка и получение (на втором TrueNAS, доступном по SSH):
bashzfs send -R tank/data@$(date +\%Y\%m\%d) | ssh user@backup-host zfs receive -R backup/tank/data
Эту команду удобно добавить в cron того же TrueNAS, где выполняются snapshot‑ы.
Автоматическая очистка старых snapshot‑ов
Чтобы не заполнять диски бесконечными данными, настройте prune‑скрипт, который будет удалять snapshot‑ы старше, скажем, 30 дней:
bash0 3 * * * /sbin/zfs list -t snapshot -o name -s creation tank/data | \
grep -v '@auto' | sort -r | tail -n +31 | xargs -n1 zfs destroy
Этот скрипт удаляет все snapshot‑ы, кроме последних 30, тем самым поддерживая предсказуемость использования диска.
Итого: ZFS на TrueNAS позволяет комбинировать высокий сжатие, мгновенные снимки и простую репликацию, что делает её надёжным хранилищем для контейнеров Proxmox, баз данных и резервных копий.
Если понадобится более детальная настройка Ceph‑pool или интеграция ZFS с Proxmox, дайте знать — подготовлю отдельный гайд.
Автоматизация и мониторинг: Ansible, Prometheus
### Ansible для автоматической конфигурации
Ansible — удобный способ описать желаемое состояние серверов без постоянного вручную ввода команд. В домашней лаборатории я использую его для развертывания базовых пакетов, настройки сетевых интерфейсов и применения конфигураций ZFS.
Инвентори (файл inventory.ini):
ini[homelab]
winnie-pc ansible_host=192.168.1.10
piglet ansible_host=192.168.1.11
sova ansible_host=192.168.1.12
Playbook для установки Docker CE и Docker‑Compose на всех узлах:
yaml# site.yml
- hosts: homelab
become: true
tasks:
- name: Обновить apt‑кеши
apt:
update_cache: yes
cache_valid_time: 3600
- name: Установить необходимые пакеты
apt:
name:
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
- name: Добавить официальный репозиторий Docker
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Добавить репозиторий Docker
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
update_cache: yes
- name: Установить Docker Engine
apt:
name: docker-ce
state: present
- name: Установить Docker‑Compose (v2)
pip:
name: docker-compose
state: present
- name: Запустить и включить Docker
systemd:
name: docker
enabled: yes
state: started
Запуск:
bashansible-playbook -i inventory.ini site.yml
Для более сложных сценариев удобно использовать роли из Ansible Galaxy, например geerlingguy.docker, и переопределять переменные в group_vars/all.yml.
Практический совет – держите инвентори и playbook в Git, чтобы отслеживать изменения и легко возвращаться к рабочей версии.
### Prometheus + Grafana: метрики и алерты
Prometheus — система сбора метрик, а Grafana — визуализация и оповещение. В моём кластере Proxmox я запускаю node_exporter на каждом сервере и Prometheus в отдельном контейнере, а Grafana — на хосте sova.
docker‑compose для Prometheus и node_exporter:
yaml# docker-compose.yml
version: "3.8"
services:
prometheus:
image: prom/prometheus:v2.53.0
container_name: prometheus
restart: unless-stopped
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
ports:
- "9090:9090"
node-exporter:
image: prom/node-exporter:v1.8.1
container_name: node-exporter
restart: unless-stopped
network_mode: host
pid: host
privileged: true
volumes:
prometheus_data:
prometheus.yml (минимальная конфигурация):
yamlglobal:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['winnie-pc:9100', 'piglet:9100', 'sova:9100']
Запуск:
bashdocker compose up -d
Alertmanager (можно добавить как отдельный сервис в compose) — обрабатывает правила оповещений. Пример правила в файле alerts.yml:
yamlgroups:
- name: node.rules
rules:
- alert: HighCPUUsage
expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 2m
labels:
severity: critical
annotations:
summary: "CPU usage > 80% on {{ $labels.instance }}"
description: "Average CPU idle time is below 20% for 2 minutes."
Grafana
- Установите Grafana (Docker‑image
grafana/grafana:10.2.0). - В веб‑интерфейсе добавьте datasource Prometheus с URL
http://prometheus:9090. - Импортируйте готовый дашборд, например Node Exporter Full (ID 1860) через Dashboard → Import.
Alerting в Grafana (встроенная):
yaml# rule in Grafana UI → Alerting → Create alert
- Name: CPU usage alert
Condition: WHILE sum(rate(node_cpu_seconds_total{mode="idle"}[5m])) < 20
For: 2m
Labels: { severity: critical }
Annotations: {
summary: "High CPU usage on {{ $labels.instance }}",
description: "CPU idle time dropped below 20% for more than 2 minutes."
}
Настройте получателя (email, Slack, Telegram) в Alerting → Notification channels.
Практический совет – включайте мониторинг только после того, как убедились, что метрики собираются корректно. Проверьте, что
node_exporterдоступен поhttp://<host>:9100/metrics.
Официальная документация Prometheus
Grafana Alerting
Часто задаваемые вопросы
Как правильно использовать Docker‑Compose для изоляции окружения при отладке сетевого сервиса?
Создайте docker-compose.yml, где сервис запускается в отдельном контейнере без доступа к файлам хоста, если это не требуется. Пример конфигурации показывает монтирование только нужных конфигурационных файлов в режиме ro, а порты пробрасываются явно. Запуск docker compose up -d позволяет воспроизвести окружение на любой машине и проверять гипотезы без риска повредить основной сервис.
Что делать, если после изменения конфигурации сервиса он не стартует, но в журналах нет ошибок?
Сначала проверьте, что unit‑файл systemd корректен: systemctl daemon-reload и systemctl status my-service. Убедитесь, что все зависимости, такие как сеть и файловая система, доступны, используя systemctl list-dependencies. Если сервис всё равно не стартует, запустите его в режиме отладки (ExecStart=/usr/local/bin/my-service --config /etc/my-service.conf --debug) и посмотрите вывод в journalctl -u my-service -f.
Как обеспечить предсказуемость конфигураций при работе с Ansible и systemd‑units?
Храните файлы unit‑ов и конфиги в репозитории Git, применяйте роли Ansible, которые копируют их в /etc/systemd/system/ и сразу вызывают systemctl daemon-reload. После изменения добавьте проверку через ansible-playbook --check и запустите тестовый запуск на отдельном узле. Такой подход гарантирует одинаковую конфигурацию на всех узлах и упрощает откат при проблемах.
Почему важно делать ZFS‑снимок перед применением изменений в хранилище и как быстро откатить?
Снимок zfs snapshot pool/volume@pre_change фиксирует состояние данных в момент изменения, позволяя откатиться без потери целостности. При необходимости выполните zfs rollback pool/volume@pre_change. Этот шаг минимизирует риск потери данных и ускоряет восстановление в случае неожиданного сбоя.