orenoblog

エンジニアになりたいExcel方眼紙erの物語

Infrastructure as 脳筋のためのchef recipe tips. HAProxyの例

chef-zeroのC/S wrapper knife-zero使ってますか?

とても便利です。重宝しています。

higanworks/knife-zero · GitHub

個人的にchefの真髄であるsearchが利用できるため、chef-soloと違って関連nodeの情報をattributeに記述すること無くrecipeを記述でき、

管理の幅を広げてくれるツールなので是非使いましょうと思っている次第です(がまだ横展開しきれず)

今回はHAproxyを用いてGalera Cluster MariaDBへの接続を行うための定義を簡単に書くためのtipsを残したいと思います。

EnvironmentとRoleを使い、HAProxyのロードバランス対象となるノードをnode情報から自動判別してHAProxyの設定を生成します。

chef repositoryで利用するEnvironmentとRole

  • Environment
chef_environment 意味
production 本番環境
  • Role
role 意味
galera_master Galera Cluster初期ノード
galera_member Galera Clusterメンバーノード

DBサーバとなるノードにはrole[galera_master]またはrole{galera_member]を割り当ててknife zeroを実行しておきます。(実行しておかないとnode.jsonに対象ノードの情報が集約されない)

recipe

  • haproxy/recipes/default.rb

Galera Clusterを構成するノードの情報をsearchで取得してtemplate variablesに渡します

if node.chef_environment.include?("production")
  cookbook_file "/root/haproxy-1.5.9-2.amzn1.x86_64.rpm" do
    source "haproxy-1.5.9-2.amzn1.x86_64.rpm"
    owner "root"
    group "root"
    mode 0644
  end
  
  package "haproxy" do
    action :install
    provider Chef::Provider::Package::Rpm
    source "/root/haproxy-1.5.9-2.amzn1.x86_64.rpm"
  end
  
  template "/etc/haproxy/haproxy.cfg" do
    source "haproxy.cfg.erb"
    owner "root"
    group "root"
    mode 0644
    notifies :restart, "service[haproxy]"
    variables(
      :galerahosts => search(:node,"roles:galera* AND chef_environment:#{node.chef_environment}")
    )
  end

  service "haproxy" do
    action :nothing
  end
end 
  • haproxy/template/haproxy.cfg.erb(一部抜粋)

template variablesから渡された情報をeachでぶん回します。

listen  haproxy-galera
        bind *:33306
        mode tcp
        timeout client  28800s
        timeout server  28800s
        balance roundrobin
        option httpchk
        option allbackups
        <% @galerahosts.each do |host|  %>
        server <%= host.ipaddress %> <%= host.ipaddress %>:3306 check
        <% end %> 

apply後

このようにHAProxyを導入するサーバにrecipeを適用します(chef-repo毎にbundler使ってるのでbundle execかいてます)

bundle exec knife zero chef_client search "role:app AND chef_environment production" -x ec2-user --sudo --attribute name

実行後は対象ノードに以下のようなhaproxy.cfgが作成されます。

..省略..
listen  haproxy-galera
        bind *:33306
        mode tcp
        timeout client  28800s
        timeout server  28800s
        balance roundrobin
        option httpchk
        option allbackups
        server 192.168.1.100 192.168.1.100:3306 check
        server 192.168.1.101 192.168.1.101:3306 check
        server 192.168.1.102 192.168.1.102:3306 check

attributeを使用せずroleとchef_environmentの検索でロードバランス対象ノードのIPアドレスを設定することが出来ました。

search最高。

ちなみに自分はknife zeroのコマンドラインを実行するのが面倒なので 簡単なRakefileを作成して、search条件だけ渡してknife zeroを実行しています。

適用するroleやenvironment毎にtaskを作成したらもっと簡単にかつsearchのミス無く適用することができると思います。

require 'rake'

desc "run, bundle exec knife <type> list"
task :list, [:type] do |t,args|
  command = %(bundle exec knife #{args[:type]} #{t} )
  puts command
  Bundler.clean_system command
end

desc "run, bundle exec knife search <hint>"
task :search, [:hint] do |t, args|
  command = %(bundle exec knife #{t} "#{args[:hint]}")
  puts command
  Bundler.clean_system command
end

knife_args = "-x ec2-user --sudo --attribute name"

desc "run, bundle exec knife zero chef_client --why-run"
task "dry-run", [:hint] do |t,args|
  command = %(bundle exec berks vendor cookbooks;bundle exec knife zero chef_client "#{args[:hint]}" #{knife_args} --why-run)
  puts command
  Bundler.clean_system command
end

desc "run, bundle exec knife zero chef_client."
task :apply, [:hint] do |t,args|
  command = %(bundle exec berks vendor cookbooks;bundle exec knife zero chef_client "#{args[:hint]}" #{knife_args})
  puts command
  Bundler.clean_system command
end
  • Rake実行例

why-run

bundle exec rake "dry-run[(roles:galera* AND chef_environment:production)]"

apply

bundle exec rake "apply[(roles:galera* AND chef_environment:production)]"

Rake saikou.