Библиотеки Python в работе системного администратора Linux
Системное администрирование Linux включает автоматизацию, мониторинг и управление ресурсами. Python предоставляет множество библиотек, упрощающих эти задачи. Рассмотрим основные инструменты и их применение.
Эффективное решение: библиотека psutil
Как получить информацию о загрузке процессора, использовании памяти, дисков и сети в реальном времени?
Библиотека psutil (process and system utilities) предоставляет единый интерфейс для сбора системных метрик. Она кроссплатформенна, но особенно полезна в Linux для мониторинга.
import psutil
# Загрузка процессора в процентах за последнюю секунду
cpu_percent = psutil.cpu_percent(interval=1)
print(f"CPU: {cpu_percent}%")
# Использование памяти
memory = psutil.virtual_memory()
print(f"Память: {memory.percent}% использовано")
# Информация о дисках
disk_usage = psutil.disk_usage('/')
print(f"Диск /: {disk_usage.percent}% занято")
# Сетевые интерфейсы и трафик
net_io = psutil.net_io_counters()
print(f"Отправлено: {net_io.bytes_sent}, Получено: {net_io.bytes_recv}")Linux библиотеки python (библиотеки python для linux)
CPU: 12.5%
Память: 45.2% использовано
Диск /: 67.8% занято
Отправлено: 12345678, Получено: 87654321
Каждый вызов возвращает данные с возможностью дальнейшей обработки. Для доступа к некоторым метрикам (например, информации о процессах других пользователей) могут потребоваться права root.
Типичные ошибки:
- PermissionError при попытке получить информацию о процессах, запущенных от имени другого пользователя. Решение - запускать скрипт с sudo.
- NoSuchProcess при обращении к уже завершённому процессу. Рекомендуется обрабатывать исключение try-except.
- На некоторых контейнерных окружениях (Docker) psutil может показывать данные хоста, а не контейнера. Следует учитывать при мониторинге.
Случаи использования: мониторинг серверов, сбор статистики для графиков, оповещения при превышении порогов, автоматическое масштабирование.
Варианты решения
Как выполнить shell-команду и обработать её вывод?
Модуль subprocess - стандартный инструмент для запуска внешних процессов. Возвращает код возврата и потоки stdout/stderr.
import subprocess
result = subprocess.run(['ls', '-l', '/var/log'], capture_output=True, text=True)
print(f"stdout:\n{result.stdout}")
print(f"stderr:\n{result.stderr}")
print(f"Return code: {result.returncode}")stdout:
total 1234
-rw-r--r-- 1 root root ...
stderr:
Return code: 0
Ошибки:
- Ошибка кодировки - результат может содержать символы, не декодируемые в UTF-8. Параметр encoding помогает задать корректную кодировку.
- Зависание при большом объёме вывода - рекомендуется использовать timeout или потоковое чтение.
- Команда с раширением шаблонов (например, ls *.txt) не будет работать, если не указать shell=True. Но это может быть небезопасно (shell injection).
Как упростить выполнение shell-команд, избежав шаблонного кода subprocess?
Библиотека sh (не входит в стандартную поставку) позволяет вызывать команды как функции.
import sh
# Выполнение 'df -h'
disk_free = sh.df('-h')
print(disk_free)
# Выполнение с перенаправлением stderr
error_output = sh.ls('/nonexistent', _ok_code=[1,2])
print(error_output.stderr)Проблемы:
- Необходимость установки: pip install sh
- Некоторые сложные команды (с каналами, перенаправлениями) требуют обхода через sh.bash('-c', 'команда').
Как кроссплатформенно работать с файловыми путями, избегая различий между Linux и Windows?
Модуль pathlib (Python 3.4+) предоставляет объектно-ориентированный интерфейс для путей файловой системы.
from pathlib import Path
# Создание пути
p = Path('/etc/nginx/nginx.conf')
print(p.name) # nginx.conf
print(p.parent) # /etc/nginx
print(p.suffix) # .conf
# Проверка существования
if p.exists():
with p.open() as f:
content = f.read()
# обработкаОшибки:
- Пути Linux абсолютны и начинаются с '/', на Windows - с буквы диска. При кроссплатформенном коде стоит использовать PurePosixPath или PureWindowsPath для проверок, а Path адаптируется под текущую ОС.
- Права доступа - pathlib не управляет правами напрямую, для этого используется os.chmod или stat.
Как получить информацию об аппаратной платформе и версии ядра?
Модуль platform входит в стандартную библиотеку и предоставляет данные о системе.
import platform
print(f"Система: {platform.system()}") # Linux
print(f"Имя узла: {platform.node()}") # hostname
print(f"Версия ядра: {platform.release()}") # 5.15.0-91-generic
print(f"Архитектура: {platform.machine()}") # x86_64
print(f"Информация о процессоре: {platform.processor()}")Примечание: на некоторых виртуальных машинах процессор может возвращать пустую строку. Для детального анализа лучше использовать /proc/cpuinfo через чтение файла.
Как парсить YAML-конфигурации, часто используемые в Linux-сервисах?
Библиотека pyyaml позволяет загружать и сохранять YAML-файлы.
import yaml
with open('/etc/monit/monitrc', 'r') as f:
config = yaml.safe_load(f) # безопасная загрузка
print(config.get('processes'))
# Создание YAML
data = {'memory': {'limit': '256M'}}
with open('config.yaml', 'w') as f:
yaml.dump(data, f, default_flow_style=False)Ошибки:
- yaml.scanner.ScannerError при некорректном форматировании. Рекомендуется перед загрузкой выполнять валидацию через внешний инструмент.
- Использование yaml.load без аргументов может быть опасно (выполнение произвольного кода). Всегда использовать yaml.safe_load.
Как организовать логирование в Python-скриптах для системного администрирования?
Модуль logging стандартной библиотеки гибок и подходит для записи событий, ошибок и отладочной информации.
import logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.FileHandler('/var/log/myscript.log'),
logging.StreamHandler()])
logger = logging.getLogger(__name__)
logger.info('Скрипт запущен')
logger.warning('Диск почти полон: 90%')
logger.error('Не удалось подключиться к серверу')Типичные ошибки:
- Ротация логов - использовать RotatingFileHandler, чтобы файлы не разрастались до бесконечности.
- Права на запись в /var/log - скрипт должен запускаться от root или иметь привилегии.
- Кодировка - при записи в лог не-ASCII символов возможна ошибка. Указать encoding='utf-8' в обработчике.
Как управлять Docker-контейнерами из Python?
Официальная библиотека docker-py позволяет взаимодействовать с Docker API.
import docker
client = docker.from_env()
# Список всех контейнеров
containers = client.containers.list(all=True)
for c in containers:
print(f"{c.name} - статус: {c.status}")
# Создание и запуск контейнера
container = client.containers.run('nginx:latest',
detach=True,
ports={'80/tcp': 8080})
print(f"Запущен контейнер {container.id[:12]}")
# Остановка
container.stop()
container.remove()Проблемы:
- Необходимость в работающем Docker daemon и соответствующем сокете.
- Ошибка docker.errors.APIError при неверных параметрах или конфликте портов.
- Для удалённого управления требуется настройка TLS.
Как анализировать и создавать сетевые пакеты на Linux?
Библиотека scapy - мощный инструмент для работы на уровне пакетов. Требует прав root.
from scapy.all import sniff, IP, TCP
# Захват 10 пакетов TCP с отображением IP-адресов
def packet_callback(pkt):
if pkt.haslayer(IP):
src = pkt[IP].src
dst = pkt[IP].dst
print(f"{src} -> {dst}")
sniff(filter='tcp', prn=packet_callback, count=10)Ошибки:
- scapy.error.Scapy_Exception при отсутствии прав (не root). Решение - запускать скрипт с sudo.
- Захват пакетов может перегружать систему на высоких скоростях. Использовать фильтры BPF.
- Некоторые функции (отправка пакетов, ARP-spoofing) могут быть незаконны без разрешения. Всегда учитывать правовые аспекты.
Расширенные примеры
1. Мониторинг в реальном времени с psutil и asyncio
Пример асинхронного сбора данных о системе каждые 5 секунд.
import asyncio
import psutil
async def monitor():
while True:
cpu = psutil.cpu_percent(interval=1)
mem = psutil.virtual_memory().percent
disk = psutil.disk_usage('/').percent
print(f"CPU: {cpu}% | RAM: {mem}% | Disk: {disk}%" )
await asyncio.sleep(5)
if __name__ == '__main__':
asyncio.run(monitor())CPU: 15.0% | RAM: 52.3% | Disk: 68.1%
CPU: 10.2% | RAM: 51.8% | Disk: 68.1%
...
2. Асинхронное выполнение shell-команд с subprocess и asyncio
Запуск команды с таймаутом и обработкой ошибок.
import asyncio
async def run_cmd(cmd, timeout=10):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
try:
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
return proc.returncode, stdout.decode(), stderr.decode()
except asyncio.TimeoutError:
proc.kill()
return -1, '', 'Timeout'
async def main():
code, out, err = await run_cmd('ping -c 4 google.com', timeout=5)
print(f"Exit code: {code}")
print(out if code == 0 else err)
if __name__ == '__main__':
asyncio.run(main())Exit code: 0
PING google.com (142.250.185.78) 56(84) bytes of data.
64 bytes from ...
...
3. Поиск файлов с pathlib и glob
Рекурсивный поиск всех файлов с расширением .log в /var/log.
from pathlib import Path
p = Path('/var/log')
for log_file in p.rglob('*.log'):
if log_file.stat().st_size > 10_000_000: # больше 10 MB
print(f"Большой лог: {log_file} - {log_file.stat().st_size / 1e6:.2f} MB")Большой лог: /var/log/syslog - 15.34 MB
Большой лог: /var/log/kern.log - 12.78 MB
4. Чтение /proc/cpuinfo для детальной информации о процессоре
Парсинг /proc/cpuinfo без использования сторонних библиотек.
def get_cpu_info():
with open('/proc/cpuinfo', 'r') as f:
lines = f.readlines()
cpu_info = {}
current_key = None
for line in lines:
if ':' in line:
key, value = line.split(':', 1)
key = key.strip()
value = value.strip()
if key in ['model name', 'cpu cores', 'siblings', 'cache size']:
cpu_info[key] = value
return cpu_info
info = get_cpu_info()
print(f"Модель: {info.get('model name')}")
print(f"Ядер: {info.get('cpu cores')}")
print(f"Потоков: {info.get('siblings')}")
print(f"Кэш: {info.get('cache size')}")Модель: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz
Ядер: 6
Потоков: 12
Кэш: 12288 KB
5. Удаленное выполнение команд через SSH с Paramiko
Подключение к удаленному хосту и выполнение команды.
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.168.1.100', username='admin', password='secret')
stdin, stdout, stderr = ssh.exec_command('uptime')
print(stdout.read().decode())
ssh.close()14:30:15 up 30 days, 2:15, 1 user, load average: 0.08, 0.03, 0.01
6. Создание и применение YAML-шаблонов для конфигурации
Чтение шаблона и подстановка переменных.
import yaml
from string import Template
with open('template.yaml', 'r') as f:
template_str = f.read()
tmpl = Template(template_str)
filled = tmpl.safe_substitute(hostname='server01', port=8080)
config = yaml.safe_load(filled)
print(config)template.yaml:
server:
host: ${hostname}
port: ${port}{'server': {'host': 'server01', 'port': 8080}}7. Ротация логов с помощью RotatingFileHandler
Реализация логирования с ротацией по размеру.
import logging
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler('/var/log/myapp.log', maxBytes=1024*1024, backupCount=5)
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(levelname)s %(message)s',
handlers=[handler])
for i in range(1000):
logging.info(f'Тестовая запись {i}')После превышения 1 MB создаётся myapp.log.1, myapp.log.2 и т.д.
8. Остановка и удаление всех контейнеров Docker по определенному образу
import docker
client = docker.from_env()
for container in client.containers.list(all=True):
if 'myapp:latest' in container.image.tags:
container.stop()
container.remove()
print(f"Контейнер {container.short_id} удалён")9. Сниффинг и анализ пакетов с фильтрацией (scapy)
Захват пакетов DNS и вывод запросов.
from scapy.all import sniff, DNSQR, IP
def dns_callback(pkt):
if pkt.haslayer(DNSQR):
domain = pkt[DNSQR].qname.decode()
print(f"DNS запрос: {domain} от {pkt[IP].src}")
sniff(filter='udp port 53', prn=dns_callback, count=20)DNS запрос: google.com. от 192.168.1.10
DNS запрос: example.org. от 192.168.1.11