Minimizar reinicializações de serviço a partir de notificações do chef?

StackOverflow https://stackoverflow.com//questions/21066591

  •  26-12-2019
  •  | 
  •  

Pergunta

Atualmente minha receita com atributos importantes está estruturada assim:

service 'myservice' do
  action :nothing
  supports :status => true, :start => true, :stop => true, :restart => true
end

package 'packagename' do
  ...
end

template 'configfile1'
  notifies :restart, 'service[myservice]'
end
...
template 'configfileN'
  notifies :restart, 'service[myservice]'
end

execute "a command from package which generates and enables the init script" do
  notifies :start, 'service[myservice]', :immediately
end

execute "a command that should run once every time, that requires service to be running"

Ao fazer isso, garantimos que o início inicial do serviço tenha os arquivos de configuração, durante cada execução o serviço esteja sendo executado para o segundo bloco de execução e, se algum arquivo de configuração for alterado, reiniciamos o serviço para captar as alterações.

No entanto, se uma execução do chef ocorrer onde o estado inicial do serviço for interrompido (como na primeira execução ou se algo de ruim acontecer) e os arquivos de configuração tiverem sido alterados (principalmente na primeira execução, mas possível para outras execuções), o primeiro bloco de execução fará com que o serviço seja iniciado com os arquivos de configuração corretos já instalados e, ao final da execução, o serviço será reiniciado desnecessariamente.(Suponha, é claro, que os recursos após a inicialização não causem a reinicialização do serviço)

Alterar a ação alvo das notificações parece não funcionar (já que as notificações imediatas ainda acontecerão imediatamente, as notificações atrasadas ainda acontecerão) e, além disso, não seria correto.

Além disso, não podemos inscrever a 2ª execução no início do serviço, pois se já estiver em execução, acabaríamos não executando-o.

É muito exigente, mas existe um padrão melhor que poderia ser seguido para minimizar as reinicializações de um serviço para a execução inicial?Ou um mecanismo para cancelar notificações atrasadas quando uma ação específica é realizada?

Foi útil?

Solução

Usei um arquivo de sinalização para conseguir isso.

Como abaixo, "apt-get update" não é executado uma vez.

cookbook_file '/etc/apt/sources.list.d/maven.list' do
  source "repo_files/ubuntu_maven.list"
  cookbook "fluig-files"
  mode 0644
  notifies :run, "execute[should_update_repo]", :immediately
end

cookbook_file '/etc/apt/sources.list.d/couchbase.list' do
  source "repo_files/ubuntu_couchbase.list"
  cookbook "fluig-files"
  mode 0644
  notifies :run, "execute[should_update_repo]", :immediately
end

execute "apt-key couchbase" do
  command "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A3FAA648D9223EDA"
  action :run
  not_if "apt-key list | grep couchbase"
  notifies :run, "execute[should_update_repo]", :immediately
end

execute "should_update_repo" do
  command "touch /tmp/should_update_repo"
  action :nothing
end

# Update system
execute "apt-get update" do
  command "rm -rf /tmp/should_update_repo && apt-get update"
  action :run
  only_if "test -f /tmp/should_update_repo"
end

Outras dicas

O Chef foi projetado para expressar a política de configuração (estado do sistema), o que é um pouco diferente de expressar uma sequência de tarefas a serem executadas.

Felizmente, como a DSL é baseada em Ruby, os recursos podem ser redefinidos em tempo de execução.

template "configfile1" do
  notifies :create, "ruby_block[restart_service1]", :immediately
end

template "configfile2" do
  notifies :create, "ruby_block[restart_service1]", :immediately
end

service "service1" do
  action [:enable, :start]
end

ruby_block "restart_service1" do
  block do

    r = resources(:service => "service1")
    a = Array.new(r.action)

    a << :restart unless a.include?(:restart)
    a.delete(:start) if a.include?(:restart)

    r.action(a)

  end
  action :nothing
end

Isso reescreverá o recurso de serviço para ter "action [:enable, :restart]" em vez de "action [:enable, :start]", se algum dos recursos do modelo mudar de estado nesta execução.Portanto, a ordem permanece a mesma e você recebe apenas uma chamada por meio do recurso de serviço, em vez de potencialmente três.

Não tenho certeza se isso resolverá seus problemas ao reiniciar o serviço muitas vezes, mas essa estrutura me parece mais lógica.

#Prepare everything to start the service
package 'packagename' do
  ...
end

template 'configfile1'
  notifies :restart, 'service[myservice]'
end
...
template 'configfileN'
  notifies :restart, 'service[myservice]'
end

execute "a command from package which generates and enables the init script" do
  notifies :restart, 'service[myservice]'
end

#Start the service
service 'myservice' do
  action :start
  supports :status => true, :start => true, :stop => true, :restart => true
end

#At this point service is surely running
execute "a command that should run once every time, that requires service to be running"

Cada recurso que altera o(s) arquivo(s) de configuração deve notificar o serviço para reiniciar.

Acho que o Chef é inteligente o suficiente para não reiniciar o serviço que acabou de iniciar.(Não prestei atenção nisso antes, mas me parece que teria feito, se houvesse reinicializações desnecessárias)

O Chef executará apenas uma ação por recurso, independentemente do número de vezes que for notificado.É, no entanto, específico para cada ação.Então, se você enviar um action :restart e também um action :start notificação, ambos serão executados na ordem em que o Chef os encontrou.Então, o que você está vendo com seu exemplo de código é o inicial :start notificação do bloco de execução, seguida pelo modelo :restart notificações.

Você deve ser capaz de evitar isso reestruturando um pouco sua receita e usando subscribes se estou seguindo corretamente.

package 'packagename' do
  ...
end

execute "a command from package which generates and enables the init script" do
  not_if File.exists?('/etc/init.d/myservice_script')
end

template 'configfile1'
  notifies :restart, 'service[myservice]'
end
...
template 'configfileN'
  notifies :restart, 'service[myservice]'
end

service 'myservice' do
  supports :status => true, :start => true, :stop => true, :restart => true
  subscribes :run, 'execute[a command from package which generates and enables the init script]', :immediately
  action :start
end

execute "a command that should run once every time, that requires service to be running"

Primeiro, movemos o service recurso na parte inferior da receita para que ele só seja chamado depois que todos os outros recursos forem avaliados.Então mudamos o execute recurso para assinar o :start ação do service[myservice] recurso para que ele só execute este comando quando o :start ação é chamada.Também adicionamos um pouco de idempotência para garantir que ele não apenas recrie o script de inicialização a cada execução.

Finalmente, adicionamos todos os modelos com as notificações normais para service[myservice].

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top