Как стать автором
Обновить

Книга «Python и DevOps: Ключ к автоматизации Linux»

Время на прочтение11 мин
Количество просмотров17K
image Привет, Хаброжители! За последнее десятилетие технологии сильно изменились. Данные стали хитом, облака — вездесущими, и всем организациям понадобилась автоматизация. В ходе таких преобразований Python оказался одним из самых популярных языков программирования. Это практическое руководство научит вас использовать Python для повседневных задач администрирования Linux с помощью наиболее удобных утилит DevOps, включая Docker, Kubernetes и Terraform.

Умение взаимодействовать с Linux играет важнейшую роль для миллионов специалистов. Python сильно упрощает эту задачу. Прочитав книгу, вы научитесь разрабатывать программное обеспечение и использовать контейнеры, а также выполнять мониторинг, телеметрию, нагрузочное тестирование ПО и вводить его в эксплуатацию. Ищете эффективный способ достичь поставленных целей на Python? Это руководство — для вас.

В книге

  • Основы Python, включая краткое введение в сам язык.
  • Автоматизация обработки текста, использование командной строки и автоматизация работы с файловой системой.
  • Утилиты Linux, управление пакетами, системы сборки, мониторинг и телеметрия, а также автоматизация тестирования.
  • Облачные вычисления, инфраструктура как код, Kubernetes и бессерверная обработка данных.
  • Машинное обучение и инженерия данных с точки зрения DevOps.
  • Создание, развертывание и ввод в эксплуатацию проекта машинного обучения.

Автоматизация работы с файлами и файловой системой


Одни из самых замечательных возможностей Python — операции с текстом и файлами. В мире DevOps постоянно приходится выполнять синтаксический разбор, поиск и изменение текста в файлах, идет ли речь о поиске в журналах приложения или распространении файлов конфигурации. Файлы — это способ сохранения состояния данных, кода и конфигурации, именно с их помощью можно просматривать постфактум журналы и управлять настройками. В Python можно создавать, читать и менять файлы и текст с помощью кода, и эти возможности вы будете использовать все время. Автоматизация этих задач — один из аспектов современного DevOps, который отличает его от традиционного системного администрирования. Вместо того чтобы хранить набор инструкций и следовать им самостоятельно, можно просто написать код, что снизит вероятность пропустить какие-либо шаги или перепутать их очередность. Уверенность в выполнении одинаковой последовательности шагов при каждом запуске системы повышает понятность и надежность процесса.

Чтение и запись файлов


Чтобы открыть файловый объект для чтения и записи, можно воспользоваться функцией open. Она принимает на входе два аргумента: путь к файлу и режим (по умолчанию режим чтения). Режим позволяет указывать, помимо прочего, открывается ли файл для чтения или записи, содержит ли он текстовые или двоичные данные. Для чтения содержимого текстового файла подходит режим r. У файлового объекта есть метод read, возвращающий содержимое файла в виде строкового значения:

In [1]: file_path = 'bookofdreams.txt'
In [2]: open_file = open(file_path, 'r')

In [3]: text = open_file.read()
In [4]: len(text)
Out[4]: 476909

In [5]: text[56]
Out[5]: 's'

In [6]: open_file
Out[6]: <_io.TextIOWrapper name='bookofdreams.txt' mode='r' encoding='UTF-8'>

In [7]: open_file.close()

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

Можно также читать файлы с помощью метода readlines: он читает файл и разбивает его содержимое по символам перевода строк. Он возвращает список строковых значений, каждое из которых содержит одну строку исходного текста:

In [8]: open_file = open(file_path, 'r')
In [9]: text = open_file.readlines()
In [10]: len(text)
Out[10]: 8796

In [11]: text[100]
Out[11]: 'science, when it admits the possibility of occasional hallucinations\n'

In [12]: open_file.close()

Файлы удобно открывать с помощью операторов with. При этом не требуется закрывать их явно. Python сам закроет файл и освободит выделенные под него ресурсы в конце отформатированного с помощью отступов блока:

In [13]: with open(file_path, 'r') as open_file:
...: text = open_file.readlines()
...:

In [14]: text[101]
Out[14]: 'in the sane and healthy, also admits, of course, the existence of\n'

In [15]: open_file.closed
Out[15]: True

В различных операционных системах — разные экранированные символы для обозначения конца строки: в Unix-системах — \n, а в Windows — \r\n. Python преобразует их в \n при открытии файла как текстового. Если открывать как текст двоичный файл, например изображение .jpeg, подобное преобразование, вероятно, повредит данные. Однако для чтения двоичных файлов можно добавить b в модификатор режима:

In [15]: file_path = 'bookofdreamsghos00lang.pdf'
In [16]: with open(file_path, 'rb') as open_file:
...: btext = open_file.read()
...:

In [17]: btext[0]
Out[17]: 37

In [18]: btext[:25]
Out[18]: b'%PDF-1.5\n%\xec\xf5\xf2\xe1\xe4\xef\xe3\xf5\xed\xe5\xee\xf4\n18'

Добавление этого модификатора позволяет открыть файл без какого-либо преобразования символов конца строки.

Для записи в файл необходимо использовать режим записи, представленный аргументом w. Утилита direnv позволяет автоматически настроить среду разработки. В файле .envrc можно описать переменные среды и среду выполнения приложения; direnv настраивает все это на его основе при входе в каталог с файлом. Например, в Python можно задать в подобном файле переменную среды STAGE равной PROD и TABLE_ID равным token-storage-1234, воспользовавшись функцией open с флагом write:

In [19]: text = '''export STAGE=PROD
...: export TABLE_ID=token-storage-1234'''

In [20]: with open('.envrc', 'w') as opened_file:
...: opened_file.write(text)
...:

In [21]: !cat .envrc
export STAGE=PROD
export TABLE_ID=token-storage-1234

Учтите, что метод write команды pathlib перезаписывает уже существующие файлы.

Функция open создает файл, если он еще не существует, и перезаписывает в противном случае. Чтобы сохранить существующее содержимое файла и просто добавить данные в его конец, используйте флаг a. Он позволяет добавить новый текст в конец файла, сохранив исходное содержимое. Запись нетекстового содержимого, например содержимого файла .jpeg, вероятно, повредит его, если задействовать флаги w или a. Дело в том, что Python преобразует символы конца строки в ориентированные на конкретную платформу при записи текстовых данных. Для безопасной записи двоичных данных можно использовать флаг wb или ab.

В главе 3 команда pathlib обсуждается подробно. В числе ее возможностей — две удобные функции для чтения и записи файлов, все операции с файловым объектом команда pathlib производит «за кулисами». Вот так можно прочитать текст из файла:

In [35]: import pathlib

In [36]: path = pathlib.Path(
"/Users/kbehrman/projects/autoscaler/check_pending.py")

In [37]: path.read_text()

Для чтения двоичных данных предназначен метод path.read_bytes.

Если нужно перезаписать старый файл или записать новый, существуют методы для записи как текста, так и двоичных данных:

In [38]: path = pathlib.Path("/Users/kbehrman/sp.config")

In [39]: path.write_text("LOG:DEBUG")
Out[39]: 9

In [40]: path = pathlib.Path("/Users/kbehrman/sp")
Out[41]: 8

Для неструктурированного текста обычно вполне достаточно функций read и write файлового объекта, но что делать, если речь идет о более сложных данных? Для хранения простых структурированных данных в современных сервисах широко применяется формат нотации объектов JavaScript (JavaScript Object Notation, JSON). В нем задействуются две структуры данных: ассоциативный массив пар «ключ/значение», подобный ассоциативным массивам языка Python, и список элементов, подобный спискам Python. В нем описаны типы данных для чисел, строк, булевых значений (для хранения значений «истина/ложь») и неопределенных (пустых) значений (null). Веб-сервис AWS Identity and Access Management (IAM) позволяет управлять доступом к ресурсам AWS. Для описания стратегий доступа в нем используют JSON-файлы наподобие следующего примера:

{
    "Version": "2012-10-17",
    "Statement": {
       "Effect": "Allow",
       "Action": "service-prefix:action-name",
       "Resource": "*",
       "Condition": {
          "DateGreaterThan": {"aws:CurrentTime": "2017-07-01T00:00:00Z"},
          "DateLessThan": {"aws:CurrentTime": "2017-12-31T23:59:59Z"}
       }
    }
}

Для извлечения данных из подобного файла можно использовать стандартные методы read и readlines файлового объекта:

In [8]: with open('service-policy.json', 'r') as opened_file:
   ...: policy = opened_file.readlines()
   ...:
   ...:

Результат нельзя будет применить сразу же, поскольку он будет выглядеть как одна строка или список строк в зависимости от выбранного метода чтения:

In [9]: print(policy)
['{\n',
'    "Version": "2012-10-17",
\n',
'    "Statement": {\n',
'        "Effect": "Allow",
\n',
'        "Action": "service-prefix:action-name",
\n',
'        "Resource": "*",
\n',
'        "Condition": {\n',
'             "DateGreaterThan": {"aws:CurrentTime": "2017-07-01T00:00:00Z"},
\n',
'             "DateLessThan": {"aws:CurrentTime": "2017-12-31T23:59:59Z"}\n',
'         }\n',
'     }\n',
'}\n']

Далее нужно будет произвести синтаксический разбор этой строки (строк) в структуры данных и типы, соответствующие исходному файлу, что может потребовать немалых усилий. Так что намного удобнее будет воспользоваться модулем json:

In [10]: import json
In [11]: with open('service-policy.json', 'r') as opened_file:
   ...: policy = json.load(opened_file)
   ...:
   ...:
   ...:

Этот модуль производит синтаксический разбор формата JSON и возвращает данные в виде соответствующих структур данных Python:

In [13]: from pprint import pprint

In [14]: pprint(policy)
{'Statement': {'Action': 'service-prefix:action-name',
              'Condition': {'DateGreaterThan':
                       {'aws:CurrentTime': '2017-07-01T00:00:00Z'},
                               'DateLessThan':
                       {'aws:CurrentTime': '2017-12-31T23:59:59Z'}},
              'Effect': 'Allow',
              'Resource': '*'},
'Version': '2012-10-17'}

Модуль pprint автоматически форматирует объекты Python для вывода в консоль. Выводимые им данные обычно намного удобнее для чтения и анализа вложенных структур данных.

Теперь можно работать с данными с исходной структурой из файла. Например, вот так можно изменить ресурс, доступом к которому управляет эта стратегия, на S3:

In [15]: policy['Statement']['Resource'] = 'S3'
In [16]: pprint(policy)
{'Statement': {'Action': 'service-prefix:action-name',
              'Condition': {'DateGreaterThan':
                        {'aws:CurrentTime': '2017-07-01T00:00:00Z'},
              'DateLessThan':
                        {'aws:CurrentTime': '2017-12-31T23:59:59Z'}},
              'Effect': 'Allow',
              'Resource': 'S3'},
'Version': '2012-10-17'}

С помощью метода json.dump можно записать ассоциативный массив Python в JSON-файл. Вот так можно обновить только что модифицированный нами файл стратегии:

In [17]: with open('service-policy.json', 'w') as opened_file:
   ...: policy = json.dump(policy, opened_file)
   ...:
   ...:
   ...:

В файлах конфигурации нередко применяется и еще один язык — YAML, представляющий собой расширенную версию JSON, но в более сжатом формате, в котором пробелы используются так же, как в Python.

Одна из утилит, предназначенных для автоматизации настройки программного обеспечения, его развертывания и управления им, — Ansible. Для описания автоматизируемых действий в Ansible применяют так называемые сборники сценариев (playbooks) в формате YAML:

---
- hosts: webservers
   vars:
     http_port: 80
     max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
     yum:
       name: httpd
       state: latest
 ...

Для синтаксического разбора YAML в Python чаще всего используется библиотека PyYAML. Она не входит в стандартную библиотеку Python, но ее можно установить с помощью pip:

$ pip install PyYAML

После установки можно импортировать и экспортировать данные в формате YAML с помощью PyYAML аналогично тому, как мы делали с JSON:

In [18]: import yaml

In [19]: with open('verify-apache.yml', 'r') as opened_file:
   ...: verify_apache = yaml.safe_load(opened_file)
   ...:

Данные при этом загружаются в уже привычные для нас структуры данных Python (список, содержащий ассоциативный массив):

In [20]: pprint(verify_apache)
[{'handlers': [{'name': 'restart apache',
               'service': {'name': 'httpd', 'state': 'restarted'}}],
   'hosts': 'webservers',
   'remote_user': 'root',
   'tasks': [{'name': 'ensure apache is at the latest version',
                'yum': {'name': 'httpd', 'state': 'latest'}},
              {'name': 'write the apache config file',
                'notify': ['restart apache'],
                'template': {'dest': '/etc/httpd.conf', 'src': '/srv/httpd.j2'}},
              {'name': 'ensure apache is running',
                'service': {'name': 'httpd', 'state': 'started'}}],
    'vars': {'http_port': 80, 'max_clients': 200}}]

Можно также сохранять данные из Python в формате YAML:

In [22]: with open('verify-apache.yml', 'w') as opened_file:
   ...: yaml.dump(verify_apache, opened_file)
   ...:
   ...:
   ...:

Еще один язык, широко применяемый для представления структурированных данных, — XML (Extensible Markup Language, расширяемый язык разметки). В нем используются иерархические документы, состоящие из маркированных элементов. Исторически так сложилось, что многие веб-системы задействовали XML для передачи данных, в частности, для RSS-каналов. С помощью RSS-каналов отслеживают обновления веб-сайтов и оповещают о них пользователей, а также отслеживают публикации статей в различных источниках. RSS-каналы применяют страницы в формате XML. Python включает библиотеку xml, предназначенную для работы с XML-документами и умеющую отображать иерархические структуры XML-документов как древовидные структуры данных. Узлы дерева играют роль элементов XML, а иерархия моделируется с помощью взаимосвязи «родительский элемент — дочерний элемент». Самый верхний родительский узел называется корневым элементом. Произвести синтаксический разбор XML-документа RSS и получить его корневой элемент можно следующим образом:

In [1]: import xml.etree.ElementTree as ET
In [2]: tree = ET.parse('http_feeds.feedburner.com_oreilly_radar_atom.xml')

In [3]: root = tree.getroot()

In [4]: root
Out[4]: <Element '{http://www.w3.org/2005/Atom}feed' at 0x11292c958>

Обход дерева можно выполнить посредством прохода в цикле дочерних узлов:

In [5]: for child in root:
   ...: print(child.tag, child.attrib)
   ...:
{http://www.w3.org/2005/Atom}title {}
{http://www.w3.org/2005/Atom}id {}
{http://www.w3.org/2005/Atom}updated {}
{http://www.w3.org/2005/Atom}subtitle {}
{http://www.w3.org/2005/Atom}link {'href': 'https://www.oreilly.com'}
{http://www.w3.org/2005/Atom}link {'rel': 'hub',
                                  'href': 'http://pubsubhubbub.appspot.com/'}
{http://www.w3.org/2003/01/geo/wgs84_pos#}long {}
{http://rssnamespace.org/feedburner/ext/1.0}emailServiceId {}
...

XML позволяет использовать пространства имен (группировать данные с помощью тегов). В XML перед тегами в скобках указываются пространства имен. Если структура иерархии известна, можно искать элементы на основе их путей. Для удобства можно передать ассоциативный массив с описанием пространств имен:

In [108]: ns = {'default':'http://www.w3.org/2005/Atom'}
In [106]: authors = root.findall("default:entry/default:author/default:name", ns)

In [107]: for author in authors:
    ...: print(author.text)
    ...:
Nat Torkington
VM Brasseur
Adam Jacob
Roger Magoulas
Pete Skomoroch
Adrian Cockcroft
Ben Lorica
Nat Torkington
Alison McCauley
Tiffani Bell
Arun Gupta

Вы можете столкнуться также с необходимостью работы с данными в виде значений, отделенных друг от друга запятыми (CSV). Этот формат часто применяется для данных в электронных таблицах. Чтобы было удобно их читать, можно воспользоваться модулем csv Python:

In [16]: import csv
In [17]: file_path = '/Users/kbehrman/Downloads/registered_user_count_ytd.csv'

In [18]: with open(file_path, newline='') as csv_file:
   ...:        off_reader = csv.reader(csv_file, delimiter=',')
   ...:        for _ in range(5):
   ...:             print(next(off_reader))
   ...:
['Date', 'PreviousUserCount', 'UserCountTotal', 'UserCountDay']
['2014-01-02', '61', '5336', '5275']
['2014-01-03', '42', '5378', '5336']
['2014-01-04', '26', '5404', '5378']
['2014-01-05', '65', '5469', '5404']

Объект csv.reader проходит в цикле CSV-файл построчно, благодаря чему можно обрабатывать данные по одной строке за раз. Такой способ обработки файлов особенно удобен для больших CSV-файлов, которые нежелательно полностью загружать в оперативную память. Конечно, если нужно выполнять вычисления над столбцами из нескольких строк и файл не слишком велик, имеет смысл загрузить его в память целиком.

Пакет Pandas — краеугольный камень мира науки о данных. Он содержит структуру данных pandas.DataFrame, ведущую себя наподобие таблицы данных, аналогичной электронной таблице с очень широкими возможностями. DataFrame — идеальный инструмент для статистического анализа табличных данных или каких-либо операций с их столбцами или строками. Это сторонняя библиотека, которую необходимо установить с помощью pip. Существует множество способов загрузки данных в объекты DataFrame, один из наиболее распространенных — загрузка из CSV-файла:

In [54]: import pandas as pd

In [55]: df = pd.read_csv('sample-data.csv')

In [56]: type(df)
Out[56]: pandas.core.frame.DataFrame

Можете просмотреть несколько первых строк объекта DataFrame с помощью метода head:

In [57]: df.head(3)
Out[57]:
   Attributes        open      high      low       close       volume
0     Symbols           F         F        F           F            F
1        date         NaN       NaN      NaN         NaN          NaN
2  2018-01-02     11.3007    11.4271 11.2827      11.4271     20773320

А основные статистические показатели DataFrame можно вывести с помощью метода describe:

In [58]: df.describe()
Out[58]:
         Attributes     open    high    low    close    volume
count           357      356     356    356      356       356
unique          357      290     288    297      288       356
top      2018-10-18   10.402   8.3363  10.2    9.8111 36298597
freq              1        5        4     3         4        1

Или можно просмотреть отдельный столбец данных, указав его название в квадратных скобках:

In [59]: df['close']
Out[59]:
0        F
1      NaN
2  11.4271
3  11.5174
4  11.7159
    ...
352   9.83
353   9.78
354   9.71
355   9.74
356   9.52
Name: close, Length: 357, dtype: object

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

Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок

Для Хаброжителей скидка 25% по купону — Python

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Теги:
Хабы:
Всего голосов 7: ↑6 и ↓1+5
Комментарии2

Публикации

Информация

Сайт
piter.com
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия