Здравствуйте! О разработке 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 сервер. Т.е. все вопросы, связанные с первоначальной настройкой системы оставим "за скобками". Далee у нас есть 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 target mode to 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: Forking 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 3.604494597 seconds
[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 target mode to 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/yum/ 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  Upload   Total   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  Upload   Total   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  Upload   Total   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  Upload   Total   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, выгодно отличающая ee от других похожих инструментов, таких как serverspec/inspec в том, что функциональность не зашита жестко "в ядре", но пользователь может легко и быстро писать свои плагины, подходящие под его реалии и тут же использовать их посредством sparrowdo, вы даже можете "компилировать" более сложные сценарии, на основе sparrow плагинов с помощью так называемых sparrowdo модулей, которые пишутся на Perl6 ( об этом, если будет интерес, можно будет написать отдельную статью ).


Если данная статья вызвала у вас интерес — пишите, комментируйте, задавайте вопросы и… конструктивно критикуйте :)) буду признателен. Как обычно, единым центром для документации и репозиторием плагинов sparrow является сайт https://sparrowhub.org


Спасибо.


PS В конце статьи, как обычно, простенький вопрос, косвенно относящийся к теме статьи.

Используете ли вы языки программирования Perl5 или Perl6?

Проголосовало 12 человек. Воздержалось 5 человек.

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

Поделиться с друзьями
-->

Комментарии (0)