Библиотеки 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

Библиотеки Python для Linux - comments

En
Linux библиотеки python (python)