hidemium's blog

日々学んだことをアウトプットする。

ChefからDockerコンテナにSensu Serverをインストールする

前回、ChefからDockerコンテナ内の起動プロセスを追加することが確認できました。そこで、今回はChefを使ってDockerコンテナに監視ツールのSensu Serverをインストールしてみました。

構成

Ubuntu 12.04: サーバ構築対象
Ubuntu 12.04はDocker 1.0.0上で動作しています。

Dockerコンテナ

Dockerfileの構成は以下の通りです。

sshd
├──Dockerfile
├──sources.list      ... ミラーサイト一覧
├──id_rsa.pub        ... Chef workstationの公開鍵
└──supervisord.conf  ... supervisorの定義ファイル

Dockerfileを以下のように作成します。
supervisorの定義ファイルは、/etc/supervisor/conf.d/配下にも置くことができるので、「RUN mkdir -p /etc/supervisor/conf.d/」でディレクトリを作成しています。

$ vi Dockerfile
FROM ubuntu:12.04

MAINTAINER hidemium

# Ubuntu update
ADD sources.list /etc/apt/sources.list
RUN apt-get -y update

# Hack for initctl not being available in Ubuntu
RUN dpkg-divert --local --rename --add /sbin/initctl
RUN ln -sf /bin/true /sbin/initctl

# ssh install
RUN apt-get -y install openssh-server
RUN apt-get -y install python-setuptools
RUN apt-get clean
RUN easy_install supervisor

RUN mkdir /var/run/sshd
RUN echo 'root:root' | chpasswd

# sshd config
ADD id_rsa.pub /root/id_rsa.pub
RUN mkdir /root/.ssh/
RUN mv /root/id_rsa.pub /root/.ssh/authorized_keys
RUN chmod 700 /root/.ssh
RUN chmod 600 /root/.ssh/authorized_keys
RUN sed -i -e '/^UsePAM\s\+yes/d' /etc/ssh/sshd_config

# supervisor config
RUN mkdir -p /var/log/supervisor
RUN mkdir -p /etc/supervisor/conf.d/
ADD supervisord.conf /etc/supervisord.conf

# Expose ports.
EXPOSE 22

# Define default command.
CMD ["supervisord", "-n"]

supervisorの定義ファイルは、デフォルトの定義にsshdの起動を追加したものにしています。

$ vi supervisord.conf
[unix_http_server]
file=/tmp/supervisor.sock   ; (the path to the socket file)

[supervisord]
logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB        ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10           ; (num of main logfile rotation backups;default 10)
loglevel=info                ; (log level;default info; others: debug,warn,trace)
pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false               ; (start in foreground if true;default false)
minfds=1024                  ; (min. avail startup file descriptors;default 1024)
minprocs=200                 ; (min. avail process descriptors;default 200)

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket

[include]
files = /etc/supervisor/conf.d/*.conf

[program:sshd]
command=/usr/sbin/sshd -D
autostart=true
autorestart=true

docker buildコマンドにより、イメージを作成します。
実行後、ubuntu-supervisorというイメージが作成されていることを確認します。

$ sudo docker build -t ubuntu-supervisor:12.04 .
$ sudo docker images

Sensu ServerのChefレシピ

それでは、Sensu Serverをインストーするレシピについて見ていきます。

cookbookの構成

cookbookの構成は以下の通りです。

site-cookbook
└──sensu-server
      └──recipes
      │    └──default.rb
      └──templates
            └──default
                  ├──checks_proc.json.erb ... 監視動作定義ファイル
                  ├──client.json.erb ... Sensu Clientの監視定義ファイル
                  ├──config.json.erb ... Sensu Serverの定義ファイル
                  ├──sensu.list.erb  ... リポジトリの定義ファイル
                  └──sensu-server.conf.erb ... supervisorの定義ファイル

recipesファイル

recipesファイルは以下の通りです。

$ vi site-cookbooks/sensu-server/recipes/default.rb
%w{wget python-software-properties}.each do | pkg |
    package pkg do
        action :install
    end
end

template "/etc/apt/sources.list.d/sensu.list" do
    owner "root"
    mode 0644
    source "sensu.list.erb"
end

bash "add sensu apt-key" do
    code "wget -q http://repos.sensuapp.org/apt/pubkey.gpg -O- | apt-key add -"
    action :run
end

bash "add rabbitmq apt-key" do
    code "wget -q http://www.rabbitmq.com/rabbitmq-signing-key-public.asc -O- | apt-key add -"
    action :run
end

bash "add redis repos" do
    code "add-apt-repository -y ppa:rwky/redis"
    action :run
end

bash "apt-get update" do
    code "apt-get update"
    action :run
end

%w{sensu rabbitmq-server redis-server git-core bc rsyslog}.each do | pkg |
    package pkg do
        action :install
    end
end

git "/tmp/sensu_plugins" do
    repository "git://github.com/sensu/sensu-community-plugins.git"
    reference "master"
    action :sync
end

bash "copy sensu plugins" do
    code "cp -Rf /tmp/sensu_plugins/plugins /etc/sensu/"
    action :run
end

bash "chmod sensu plugins" do
    code "find /etc/sensu/plugins/ -name *.rb -exec chmod +x {} \\;"
    action :run
end

template "sensu-server.conf" do
    path "/etc/supervisor/conf.d/sensu-server.conf"
    owner "root"
    group "root"
    mode "0644"
    source "sensu-server.conf.erb"
end

template "config.json" do
    path "/etc/sensu/config.json"
    owner "root"
    group "root"
    mode "0644"
    source "config.json.erb"
end

template "client.json" do
    path "/etc/sensu/conf.d/client.json"
    owner "root"
    group "root"
    mode "0644"
    source "client.json.erb"
end

template "checks.json" do
    path "/etc/sensu/conf.d/checks.json"
    owner "root"
    group "root"
    mode "0644"
    source "checks.json.erb"
end

bash "ln ruby path" do
    code   "ln -s /opt/sensu/embedded/bin/ruby /usr/bin/ruby"
    action :run
end

bash "supervisorctl reload" do
    code   "supervisorctl reload; sleep 10"
    action :run
end

bash "rabbitmqctl add_user" do
    code "rabbitmqctl add_user admin admin"
    action :run
end

bash "rabbitmqctl set_user_tags" do
    code "rabbitmqctl set_user_tags admin administrator"
    action :run
end

bash "rabbitmqctl set_permissions" do
    code "rabbitmqctl set_permissions -p / admin '.*' '.*' '.*'"
    action :run
end

bash "rabbitmq_management" do
    code "rabbitmq-plugins enable rabbitmq_management"
    action :run
end

bash "rabbitmq restart" do
    code   "rabbitmqctl stop"
    action :run
end
  • Sensu Serverをインストールするために、Sensuのリポジトリを指定しています。
  • 普通にapt-get install rabbitmq-serverとした場合、RabbitMQ 2.7.1がインストールされるため、RabbitMQのリポジトリを指定し、RabbitMQ 3系がインストールされるようにしています。
  • GitHubからSensuのCommunity Pluginを取得しています。
  • Sensu ServerやRabbitMQを起動するため、supervisorの定義ファイルであるsensu-server.confを配置しています。
  • RabbitMQ 3系では、RabbitMQの管理画面にguestユーザでログインするためには、localhost経由しかできない仕様となったため、adminユーザを追加しています。
  • RabbitMQの管理画面を有効にするため、rabbitmq-plugins enable rabbitmq_managementコマンドを実行後、RabbitMQを再起動が必要となります。supervisorでRabbitMQプロセスのautorestartをオンにしているため、rabbitmqctl stopコマンドだけ実行しています。

templateファイル

templateファイルは以下の通りです。

checks.json

checks.jsonは監視の動作を定義しているファイルであり、Sensu Server側に配置します。
command内のcheck-procs.rbはSensuのCommunity Pluginになります。

$ vi site-cookbooks/sensu-server/templates/default/checks_proc.json.erb
{
  "checks": {
    "sensu-rabbitmq-beam": {
      "handlers": [
        "default"
      ],
      "command": "/etc/sensu/plugins/processes/check-procs.rb -p beam -C 1 -w 4 -c 5",
      "interval": 60,
      "occurrences": 2,
      "refresh": 300,
      "subscribers": [ "sensu" ]
    },
    "sensu-rabbitmq-epmd": {
      "handlers": [
        "default"
      ],
      "command": "/etc/sensu/plugins/processes/check-procs.rb -p epmd -C 1 -w 1 -c 1",
      "interval": 60,
      "occurrences": 2,
      "refresh": 300,
      "subscribers": [ "sensu" ]
    },
    "sensu-redis": {
      "handlers": [
        "default"
      ],
      "command": "/etc/sensu/plugins/processes/check-procs.rb -p redis-server -C 1 -w 4 -c 5",
      "interval": 60,
      "occurrences": 2,
      "refresh": 300,
      "subscribers": [ "sensu" ]
    },
    "sensu-api": {
      "handlers": [
        "default"
      ],
      "command": "/etc/sensu/plugins/processes/check-procs.rb -p sensu-api -C 1 -w 4 -c 5",
      "interval": 60,
      "occurrences": 2,
      "refresh": 300,
      "subscribers": [ "sensu" ]
    },
    "sensu-dashboard": {
      "handlers": [
        "default"
      ],
      "command": "/etc/sensu/plugins/processes/check-procs.rb -p sensu-dashboard -C 1 -w 1 -c 1",
      "interval": 60,
      "occurrences": 2,
      "refresh": 300,
      "subscribers": [ "sensu" ]
    }
  }
}
client.json

client.jsonは監視対象の情報や監視定義を設定するファイルであり、Sensu Client側に配置します。
checks.jsonの"subscribers"に定義した名称をsubscriptionsに指定することで、監視定義を設定することができます。

$ vi site-cookbooks/sensu-server/templates/default/client.json.erb
{
    "client": {
      "name": "sensu-server",
      "address": "127.0.0.1",
      "subscriptions": [ "default", "sensu" ]
    }
}
config.json

config.jsonはSensu Serverの定義ファイルになります。
"rabbitmq"には、追加したユーザ名(guest以外)を指定しています。

$ vi site-cookbooks/sensu-server/templates/default/config.json.erb
{
  "rabbitmq": {
    "port": 5672,
    "host": "localhost",
    "user": "admin",
    "password": "admin",
    "vhost": "/"
  },
  "redis": {
    "host": "localhost",
    "port": 6379
  },
  "api": {
    "host": "localhost",
    "port": 4567
  },
  "dashboard": {
    "host": "localhost",
    "port": 8080,
    "user": "admin",
    "password": "admin"
  },
  "handlers": {
    "default": {
      "type": "pipe",
      "command": "true"
    }
  }
}
sensu.list

sensu.listには、SensuとRabbitMQのリポジトリを指定しています。

$ vi site-cookbooks/sensu-server/templates/default/sensu.list.erb
deb http://repos.sensuapp.org/apt sensu main
deb http://www.rabbitmq.com/debian/ testing main
sensu-server.conf

sensu-server.confには、supervisorからSensu Serverを起動する設定をしています。

$ vi site-cookbooks/sensu-server/templates/default/sensu-server.conf.erb
[program:rabbitmq]
priority=10
directory=/tmp
command=/usr/sbin/rabbitmq-server
user=root
autostart=true
autorestart=true
stopsignal=QUIT

[program:redis]
priority=10
directory=/tmp
command=redis-server
user=root
autostart=true
autorestart=true

[program:sensu-server]
priority=20
directory=/tmp
command=/opt/sensu/bin/sensu-server -c /etc/sensu/config.json -d /etc/sensu -e /etc/sensu/extensions -v -l /var/log/sensu/server.log
user=root
startsecs=5
autostart=true
autorestart=true

[program:sensu-api]
priority=30
directory=/tmp
command=/opt/sensu/bin/sensu-api -c /etc/sensu/config.json -d /etc/sensu -e /etc/sensu/extensions -v -l /var/log/sensu/api.log
user=root
startsecs=5
autostart=true
autorestart=true

[program:sensu-client]
priority=40
directory=/tmp
command=/opt/sensu/bin/sensu-client -c /etc/sensu/config.json -d /etc/sensu -e /etc/sensu/extensions -v -l /var/log/sensu/client.log
user=root
autostart=true
autorestart=true

[program:sensu-dashboard]
priority=50
directory=/tmp
command=/opt/sensu/bin/sensu-dashboard -c /etc/sensu/config.json -d /etc/sensu -e /etc/sensu/extensions -v -l /var/log/sensu/dashboard.log
user=root
autostart=true
autorestart=true

Chefレシピの実行

Dockerコンテナを起動します。
22、8080、4567、5672、15672のポートを外部からアクセスできるようにしておきます。

$ sudo docker run -d -p 22 -p 8080:8080 -p 4567:4567 -p 5672:5672 -p 15672:15672 ubuntu-supervisor:12.04
$ sudo docker ps -a
CONTAINER ID        IMAGE                                 COMMAND                CREATED             STATUS                    PORTS                                                                                                                        NAMES
b245647afb46        ubuntu-supervisor:12.04               supervisord -n         27 minutes ago      Up 27 minutes             0.0.0.0:4567->4567/tcp, 0.0.0.0:5672->5672/tcp, 0.0.0.0:15672->15672/tcp, 0.0.0.0:[ポート番号]->22/tcp, 0.0.0.0:8080->8080/tcp     drunk_mayer

Sensu ServerのChefレシピを流します。
Chefを実行する時は、22番ポートにフォワードされているポート番号を指定します。

$ vi nodes/<IPアドレス>.json
{
  "run_list": [
    "recipe[sensu-server]"
  ]
}
$ knife solo bootstrap root@<IPアドレス> -p [ポート番号]

Sensu Serverの管理画面

Sensu Serverの構築ができたことを確認するため、「http://<サーバのIPアドレス>:8080」にアクセスし、Sensuのダッシュボードに接続します。ログインはadmin/adminでできます。(config.jsonで定義しています。)

f:id:hidemium:20140701233758p:plain

また、「http://<サーバのIPアドレス>:15672」にアクセスし、RabbitMQの管理画面に接続します。ログインはadmin/adminでできます。(config.jsonで定義しています。)

f:id:hidemium:20140702001932p:plain

おわりに

ChefからDockerコンテナにSensu Serverをインストールすることができました。*1
Sensuの環境ができたので、これから色々試してみたいと思います。

Sensuの特徴として、クライアント(監視対象)の自動登録がありますが、Dockerのようにscrap & buildが多い仮想環境に合っているのではと思っています。
Dockerコンテナをプロビジョニングする際に、Sensu Clientをインストールする仕組みにしておけば、コンテナをいくら起動しても監視設定を自動的にすることができるかもしれません。

*1:Chefを使ったDockerコンテナのプロビジョニングは、慣れてくると意外といい気がしてきました。