J3qx

information archive

Почему мы уверены в том, что развернули

Posted by j3qx на Май 21, 2017

image
Часто бывает, когда что-то не работает. И никто не хочет, чтобы что-то не работало по его вине. В контексте больших инфраструктур и распределенных приложений ошибка конфигурации может быть фатальной.

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

Статья будет интересна командам, которые практикуют DevOps или SRE, ответственным Dev, и прочим хорошим людям.

Следует сказать, что реализовывать концепцию Infrastructure as Code можно и без тестирования. И даже будет работать. Но разве есть предел совершенству?

Тестирование к нам пришло из мира разработки, тестирование – это целая огромная эпопея, которая включает в себя такие варианты реализаций:

  • Юнит тесты (тестируют код) — есть функция, которая принимает на вход один параметр, проводит вычисления и возвращает результат. Юниты — проверка того, что результат соответствует ожидаемому, грубо говоря, что 1 == 1.
  • Интеграционные тесты (тестируют взаимосвязь компонентов) — есть приложение, которому необходима база для корректной работы, и в ней табличка `users`. Этот тест проверит что есть база, что есть табличка, что все готово к работе.
  • Системные тесты (тестируют приложение в целом) — есть приложение, оно должно конвертировать файл. Тест проверяет, что приложение конвертирует, и результат нас устраивает.
  • Дымовые тесты (имитируют поведение пользователя) — тестирует, что пользователь можетоткрыть в браузере сайт, сделать log in, загрузить изображение, и сконвертировать его.

И тут может прийти лживое осознание, что в нашем мире Ansible/Chef/Puppet/Salt все очень примитивно, все очень просто, и в экосистеме наших тулзовин нету реализации чего-то подобного.

А вот как-бы не так.

Все это есть, все это используют уже давно и успешно.

Чем тестировать

Уточню сразу, что мы не будем рассматривать высокоуровневое программирование для Configuration management. Например, если вы написали свой Ansible модуль, или Chef LWRP – ваших знаний достаточно, чтобы понять как правильно тестировать ваше творение.

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

Везде будем решать одну задачу для примера: мы должны убедиться в том, что пакет ‘apache2‘ у нас установлен, и сервис ‘apache2‘ запущен и работает. В конце проверяем, что порт 80 кто-то слушает.

ServerSpec

image

Первый фреймворк для тестирования, который мы рассмотрим — Serverspec.

Пример использования:

require 'spec_helper'

describe package('apache2') do
  it { should be_installed }
end

describe service('apache2') do
  it { should be_enabled   }
  it { should be_running   }
end

describe port(80) do
  it { should be_listening }
end

 

InSpec

image

Второй фреймворк — InSpec.
Синтаксис идентичный Serverspec.

Testinfra

image

Третий фреймворк – Testinfra.

def test_apache_is_installed(Package):
    apache = Package("apache2")
    assert apache.is_installed

def test_apache_running_and_enabled(Service):
    apache = Service("apache2")
    assert apache.is_running
    assert apache.is_enabled

def test_apache_port(Socket):
    sock = Socket("tcp://80")
    assert sock.is_listening  

 

Goss

image

Четвертый фреймворк – Goss.

package:
  apache2:
    installed: true
service:
  apache2:
    enabled: true
    running: true
port:
  tcp:80:
    listening: true

 

Serverspec/InSpec/Testinfra/Goss?

Как видно по синтаксису – есть из чего выбрать. Кому что больше нравится, то лучше всего и использовать. Например, если у вас Chef – отлично ляжет InSpec или Serverspec. Если Ansible или Salt – круто подойдет Testinfra или Goss.

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

Окей, выбрали. Что же именно тестировать?

Что тестировать

Несколько недель назад мы общались в нашем DevOps Community по поводу того, что именно нужно тестировать, нужно ли вообще что-то тестировать, сколько лет лететь до Trappist-1 и так далее.

Например, ctrlok считает что тестировать декларативные штуки не правильно. И я с ним согласен.

Оговорюсь, что точно не нужно тестировать:

  • Разные декларативные штуки (наличие пакета, версию пакета, присутствие файла) – обо всем этом позаботится ваш Configuration management.

Что нужно тестировать:

  1. Вещи, которые когда-то/недавно уже ломались
  2. Вещи, которые потенциально могут поломаться
  3. Вещи, которые кто-то (коллега) может поломать из-за незнания
  4. Вещи, без которых ничего точно работать не будет

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

Для того, чтобы правильно оценить приложение и подготовить его для тестирования – нужно думать как тестировщик. Или, например, проконсультироваться у команды QA.

Во время общения необходимо продумать основные тест-кейсы и попытаться покрыть все из них.

Практический пример (на нашем приложении):

  • Конвертация из pdf в html
  • Конвертация из html в pdf
  • Конвертация из doc/docx в pdf

В нашем случае отдельные пункты – это отдельные модули приложения, именно так мы их и будем тестировать.

Давайте тестировать!

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

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

# Validate binary exists and working
describe bash('pdf2htmlEX --version') do
  its('stderr') { should match /pdf2htmlEX version 0.14.6/ }
  its('exit_status') { should eq 0 }
end 

Теперь давайте протестируем, что этот бинарник реально умеет конвертировать тестовый документ, и результат нас устраивает:

# Try to convert and validate result html
describe bash('pdf2htmlEX /opt/test/pdf-sample.pdf /tmp/pdf-sample.html') do
  its('stderr') { should match /Working/ }
  its('exit_status') { should eq 0 }
end

describe file('/tmp/pdf-sample.html') do
  it { should exist }
  its('content') { should match /<!DOCTYPE html>/}
  its('size') { should eq 267189 }
end

В данном случае, если тест пройдет успешно – мы можем четко декларировать, что модуль приложения, который отвечает за конвертацию из PDF в HTML работает. Мало того, он работает корректно, нас устраивает результат его работы.

Сложно и долго делать такой тест? Не думаю.

Сколько это сэкономит денег бизнесу? У каждого своя цена ошибки.

Benefits

Стоит сказать, что тестировать окружения мы начали не сразу. Зачем тратить время на такие вещи – это же очевидно, что все мы супермены, и пишем код для Configuration Management сразу без ошибок?

И такой подход работает, когда DevOps команда состоит из 1-2 человек. В таком случае каждый инженер знает как должно работать приложение, знает как готовить для него окружение, и как его «потыкать» — посмотреть, что оно будет работать на площадке, которую он только что подготовил.

Все заканчивается тогда, когда в production среде все должно работать, но не работает. Начинается debug процесс руками на проде или откаты-роллбеки, а каждая минута очень дорого стоит для бизнеса.

Именно поэтому тестирование инфраструктуры – это инвестиция в будущее.
Теперь, когда что-то ломается – мы абсолютно уверены, что наша часть работы была сделана на 100%, и с нашей стороны все вопросы закрыты.
Поэтому мы и уверены в том, что только что развернули.

Выводы

Все мы работаем с приложениями, которые очень часто меняются в очень динамичном мире благодаря нашим же правильно настроенным процессам – CI  и CD. Мы все очень серьезно относимся к работе самих приложений, тестируя со всех сторон одно и тоже. И в это же время халатно относиться к инфраструктуре, на которой это приложение работает – не очень разумно. Тем более, это чревато большими последствиями.

Для себя мы решили, что будем тестировать в таких случаях:

  • если в модуле системы есть сложная логика (комплексность)
  • если модуль уже сейчас часто ломается (доступность)
  • если нужно передать специфичные знания (коммуникация)
  • если ошибка будет стоить нам больше Х денег (бизнес-ценность)

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

А сколько процентов вашей инфраструктуры покрыто тестами?

© https://habrahabr.ru/post/323472/

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

 
%d такие блоггеры, как: