Chef CentOS v11
Chef сервер под CentOS 6.3
Все очень призрачно...
За пару месяцев что я работаю с шефом произошли заметные изменения в процедуре установки. Точнее, новая процедура отличается от старой практически на 100%.
Я делаю установку внутри линукс-контейнера, потому я допускаю что есть отличия от установки на "нормальную" систему.
Скачать
Я брал здесь:
https://opscode-omnitruck-release.s3.amazonaws.com/el/6/x86_64/chef-server-11.0.4-1.el6.x86_64.rpm https://opscode-omnitruck-release.s3.amazonaws.com/el/6/x86_64/chef-11.4.0-1.el6.x86_64.rpm
Но вообще-то узнать последнюю версию можно тут: http://www.opscode.com/chef/install/
Мне не очень нравится идея комбайна - эта РПМка тянет внутри себя кучу всего, включая Postgress, RabbitMQ и т.д.
Управляется все через новый механизм initctl
Немного забегая вперед, вот мой вывод:
Конфигурация
Запускаю:
После завершения длительного процесса у меня запущен весь комплекс сервисов:
Базовое тестирование
Достаточно длительный процесс (по крайне мере на ограниченных ресурсах контейнера)
У меня возникли некоторые проблемы (пока я не выявил сказалось ли это на работоспособности сервера)
Search API endpoint /search/environment GET when searching for a single environment by name should have more than just the target of our environment search on the system should return status code 200 and a single environment POST targeted toward many environments with body of {"possibly_nested"=>["default_attributes", "top", "middle", "bottom"], "the_name"=>["name"], "not_found"=>["foo", "bar", "baz", "totally_not_a_real_field"], "empty"=>[]} should succeed, and return multiple environments (FAILED - 1) /search/node GET when searching for a single node by name should have more than just the target of our node search on the system should return status code 200 and a single node POST
Failures: 1) Search API endpoint /search/environment POST targeted toward many environments with body of {"possibly_nested"=>["default_attributes", "top", "middle", "bottom"], "the_name"=>["name"], "not_found"=>["foo", "bar", "baz", "totally_not_a_real_field"], "empty"=>[]} should succeed, and return multiple environments Failure/Error: r.should look_like search_success_response 'total' should match '6', but we got '7' instead. # ./lib/pedant/rspec/search_util.rb:99:in `block (2 levels) in performing_a_search' # ./lib/pedant/rspec/search_util.rb:670:in `with_search_polling' # ./lib/pedant/rspec/search_util.rb:86:in `block in performing_a_search' Finished in 5 minutes 43.13 seconds 70 examples, 1 failure Failed examples: rspec ./lib/pedant/rspec/search_util.rb:85 # Search API endpoint /search/environment POST targeted toward many environments with body of {"possibly_nested"=>["default_attributes", "top", "middle", "bottom"], "the_name"=>["name"], "not_found"=>["foo", "bar", "baz", "totally_not_a_real_field"], "empty"=>[]} should succeed, and return multiple environments
Если я понимаю правильно - ответ содержит 7 результатов вместо ожидаемых 6 но в json ниже я не могу найти ни 6 ни 7 атрибутов. Тут есть неясность.
{ "possibly_nested"=> [ "default_attributes", "top", "middle", "bottom" ], "the_name"=> [ "name" ], "not_found"=> [ "foo", "bar", "baz", "totally_not_a_real_field" ], "empty"=> [ ] }
настройка knife
Для работы с 10-м шефом использовался "нож", в 11 он тоже присутствует Подкладываю в ~/.chef файлы ключей:
Запускаем knife configure -i
Обратить внимание - у меня при указании localhost вместо https://172.31.0.2:443 не работал бутстрап
Нод пока нет, но все равно проверяю ...
Конфиг .chef/knife.rb выглядит где-то так:
log_level :info log_location STDOUT node_name 'root' client_key '/root/.chef/root.pem' validation_client_name 'chef-validator' validation_key '/root/.chef/chef-validator.pem' chef_server_url 'https://localhost:443' syntax_check_cache_path '/root/.chef/syntax_check_cache'
chef-server-ctl
Управлять сервером теперь тоже по новому. Вобщем, хелп понятный - особо расписывать нечего. chef-server]# chef-server-ctl status
run: bookshelf: (pid 1226) 9024s; run: log: (pid 1225) 9024s run: chef-expander: (pid 1162) 9030s; run: log: (pid 1161) 9030s run: chef-server-webui: (pid 1391) 9002s; run: log: (pid 1390) 9002s run: chef-solr: (pid 1136) 9031s; run: log: (pid 1135) 9031s run: erchef: (pid 1578) 8984s; run: log: (pid 1271) 9018s run: nginx: (pid 1558) 8986s; run: log: (pid 1557) 8986s run: postgresql: (pid 1036) 9042s; run: log: (pid 1035) 9042s run: rabbitmq: (pid 702) 9059s; run: log: (pid 701) 9059s
Настройка клиентов
Самый простой способ - это сделать chef bootstrap Звучит смешно но это так )
#knife bootstrap 172.31.0.5 --node-name 172.31.0.5 Bootstrapping Chef on 172.31.0.5 Failed to authenticate root - trying password auth
После чего на клиенте можно запускать
# chef-client Starting Chef Client, version 11.4.0 resolving cookbooks for run list: [] Synchronizing Cookbooks: Compiling Cookbooks... [2013-02-18T08:03:14-05:00] WARN: Node 172.31.0.5 has an empty run list. Converging 0 resources Chef Client finished, 0 resources updated
Важно
Везде используются FQDN потому без записей в в DNS или /etc/hosts не обойтись.
Например когда у меня hostname сервера резолвился в 127.0.0.1 то именно этот адрес передавался в запросах и клиенты пробовали получить с него данные. Ничего, конечно же, не работало. Лечить так:<BR> Было: <PRE> 127.0.0.1 localhost centos-chefserver 172.31.0.2 centos-chefserver
Нужно:
127.0.0.1 localhost 172.31.0.2 centos-chefserver
И потом
chef-server-ctl reconfigure
Поваренные книги и рецепты, роли и вообще конфигурация сервера
cookbook
Создать поваренную книгу:
#knife cookbook create demo ** Creating cookbook demo ** Creating README for cookbook: demo ** Creating CHANGELOG for cookbook: demo ** Creating metadata for cookbook: demo
ls -lsa /var/chef/cookbooks/demo/ total 52 4 drwxr-xr-x 10 root root 4096 Фев 18 07:58 . 4 drwxr-xr-x 4 root root 4096 Фев 18 08:05 .. 4 drwxr-xr-x 2 root root 4096 Фев 18 07:58 attributes 4 -rw-r--r-- 1 root root 406 Фев 18 07:58 CHANGELOG.md 4 drwxr-xr-x 2 root root 4096 Фев 18 07:58 definitions 4 drwxr-xr-x 3 root root 4096 Фев 18 07:58 files 4 drwxr-xr-x 2 root root 4096 Фев 18 07:58 libraries 4 -rw-r--r-- 1 root root 272 Фев 18 07:58 metadata.rb 4 drwxr-xr-x 2 root root 4096 Фев 18 07:58 providers 4 -rw-r--r-- 1 root root 1431 Фев 18 07:58 README.md 4 drwxr-xr-x 2 root root 4096 Фев 18 08:04 recipes 4 drwxr-xr-x 2 root root 4096 Фев 18 07:58 resources 4 drwxr-xr-x 3 root root 4096 Фев 18 07:58 templates
cat /var/chef/cookbooks/demo/recipes/default.rb package "ntp" do action :install provider Chef::Provider::Package::Yum end package "mc" do action :install provider Chef::Provider::Package::Yum end service "ntpd" do supports :status => true, :restart => true, :reload => true action [ :enable, :start ] end
# knife cookbook upload demo Uploading demo [0.1.0] Uploaded 1 cookbook.
role
EDITOR=mcedit knife role create demo_role
{ "name": "demo_role", "description": "", "json_class": "Chef::Role", "default_attributes": { }, "override_attributes": { }, "chef_type": "role", "run_list": [ ], "env_run_lists": { } }
Добавить наш кукбук:
{ "name": "demo_role", "description": "", "json_class": "Chef::Role", "default_attributes": { }, "override_attributes": { }, "chef_type": "role", "run_list": [ "recipe[demo]" ], "env_run_lists": { } }
run_list
knife node run_list 172.31.0.5 add role[demo_role] 172.31.0.5: run_list: role[demo_role]
Если есть роль но нет рецептов, это не ошибка
chef-client Starting Chef Client, version 11.4.0 resolving cookbooks for run list: [] Synchronizing Cookbooks: Compiling Cookbooks... Converging 0 resources Chef Client finished, 0 resources updated
После добавления нашего рецепта к роли:
chef-client Starting Chef Client, version 11.4.0 resolving cookbooks for run list: ["demo"] Synchronizing Cookbooks: - demo Compiling Cookbooks... Converging 3 resources Recipe: demo::default * package[ntp] action install - install version 4.2.4p8-2.el6.centos of package ntp * package[mc] action install (up to date) * service[ntpd] action enable - enable service service[ntpd] * service[ntpd] action start - start service service[ntpd] Chef Client finished, 3 resources updated
Проверяем:
# ps -auxfw USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 116136 1628 ? Ss 07:49 0:00 /sbin/init root 8 0.0 0.0 52688 1676 ? Ss 07:49 0:00 login -- root root 209 0.0 0.0 11480 1776 console Ss+ 07:49 0:00 \_ -bash root 165 0.0 0.0 245088 1352 ? Sl 07:49 0:00 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5 root 201 0.0 0.0 4108 588 tty1 Ss+ 07:49 0:00 /sbin/mingetty /dev/tty1 root 203 0.0 0.0 4108 584 tty2 Ss+ 07:49 0:00 /sbin/mingetty /dev/tty2 root 205 0.0 0.0 4108 584 tty3 Ss+ 07:49 0:00 /sbin/mingetty /dev/tty3 root 207 0.0 0.0 4108 588 tty4 Ss+ 07:49 0:00 /sbin/mingetty /dev/tty4 root 265 0.0 0.0 64120 1168 ? Ss 07:55 0:00 /usr/sbin/sshd root 875 0.0 0.0 91712 3908 ? Ss 08:22 0:00 \_ sshd: root@pts/0 root 877 0.0 0.0 108344 1896 pts/0 Ss 08:22 0:00 \_ -bash root 2102 0.0 0.0 110196 1064 pts/0 R+ 11:01 0:00 \_ ps -auxfw ntp 2099 0.0 0.0 30208 1612 ? Ss 09:15 0:00 ntpd -u ntp:ntp -p /var/run/ntpd.pid -g
Особенности - то чего нет в puppet
Поиск
knife search node "role:demo_role"
knife node show 172.31.0.5 -Fj { "name": "172.31.0.5", "chef_environment": "_default", "run_list": [ "role[demo_role]" ], "normal": { "tags": [ ] } }
Переменные (например состояние ноды)
рецепт
приведем рецепт к такому виду:
package "ntp" do action :install provider Chef::Provider::Package::Yum end package "mc" do action :install provider Chef::Provider::Package::Yum end service "ntpd" do supports :status => true, :restart => true, :reload => true action [ :enable, :start ] end #puts node.to_s node.set[:demo][:demo_variable]='text' node.save
Запустим его:
chef-client Starting Chef Client, version 11.4.0 resolving cookbooks for run list: ["demo"] Synchronizing Cookbooks: - demo Compiling Cookbooks... Converging 3 resources Recipe: demo::default * package[ntp] action install (up to date) * package[mc] action install (up to date) * service[ntpd] action enable (up to date) * service[ntpd] action start (up to date) Chef Client finished, 0 resources updated
И теперь мы можем наблюдать переменную в св-вах ноды.
knife node show 172.31.0.5 -Fj { "name": "172.31.0.5", "chef_environment": "_default", "run_list": [ "role[demo_role]" ], "normal": { "tags": [ ], "demo": { "demo_variable": "text" } } }
Для чего это нужно? Например для вот таких конструкций:
puts node.to_s #node.set[:demo][:demo_variable]='text' #node.save puts node[:demo][:demo_variable].to_s if node[:demo][:demo_variable].to_s == "test" Chef::Log.info("OK") else Chef::Log.info("node[:demo][:demo_variable] = "+node[:demo][:demo_variable].to_s) end
"если перемення установлен действие А, если нет Б". Забавно?)
Боевой пример - "кластер"
Задача - установить 3 ноды, на ноде 1 СТРОГО ПОСЛЕ ЗАВЕРШЕНИЯ УСТАНОВКЕ НА ВСЕХ НОДАХ сделать набор post-install шагов.
Определить параметры кластера
Это живой пример, потому определяю параметры так как я это делал на живом кластеер
Рецепт
/var/chef/cookbooks/demo/attributes/default.rb - файл с пре-определнными атрибутами. У нас всего один атрибут - ip address мастер-ноды
set[:demo][:master_node] = "172.31.0.5"
Рецепт приводим к такому виду:
puts "===="+node[:demo][:master_node].to_s+"===" puts "===="+node[:ipaddress].to_s+"===" if node[:demo][:master_node].to_s == node[:ipaddress].to_s puts "Master detected" package "ntp" do action :install provider Chef::Provider::Package::Yum end package "mc" do action :install provider Chef::Provider::Package::Yum end service "ntpd" do supports :status => true, :restart => true, :reload => true action [ :enable, :start ] end puts "=== Master node is installed ===" node.set[:demo][:is_installed]=1 node.save else package "httpd" do action :install provider Chef::Provider::Package::Yum end service "httpd" do supports :status => true, :restart => true, :reload => true action [ :enable, :start ] end puts "=== Slave node is installed ===" node.set[:demo][:is_installed]=1 node.save end
Этот код следует читать примерно так
- Если нода - мастре - то установить один паке (ntp) и выставить переменную "установка сделана"
- если нода - слейв то совсем другое ПО но так же поднять флаг "установлено"
- выводить на экран что-то вроде дебага что бы было ясно по какой из веток двигается процесс
Проверяем:
нода 1 (мастрер)
chef-client Starting Chef Client, version 11.4.0 resolving cookbooks for run list: ["demo"] Synchronizing Cookbooks: - demo Compiling Cookbooks... ====172.31.0.5=== ====172.31.0.5=== Master detected === Master node is installed === Converging 3 resources Recipe: demo::default * package[ntp] action install (up to date) * package[mc] action install (up to date) * service[ntpd] action enable (up to date) * service[ntpd] action start (up to date) Chef Client finished, 0 resources updated
нода 2 (слейв)
Не забываем добавить ноде роль:
knife node run_list 172.31.0.3 add role[demo_role]
chef-client Starting Chef Client, version 11.4.0 resolving cookbooks for run list: ["demo"] Synchronizing Cookbooks: - demo Compiling Cookbooks... ====172.31.0.5=== ====172.31.0.3=== Slave node detected === Slave node is installed === Converging 2 resources Recipe: demo::default * package[httpd] action install - install version 2.2.15-15.el6.centos.1 of package httpd * service[httpd] action enable - enable service service[httpd] * service[httpd] action start - start service service[httpd] Chef Client finished, 3 resources updated
Как видим, поставился совсем другой набор софта!
ps -auxfw USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND <skipped> root 2313 0.0 0.0 173524 3764 ? Ss 12:49 0:00 /usr/sbin/httpd apache 2315 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2316 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2317 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2318 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2319 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2320 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2321 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd apache 2322 0.0 0.0 173524 2240 ? S 12:49 0:00 \_ /usr/sbin/httpd
рабочий кусок кода для нашего примера
# Выставить флаг готовности node.set[:demo][:post_install]=1 node.save puts "==nodes list==" demo_nodes=search(:node, "(role:demo_role OR roles:demo_role)") # demo_nodes.each do |demo_node| puts demo_node[:ipaddress].to_s+"___"+demo_node.to_s # проверить есть ли у ноды атрибуты вообще на случай если на ней ни разу не запускался chef-client if demo_node.attribute?('demo') # если мастер: if demo_node[:demo][:master_node].to_s == demo_node[:ipaddress].to_s puts "is installed ( master) = "+demo_node[:demo][:is_installed].to_s else puts "is installed ( slave) = "+demo_node[:demo][:is_installed].to_s end puts "Check [:is_installed] variable:"+demo_node[:demo][:is_installed].to_s if demo_node[:demo][:is_installed] != 1 puts "node "+ demo_node[:ipaddress].to_s+" is not ready" node.set[:demo][:post_install]=0 node.save end else # эта секция отработает если есть хотя бы одна нода которая на сервере указана как demo на самом деле не запускала клиента puts "at least one node is not configured! "+demo_node[:ipaddress] node.set[:demo][:post_install]=0 node.save end end if node[:demo][:post_install] == 1 if node[:demo][:master_node].to_s == node[:ipaddress].to_s puts "Do post-install for master" else puts "Do post-install for slave" end else puts "not ready for post-install" end
Логика работы такая
- Проверить есть ли demo_node.attribute?('demo'). его не будет если ноде прописана роль демо, но реально chef-client еще ни разу не запускался.
- если атрибута нет - вывод однозначен, кластер не готов к Post-Install
- если атрибут есть - дополнительные проверки
- для каждой ноды выполнить проверку demo_node[:demo][:is_installed] != 1. Если хотя бы одна нода не имеет атрибута is_installed==1 то установить атрибут post_install]=0
В результате исполнения этого кода мы можем точно знать - на какой стадии установки у нас находится кластер и предпринимать действия на основе этого знанеия.