pgrep, pkillでプロセスをkillする
特定のプロセスをkillするときは、いつも以下のようなコマンドを使っていました。
# ps -ef | grep java | grep -v grep root 12927 1 2 15:51 pts/0 00:00:05 java -Xmx64m -jar start.jar # kill 12927
もっといい方法はないのかと思っていたら、pgrep
やpkill
という方法があるのを知りました。
pgrep
は、プロセス名で絞り込んだPIDを表示させることができます。
# pgrep java 12927
-l
オプションの場合、コマンドが表示されます。
# pgrep -l java 12927 java
ただ、複数のプロセスがある場合は、区別がつきません。
この場合は、-f
オプションにより詳細が表示されます。
# pgrep -lf java 12927 java -Xmx64m -jar start.jar
同様に、プロセスをkill
する場合もpkill
により、いちいちPID
を調べる必要がなくなります。
オプションも同様で、-f
オプションによりプロセスの引数も含めて指定することができます。
# pkill -f "java.*start\.jar"
これは便利。
ZABBIXのホスト自動登録機能でJMXの設定を行う
ZABBIXのホストの自動登録機能の問題点
Zabbixでのホストの自動登録機能は、Zabbixエージェントを導入したノードに、自動的にホストグループの組み込みやテンプレートのリンクを行うできる便利な機能です。これにより、はじめてZabbixエージェントを導入したノードに対しても、監視の初期設定を自動的に行うことができます。
が、通常ではJMXインターフェースは自動で認識されないという欠点があります。そのため、JMX関係の設定はホストの認識後に手動で設定する必要があります。また、それによってJMXを利用するテンプレートをリンクすることもできません。
ZABBIX APIを利用したカスタムスクリプト
そこで、ホストの自動登録機能を生かしつつJMX関係の設定(ホストへのJMXインターフェースの追加、JMX関係テンプレートのリンク)を行うために、ZABBIX APIを利用したカスタムスクリプトを自動登録機能に組み込みました。これにより、ホストはJMXインターフェースの追加やJMX関連テンプレートのリンクも自動で行うことができるようになっています。
zabbix-jmxsetting
なお、テンプレートのリンク用に、以下を利用しています。
Zabbix 2.0 Tomcat 7 JMX Template
設定
スクリプトの配置
上記から取得したzabbix-jmxsetting.sh
をZABBIXサーバ上の好きな場所に置きます。
今回は/usr/lib/zabbix/settingscripts
配下に置きます。chmod
で実行権を与えてください。
ホストの自動登録
まずは、通常通り、ZABBIXのホストの自動登録機能を利用します。
カスタムスクリプトの設定
[アクションの実行内容]から、リモートコマンドを追加してください。
- 実行内容のタイプ : リモートコマンド
- ターゲットリスト : 現在のホスト
- タイプ : カスタムスクリプト
- 次で実行 : Zabbixサーバー
- コマンド :
/usr/lib/settingscripts/zabbix-jmxsetting.sh {HOST.HOST} {HOST.IP}
スクリプトの場所は、置いた場所に応じて適宜読み替えてください。
実行結果
新しいホストが登録されてしばらく待つと、上記の通りTemplate JMX Tomcat 7
が追加され、JMXのアイコンも点灯していることが分かります。最初は登録されてなくて焦りますが、しばらく待って画面をリロードすると、遅れて点灯するはずです。
ホストの詳細を見ても、JMXインターフェースが設定されていることが分かります。
注意事項
スクリプト内で、Template JMX Tomcat 7
に決め打ちにしているので、あんまり汎用的ではないです。また、ZABBIX APIを利用する関係で、スクリプト内のユーザ名/パスワードをそれぞれの環境用に書き換える必要があります。
あと、ZabbixエージェントのインターフェースのIPとJMXインターフェースのIPが同じである場合でしか適用できないので、もしインターフェースが異なる場合は対応できません。この辺りは反省…。
あと、JSON形式の結果をパースするためにjq
を利用しています。そのため、jq
がZABBIXサーバにインストールされている必要があります。
jq
内部的な話
スクリプトの中身は、単にZABBIX APIを利用してJMXインターフェースの追加やテンプレートのリンクを行っているだけです。
結果はJSON形式なので、これをjq
コマンドでパースして必要な値だけ取得し、加工しています。
ZABBIX APIを始めて利用して、最初はかなり戸惑いましたが、慣れるとかなり便利でした。APIを使っていろいろできそうです。
あとjq
も物凄く便利です。JSON形式で返すZABBIX APIとはかなり相性がいいですね。
curlコマンドでプログレスメータを表示させない
curl
コマンドをパイプでリダイレクトすると、大体以下のような標準出力になります。
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 68 0 68 0 163 1893 4538 --:--:-- --:--:-- --:--:-- 0
普段は問題ないのですが、表示を消したい場合はどうするんだろうと思ったら、-s
オプションで行けました。
curl -s ${URL} | ${COMMAND}
というか上記を「プログレスメータ」ということらすら知りませんでした…。
chefでserviceを正しく管理する(kibana)
前々回、kibanaのサービスとしてkibana-daemon.rb
(を中で使っている/etc/init.d/kibana
)を使っていました。
chefで、最初にkibanaをインストールしてサービスを起動しようとしたときに、 サービスがなぜかスキップされて起動しません。recipeではちゃんと指定しています。
site-cookbooks/kibana/recipes/default.rb :
cookbook_file "/etc/init.d/kibana" do source "kibana" action :create_if_missing mode 00755 end bash "add_kibana_service" do code <<-EOL chkconfig --add kibana EOL end service "kibana" do action [:start, :enable] end
出力ログ :
Recipe: kibana::default 〜中略〜〜 * service[kibana] action start (up to date) * service[kibana] action enable (up to date)
実際に確認してみても、確かに起動していません。
$ service kibana status
kibana: no instances running
結論から言うと、戻り値が管理されていませんでした。
chefでserviceリソースを利用するときは、service <service_name> statusの戻り値を適切に管理する必要があるようです。
サービス停止状態のときは"3"を返すことで、chefは適切にサービスを管理してくれます。
というか、kibana-daemon.rb
に任せる必要すらない気がするので、statusコマンドに任せることにしました。
/etc/init.d/kibana (元々は /usr/share/kibana/sample/kibana) 変更前:
KIBANA_PATH="/usr/share/kibana" # 略 status) ruby $KIBANA_PATH/kibana-daemon.rb $1 ;;
変更後 :
KIBANA_PATH="/usr/share/kibana" . /etc/init.d/functions # 略 status) # ruby $KIBANA_PATH/kibana-daemon.rb $1 status -p ${KIBANA_PATH}/tmp/kibana.pid kibana ;;
これで動作するようになりました。
$ knife solo cook <server_name>
出力ログ :
Recipe: kibana::default 〜中略〜〜 * service[kibana] action start - start service service[kibana] * service[kibana] action enable (up to date)
Rubyを知らずにchefでrecipeを書くときのTips
Rubyをほとんど使ったことがなくて、そのままchefのrecipeを書こうとすると、いろいろと細かいところがどう書くのか分からなくなります。 ということで、個人的に困ったところをメモします。
複数のリソースを使う
%w{... ...}
で必要な分だけ記入して、eachでぐるぐる回します。
%w{vim-enhanced yum-utils}.each do |pkgs| package pkgs do action :install end end
環境変数を設定する
ruby_block
の中でENV["ENV_NAME"]
を使います。
ruby_block "set-env-java-home" do block do ENV["JAVA_HOME"] = "/usr/java/default" end end
恒久的に設定する場合は、/etc/profile.d/
配下にスクリプトを置きます。
file "/etc/profile.d/jdk.sh" do content <<-EOS export JAVA_HOME="/usr/java/default" EOS mode 0755 end
ファイルが存在するかどうかを判定する
File.exist?("<PATH>")
を使います。
not_if
と併用すると、ファイルが存在しない場合に実行されます。
bash "fluentd_repo" do code <<-EOL curl -L http://toolbelt.treasure-data.com/sh/install-redhat.sh | sh EOL not_if {File.exist?("/usr/sbin/td-agent")} end
特定の文字列が含むかどうかを判定する
環境変数が設定されているかどうかを判定したくて調べました。
<STRING>.include?(<CHECK_STRING>)
で利用します。
ruby_block "set-env-rbenv" do block do ENV["RBENV_ROOT"] = "/usr/local/rbenv" ENV["PATH"] = ENV["RBENV_ROOT"] + "/bin:" + ENV["PATH"] end not_if {ENV["PATH"].include?("/usr/local/rbenv")} end
上記では、環境変数${PATH}
に"/usr/local/rbenv"
が含まれていない場合に環境変数の設定が行われます。
複数の(可変の)行を挿入する
/etc/hosts
をtemplateとしてhosts.erb
で管理するとき、attributeでホストの一覧を直接記述してしまうと、ホストが増えた時に、いちいちtemplateごと変えることになり面倒…なので、hashで設定することにします。
attributes/default.rb :
default['Network']['config']['HostIPList'] = { "host1" => "192.168.5.1", "host2" => "192.168.5.2", "host3" => "192.168.5.3", "host4" => "192.168.5.4" }
templates/default/hosts.erb :
<% node['Network']['config']['HostIPList'].each do | hostname , ip | %> <%= ip %> <%= hostname %> <% end %>
chefで上記templateを配布した後は、最終的に以下のようになります。
/etc/hosts :
192.168.5.1 host1 192.168.5.2 host2 192.168.5.3 host3 192.168.5.4 host4
もしホストを追加したくなったら、attributeに行を追加すればよさそうです。
Kibanaでkibana-daemon.rbを実行する時にはまった話
もともとはkibanaインストールディレクトリ内に、sample/kibana
が存在していて、これを/etc/init.d/
向けに使おうとしたときにはまった話。
試しに実行してみる。
$ cd sample $ ./kibana start $
ところが、何も起こらない。
$ ps -ef | grep kibana $
特に何も表示されない。内部ではkibana-daemon.rb
を実行しているみたい。
仕方ないので色々調べてみましたが、そもそもrubyを知らないので、解析するのにえらく時間がかかりました…。
ruby kibana-daemon.rb start fails siliently
これによると、-t
オプションで詳細出力することができるみたいです。
$ cd ../ $ ruby kibana-daemon.rb -t
以下出力結果:
/usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/pidfile.rb:94:in `initialize': No such file or directory - /usr/local/Kibana/tmp/kibana.pid (Errno::ENOENT) from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/pidfile.rb:94:in `open' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/pidfile.rb:94:in `pid=' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/application.rb:211:in `block in start_proc' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/application.rb:264:in `call' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/application.rb:264:in `start_proc' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/application.rb:296:in `start' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/controller.rb:70:in `run' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons.rb:197:in `block in run_proc' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/cmdline.rb:109:in `call' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/cmdline.rb:109:in `catch_exceptions' from /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons.rb:196:in `run_proc' from kibana-daemon.rb:25:in `<main>'
/usr/local/Kibana/tmp/kibana.pid
ファイルを作ることができないらしい。というかtmpディレクトリがない…。ということで作成。
$ mkdir sample/tmp
これで起動できるようになりました。
$ cd sample $ ./kibana start pid-file for killed process 4417 found (/usr/share/kibana/tmp/kibana.pid), deleting.
あとは、このファイルを/etc/init.d/
配下に置いておけばいいかな。
以下余談:
最初はrubyのデバッグ出力をしてみていましたが、よく分かりませんでした。
$ ruby -d kibana-daemon.rb
Exception `LoadError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems.rb:1082 - cannot load such file -- rubygems/defaults/operating_system Exception `LoadError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems.rb:1091 - cannot load such file -- rubygems/defaults/ruby Exception `LoadError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45 - cannot load such file -- daemons /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:59: warning: assigned but unused variable - sess_id /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:102: warning: assigned but unused variable - pid /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/application.rb:337: warning: mismatched indentations at 'end' with 'def' at 326 /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/application_group.rb:80: warning: assigned but unused variable - pid Exception `ArgumentError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:137 - The given fd is not accessible because RubyVM reserves it Exception `ArgumentError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:137 - The given fd is not accessible because RubyVM reserves it Exception `ArgumentError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:137 - The given fd is not accessible because RubyVM reserves it Exception `ArgumentError' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:137 - The given fd is not accessible because RubyVM reserves it Exception `Errno::EBADF' at /usr/local/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/daemons-1.1.9/lib/daemons/daemonize.rb:137 - Bad file descriptor
「rubygems/defaults/operating_system」がないとかでエラーになるのは、特に問題ないらしいです。
Ruby 1.9.2とRubyGems 1.3.7とGem.pathの消失 - \ay diary