Розробка і тестування chef кукбуков за допомогою інструменту Sparrowdo

Привіт! Про розробку chef кукбуков і пов'язаної з нею інфраструктурою написано чимало, так і інструментів в цій області існує вже достатньо. Серед них можна перерахувати такі рішення як vagrant, test kitchen, food critic, chef spec, minitest-chef-handler serverspec, inspec. Всі вони, в тій чи іншій мірі спрощують і прискорюють промислову розробку і тестування chef кукбуков і настроюється ними інфраструктури.
Якщо дана область близька для вас і ви так-таки має деяке відношення до мови Perl ( точніше Perl6 — то ласкаво просимо в топік.
Отже, сьогодні я розповім як я використовую Sparrowdo при розробці та тестуванні chef кукбуков.

Для початку трохи вступній.
Що таке Sparrowdo?
Sparrowdo — це надбудова на систему плагінів sparrow, яка дозволяє запускати дані плагіни по ssh на віддалених серверах. У свою чергу, плагіни sparrow — різні сценарії автоматизації, написаних в основному ( але не обмежуються даними мовами ) на Perl5 і Bash. Про всім цьому мною вже був написаний цілий ряд статей на habrahabr, кому цікаво, може набрати пошуковий запит зі словом sparrow і, відповідно почитати. Але, що б для необізнаного читача було зрозуміло, все це дуже схоже на ідеологію ansible, коли у вас є централізований сервер, з якого ви запускаєте різні задачі на інших віддалених серверах.
Отже, ви можете запускати різні плагіни sparrow після або запуску chef клієнта на сервері, і виконувати різні перевірки, визначають процедуру деплоймента пройшла успішна або задовольняє певним умовам.
Все це дуже схоже на написання сценаріїв в стилі serverspec або inspec з тією лише різницею, що плагіни sparrow — багатоцільові, і не обмежуються завданнями тестування і аудиту, в принципі через sparrow ви можете реалізувати будь-яку іншу логіку, яку ви з тих чи інших причин не хотіли б запихати в chef кукбуки.
насправді sparrowdo так зручно "вписався" завдання з автоматичної настройки серверів, що я навіть запускаю їм власне chef клієнт… Але, досить теорії, давайте розглянемо конкретний простий, але показовий приклад ...
Пишемо кукбук для установки nginx + tomcat і тестуємо його з допомогою sparrowdo
Для простоти прикладу буду використовувати ec2 інстанси з передвстановленим chef клієнтом і налаштованим на локальний chef сервер. Тобто всі питання, пов'язані з початковим налаштуванням системи залишимо "за дужками". Далі у нас є ssh ключ до нашого инстансу і логін з sudo:
$ ssh remote.server 

Тепер відійдемо трохи в бік від питань доступу до сервера і напишемо наш символічний кукбук, нам потрібно:
  • встановити nginx
  • встановити tomcat
  • якщо заданий атрибут tomcat_redirect налаштувати проксіювання всіх запитів, що надходять до nginx в tomcat сервер, запущений на localhost порт 8080
Пишемо кукбук
Код тривіальний, знову-таки ж фокус цієї статті не на навчанні написання chef кукбуков, а на використанні chef в зв'язці з sparrowdo/sparrow
# recipes/default.rb

package 'nginx'

package 'tomcat7'

service 'nginx' do
action [ :enable, :start ]
end

service 'tomcat7' do
action [ :enable, :start ]
end

template '/etc/nginx/conf.d/default.conf' do
source 'nginx.conf'
mode '644'
variables :tomcat_redirect => node[:tomcat_redirect]
notifies :restart, 'service[nginx]', :delayed
end

# attributes/default.rb

default[:tomcat_redirect] = false

# cat templates/default/nginx.conf

server {

listen 80 default_server;

server_name _;

root /usr/share/nginx/html;
index index.html index.htm;

<% if @tomcat_redirect %>

location / {
proxy_pass http://127.0.0.1:8080;
}

<% else %>
location / {
try_files $uri $uri/ $uri.html =404;
}
<% end %>

error_page 404 /404.html;
location = /404.html {
}

# redirect server error pages to the static page /50x.html
#

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}

}

Думаю, що коментарі з кодом кукбука зайві, зауважу лише, що по дефолту nginx не виконує проксіювання на tomcat, так як атрибут
tomcat_redirect
встановлено в false. Ну і наостанок назвемо кукбук nginx-app і завантажимо його в chef сервер:
# cat metadata.rb
name 'app-nginx'
version '0.0.1'

$ knife cookbook upload app-nginx -o ../

Тепер, власне запустимо створений кукбук на нашому сервері.
Пишемо sparrowdo сценарій
Sparrowdo сценарій — код написаний на Perl6 і запускає завдання на віддаленому сервері. Завдання — це не що інше як sparrow плагіни з параметрами. Як я вже говорив, ми будемо використовувати sparrow в тому числі і для запуску chef клієнта
$ cat sparrowfile

task_run %(
task => "set up chef run list an attributes",
plugin => "file",
parameters => %(
target => "/tmp/chef.json",
content => q:to/JSON/,
{
"run_list" : [
"recipe[nginx-app]",
],
"tomcat_redirect" : false
}
JSON
),
);

task_run %(
task => "run chef-client",
plugin => "bash",
parameters => %(
command => "chef-client --color --json /tmp/chef.json"
),

);

Невеликі пояснення з кодом.
  • Файл зі сценарієм повинен називатися
    sparrowfile
    і лежати в тій же директорії звідки ви будете запускати sparrowdo клієнта, є сенс тримати його в каталозі кукбука — наочно і завжди під рукою.
  • У цьому прикладі використовуються два sparrow плагіна: file — для створення файлів і bash — для запуску довільних команд на Bash, як вже говорилося вони запускаються з параметрами за допомогою функції
    task_run
    , також параметр
    task
    у викликах цієї функції додає довільний текстовий опис виконуваної задачі.
Тепер можна запускати сценарій. Т. к. на заданому сервері sparrow клієнт ще не встановлений, запускаємося з опцією --bootstrap, попросивши sparrowdo встановити спочатку клієнта, який і буде виконувати всі завдання:
$ sparrowdo --http_proxy=$http_proxy --https_proxy=$https_proxy --host=remote.server --ssh_user=root --no_sudo --no_index_update
running sparrow tasks on remote.server ...
target OS is - centos6
push task <set up chef run list an attributes> plg <file> OK
push task <run chef-client> plg <bash> OK
set up task box file - /tmp/sparrowdo-box.json - OK
public@file is uptodate (0.0.2)
public@bash is uptodate (0.1.1)

running task box from /tmp/sparrowdo-box.json ...

<set-up-chef-run-list-an-attributes>

/ started

set target content
target created
set mode to target 644
ok scenario succeeded
ok output match /target (created|removed)/
ok output match 'set target content'
STATUS SUCCEED

<run-chef-client>

/ started

[2016-10-19T10:02:48+00:00] INFO: Породження chef instance to converge...
[2016-10-19T10:02:48+00:00] INFO: *** Chef 11.16.4 ***
[2016-10-19T10:02:48+00:00] INFO: Chef-client pid: 5389
[2016-10-19T10:02:49+00:00] INFO: Setting the run_list to ["recipe[nginx-app]"] from CLI options
[2016-10-19T10:02:49+00:00] INFO: Run List is [recipe[nginx-app]]
[2016-10-19T10:02:49+00:00] INFO: Run List expands to [nginx-app]
[2016-10-19T10:02:49+00:00] INFO: Starting Chef Run for sandbox-generic-ci-i-ef7cbedf
[2016-10-19T10:02:49+00:00] INFO: Running start handlers
[2016-10-19T10:02:49+00:00] INFO: Start handlers complete.
[2016-10-19T10:02:49+00:00] INFO: HTTP Request Returned 404 Not Found:
[2016-10-19T10:02:50+00:00] INFO: Loading cookbooks [nginx-app@0.0.1]
[2016-10-19T10:02:50+00:00] INFO: Processing package[nginx] action install (nginx-app::default line 1)
[2016-10-19T10:02:53+00:00] INFO: Processing package[tomcat7] action install (nginx-app::default line 3)
[2016-10-19T10:02:53+00:00] INFO: Processing service[nginx] action enable (nginx-app::default line 5)
[2016-10-19T10:02:53+00:00] INFO: Processing service[nginx] action start (nginx-app::default line 5)
[2016-10-19T10:02:53+00:00] INFO: Processing service[tomcat7] action enable (nginx-app::default line 9)
[2016-10-19T10:02:53+00:00] INFO: Processing service[tomcat7] action start (nginx-app::default line 9)
[2016-10-19T10:02:53+00:00] INFO: Processing template[/etc/nginx/conf.d/default.conf] action create (nginx-app::default line 13)
[2016-10-19T10:02:53+00:00] INFO: Chef Run complete in seconds 3.604494597
[2016-10-19T10:02:53+00:00] INFO: Running report handlers
[2016-10-19T10:02:53+00:00] INFO: Report handlers complete
bash-command-done
ok scenario succeeded
ok output match 'bash-command-done'
STATUS SUCCEED

Перший запуск сценарію відпрацював усешно, ми бачимо, що chef клієнт встановив необхідні пакети та налаштував їх, дотримуючись логіки, заданої в кукбуке.
Трохи змінимо sparrowdo сценарій, мінімізувавши висновок від шеф клієнта при наступних запусках:
task_run %(
task => "run chef-client",
plugin => "bash",
parameters => %(
command => "chef-client --color --json /tmp/chef.json -l error"
),
);

Тепер настав час додати кілька перевірок, що наш деплоймент завершився успіхом, в саме:
  • сервіс nginx видно в списку процесів
  • сервіс tomcat видно в списку процесів
Це може здатися зайвим, оскільки chef гарантує нам обробку/виведення всіх помилок, пов'язаних із запуском сервісів, однак досвід показує, що це не завжди досить, наприклад сервіс може впасти трохи пізніше, після того, як chef клієнт успішно відпрацював. І потім ніколи не завадить написати ще пару "паралельних" тестів ( які до речі можна запускати поза контекстом chef клієнта ), тим більше, що з sparrowdo це зробити дуже просто. Додамо в наш sparrowdo сценарій пару завдань :
task_run %(
task => 'check nginx process',
plugin => 'proc-validate',
parameters => %(
pid_file => '/var/run/nginx.pid',
footprint => 'nginx.*master'
)
);

task_run %(
task => 'check tomcat7 process',
plugin => 'proc-validate',
parameters => %(
pid_file => '/var/run/tomcat7.pid',
footprint => 'java'
)
);

Тут ми використовували плагін proc-validate, який по заданому PID файлу перевіряє існування процесу, так само шукає його "сліду" у списку запущених процесів:
$ sparrowdo --http_proxy=$http_proxy --https_proxy=$https_proxy --host=remote.server --ssh_user=root --no_sudo --no_index_update
running sparrow tasks on remote.server ...
target OS is - centos6
push task <set up chef run list an attributes> plg <file> OK
push task <run chef-client> plg <bash> OK
push task <check nginx process> plg <proc-validate> OK
push task <check tomcat7 process> plg <proc-validate> OK
set up task box file - /tmp/sparrowdo-box.json - OK
public@file is uptodate (0.0.2)
public@bash is uptodate (0.1.1)
public@proc-validate is uptodate (0.0.5)

running task box from /tmp/sparrowdo-box.json ...

<set-up-chef-run-list-an-attributes>

/ started

set target content
target created
set mode to target 644
ok scenario succeeded
ok output match /target (created|removed)/
ok output match 'set target content'
STATUS SUCCEED

<run-chef-client>

/ started

bash-command-done
ok scenario succeeded
ok output match 'bash-command-done'
STATUS SUCCEED

<check-nginx-process>

/ started

pid_file - /var/run/nginx.pid
pid file exists
pid:4526
process footprint: 4526 nginx: master process /usr/ 31:47
ok scenario succeeded
ok output match /pid_file - \S+/
ok output match 'pid file exists'
ok output match /pid:\d+/
ok output match /process footprint:/
ok 'process footprint: 4526 nginx: master process /usr/ 31:47' match /nginx.*master/
STATUS SUCCEED

<check-tomcat7-process>

/ started

pid_file - /var/run/tomcat7.pid
pid file exists
pid:29458
process footprint: 29458 /usr/lib/jvm/java-1.6.0/bin 22:11:25
ok scenario succeeded
ok output match /pid_file - \S+/
ok output match 'pid file exists'
ok output match /pid:\d+/
ok output match /process footprint:/
ok 'process footprint: 29458 /usr/lib/jvm/java-1.6.0/bin 22:11:25' match /java/
STATUS SUCCEED

Відмінно. Ми бачимо, що наші сервіси дійсно запущені. Ще одним приимуществом даного підходу є те, що ви всгеда можете запустити подібні перевірки на вже задеплоенном сервері, не занедбуючи при цьому самого chef клієнта.
Гаразд, йдемо далі. Перевіримо доступність наших сервісів http. Для цього скористаємося утилітою curl, ось що потрібно додати в наш sparrowdo сценарій:
task_run %(
task => 'install curl',
plugin => 'package-generic',
parameters => %(
list => 'curl',
)
);

task_run %(
task => 'check nginx http port',
plugin => 'bash',
parameters => %(
command => 'sleep 5; curl --retry 2 --noproxy 127.0.0.1 -f -o /dev/null -D - http://127.0.0.1',
)
);

task_run %(
task => 'check tomcat http port',
plugin => 'bash',
parameters => %(
command => 'sleep 5; curl --retry 2 --noproxy 127.0.0.1 -f -o /dev/null -D - http://127.0.0.1:8080',
)
);

...
Запустимо сценарій:
$ sparrowdo --http_proxy=$http_proxy --https_proxy=$https_proxy --host=remote.server --ssh_user=root --no_sudo --no_index_update

# частину висновку опущена ...

<install-curl>

/ started

package installer

/modules/ням/ started

trying to install curl ...
installer - yum
Installed Packages
curl.x86_64 7.19.7-37.el6_4 @base/$releasever
ok scenario succeeded
ok output match 'Installed'
STATUS SUCCEED

<check-nginx-http-port>

/ started

% Total % Received % Xferd Average Speed Time Time Time Current
Dload Total Upload Spent Left Speed
102 3698 102 3698 0 0 3218k 0 --:--:-- --:--:-- --:--:-- 0
HTTP/1.1 200 OK
Server: nginx/1.0.15
Date: Wed, 19 Oct 2016 11:30:51 GMT
Content-Type: text/html
Content-Length: 3698
Last-Modified: Fri, 26 Apr 2013 20:36:51 GMT
Connection: keep-alive
Accept-Ranges: bytes

bash-command-done
ok scenario succeeded
ok output match 'bash-command-done'
STATUS SUCCEED

<check-tomcat-http-port>

/ started

% Total % Received % Xferd Average Speed Time Time Time Current
Dload Total Upload Spent Left Speed
100 11197 0 11197 0 0 1195k 0 --:--:-- --:--:-- --:--:-- 1366k
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Transfer-Encoding: chunked
Date: Wed, 19 Oct 2016 11:30:56 GMT

bash-command-done
ok scenario succeeded
ok output match 'bash-command-done'
STATUS SUCCEED

Як ми бачимо наші сервіси доступні по http. Зауважу, попередньо ми встановили утиліту curl, скориставшись плагіном package-generic для установки пакетів.
Ну, і нарешті виставимо атрибут
tomcat_redirect
true, змусивши nginx проксировать усі запити tomcat і перевіримо що це відбувається.
Встановлюємо атрибут:
task_run %(
task => "set up chef run list an attributes",
plugin => "file",
parameters => %(
target => "/tmp/chef.json",
content => q:to/JSON/,
{
"run_list" : [
"recipe[nginx-app]",
],
"tomcat_redirect" : true
}
JSON
),
);

Додаємо параметр
expect_stdout
запуск плагіна
bash
, який змусить його перевірити STDOUT виконуваної команди по заданому regex:
task_run %(
task => 'check nginx http port',
plugin => 'bash',
parameters => %(
command => 'sleep 5; curl --retry 2 --noproxy 127.0.0.1 -f http://127.0.0.1 | head -n 10',
expect_stdout => 'Apache Tomcat'
)
);

Запустимо сценарій:
$ sparrowdo --http_proxy=$http_proxy --https_proxy=$https_proxy --host=remote.server --ssh_user=root --no_sudo --no_index_update

# частину висновку опущена ...

<check-nginx-http-port>

/ started

<!DOCTYPE html>

<html lang="en">
<head>
<title>Apache Tomcat/7.0.57</title>
<link href="favicon.ico" rel="icon" type="image/x-icon" />
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link href="tomcat.css" rel="stylesheet" type="text/css" />
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Total Upload Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (23) Failed writing body (146 != 3151)
bash-command-done
ok scenario succeeded
ok output match 'bash-command-done'
ok output match /Apache Tomcat/
STATUS SUCCEED

<check-tomcat-http-port>

/ started

% Total % Received % Xferd Average Speed Time Time Time Current
Dload Total Upload Spent Left Speed
100 11197 0 11197 0 0 3364k 0 --:--:-- --:--:-- --:--:-- 0
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Transfer-Encoding: chunked
Date: Wed, 19 Oct 2016 12:03:02 GMT

bash-command-done
ok scenario succeeded
ok output match 'bash-command-done'
STATUS SUCCEED

Висновок
На цьому простому прикладі ми навчилися використовувати sparrowdo/sparrow в процесах розробки і тестування chef кукбуков, а саме:
  • запускати chef клієнта з заданими параметрами і атрибутами на зазначених хостах
  • перевіряти існування процесів
  • робити найпростіші перевірки на доступність web сервісів
  • встановлювати інструменти, необхідні для тестування.
насправді написати можна було ще багато чого. Кейсів для використання sparrowdo і chef дійсно велика кількість. Просто візьміть готові плагіни тут або ж напишіть свій, адже це дійсно не складно і почніть використовувати sparrowdo у вашій розробці.
Вся фішка системи sparrow, вигідно відрізняє її від інших схожих інструментів, таких як serverspec/inspec в тому, що функціональність не зашита жорстко "в ядрі", але користувач може легко і швидко писати свої плагіни, що підходять під його реалії та одразу використати їх за допомогою sparrowdo, ви навіть можете "компілювати" більш складні сценарії, на основі sparrow плагінів з допомогою так званих sparrowdo модулів, які пишуться на Perl6 ( про це, якщо буде інтерес, можна написати окрему статтю ).
Якщо ця стаття викликала у вас інтерес — пишіть, коментуйте, задавайте питання і… конструктивно критикуйте :)) буду вдячний. Як правило, єдиним центром для документації і сховищем плагінів sparrow є сайт https://sparrowhub.org
Дякую.
PS В кінці статті, як зазвичай, простенький питання, побічно відноситься до теми статті.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.