Chef infra 从厨师长通知中最小化服务重启?

Chef infra 从厨师长通知中最小化服务重启?,chef-infra,Chef Infra,目前,我的配方具有重要的属性,其结构如下: service 'myservice' do action :nothing supports :status => true, :start => true, :stop => true, :restart => true end package 'packagename' do ... end template 'configfile1' notifies :restart, 'service[myser

目前,我的配方具有重要的属性,其结构如下:

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"
通过这样做,我们确保服务的初始启动具有配置文件,在每次运行期间,服务都在为第二个执行块运行,如果任何配置文件发生更改,我们将重新启动服务以获取更改

但是,如果chef运行发生在服务的初始状态停止的地方(例如,在第一次运行时,或者发生了错误),并且配置文件已更改(特别是在第一次运行时,但可能在其他运行时),则第一个执行块将导致服务在正确的配置文件已就位的情况下启动,然后在运行结束时,服务将不必要地重新启动。(当然,假设初始启动后的资源不会导致服务重新启动)

更改通知的目标操作似乎不起作用(因为即时通知仍然会立即发生,然后延迟通知仍然会发生),而且也不正确

此外,我们无法订阅服务启动的第二个execute,因为如果它已经运行,我们将无法执行它


这是非常挑剔的,但是有没有更好的模式可以用来最小化服务在初始运行时的重启?或者在执行特定操作时取消延迟通知的机制

我不确定,if是否能解决您重启服务太多次的问题,但这种结构对我来说似乎更符合逻辑

#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"
更改配置文件的每个资源都应通知服务重新启动


我猜Chef足够聪明,不会重新启动刚启动的服务。(我以前没有注意到这一点,但在我看来,如果有不必要的重新启动,我会这样做)

厨师只会对每个资源执行一个操作,而不管通知的次数如何。然而,它是特定于每个动作的。因此,如果您向它发送一个
action:restart
和一个
action:start
通知,那么两者都将按照Chef遇到它们的顺序执行。因此,您在代码示例中看到的是来自execute块的初始
:start
通知,然后是模板
:restart
通知

你应该能够避免这一点,通过重新构造你的食谱和使用,如果我遵循正确的

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"
首先,我们将
服务
资源移动到配方的底部,以便仅在对所有其他资源进行评估后调用它。然后,我们将
execute
资源更改为订阅
服务[myservice]
资源的
:start
操作,以便它仅在调用
:start
操作时执行此命令。我们还在其中添加了一点幂等性,以确保它不会每次运行时都重新创建init脚本


最后,我们为
服务[myservice]

添加了所有带有正常通知的模板,Chef被设计用来表示配置策略(系统状态),这与表示要执行的任务序列略有不同

幸运的是,由于DSL是基于ruby的,所以可以在运行时重新定义资源

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
模板“configfile1”do
通知:创建“ruby\u块[重新启动\u服务1],:立即
结束
模板“configfile2”执行
通知:创建“ruby\u块[重新启动\u服务1],:立即
结束
服务“服务1”do
操作[:启用,:启动]
结束
ruby\u块“重新启动\u服务1”do
布洛克道
r=资源(:服务=>“服务1”)
a=数组。新建(r.action)

a我使用了一个标志文件来实现这一点

如下所示,“apt get update”不会执行一次

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

可悲的是,大厨显然没有那么聪明,它仍然在做双重启动。就逻辑结构而言,我思考它的方式是,在针对同一资源声明通知之前,先声明(服务)资源。这显然更像是一种风格偏好,而不是一种正确性偏好:)那么您通过订阅“执行[generate init script]”到“服务[myservice]”能实现什么呢?如果没有init-script,您将无法启动服务。哎哟。我的意思是将订阅附加到“service[myservice]”资源。我会编辑我的帖子。由于如果init脚本不存在,“service”资源将无法执行,因此我们将其订阅到execute块,以便在第一个“execute”块创建后立即触发。如果init脚本已经存在,not_if可以防止再次触发命令。这是一个有趣的想法。我还没有机会尝试一下。。。再过几天我就应该有时间了。我有点仓促行事,根据我们解决的其他不完全相同的问题来探索一个想法。事实上,我今天尝试了一下,发现它并不完全像我想的那样工作。但这一原则基本上是正确的。我编辑了上面的示例ruby_块来显示。