Consulをサービスディスカバリに使い、Consul TemplateでPrometheusの設定ファイルを生成するという構成で、ノードが増加しても自動的にPrometheusの収集対象が増えるような構成を作ってみました。

Prometheus

PrometheusはSoundCloudが開発を行っている監視システムです。 Graphiteと違いPrometheusはPull型のアーキテクチャをとっています。Prometheusサーバがexporterと呼ばれる所謂エージェントに値を取りに行く形です。

Push型に比べれば、Pull型は負荷が集中するので収集できるノード数は少なくなると思います。 ただ、Push型は何らかの理由でメトリクスデータをPushできなくなったときに、検知が困難になるというデメリットもあります。 Pull型であれば取れなかったことが検知でき、その理由も調べることが可能です。

時系列データストアは自前の物を利用しているようですが、OpenTSDBも利用可能らしいです。 独自のクエリをサポートしており、収集したデータを加工して表示することも出来ます。 グラフ表示機能はPrometheusサーバにも簡易的な物が用意されていますが、 Rails で書かれた PromDash というものを利用するのが良さそうです。 その他、Push型のデータを収集するための pushgateway や、アラートを出すための alertmanager もあります。

今回は Prometheus Server と node_exporter を利用します。

動作環境

今回は AWS EC2 を使用します。

  • Amazon EC2
  • Amazon Linux 2015.03.1
    • Prometheus 0.14.0
    • node_exporter 0.9.0
    • Consul 0.5.2
    • Consul Template 0.10.0

Tags

EC2のタグは以下のようにしておきます。

Node Tag Description
server1 consul-leader: True Consul Server, Prometheus Server
node1 - Consul Agent, node_exporter
node2 - Consul Agent, node_exporter

Ports

Program Protocol Port
Prometheus Server TCP 9090
node_exporter TCP 9100
Consul Server TCP 8300, 8301, 8400, 8500, 8600
UDP 8600
Consul Agent TCP 8400, 8500
UDP 8600

Consul Server と Consul template, Prometheusの設定

ConsulはPrometheusに比べれば有名なので説明は割愛。 インストール手順も割愛。

まずは、ConsulとConsul Templateが起動するようにします。 Consul Serverのアドレスを取得するためにEC2のタグを参照するので、IAM Roleを付けておきます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances"
            ],
            "Resource": [
                "arn:aws:ec2:::*"
            ]
        }
    ]
}

Consul Server

Upstart を使用し Consul Serverを起動させます。

  • /etc/init/consul_server.conf
description "Consul"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

script
  if [ -f "/etc/service/consul" ]; then
    . /etc/service/consul
  fi

  # Make sure to use all our CPUs, because Consul can block a scheduler thread
  export GOMAXPROCS=`nproc`
  exec /usr/local/bin/consul agent \
   -server \
   -data-dir="/var/lib/consul/" \
   -bootstrap-expect 1 \
   -config-dir="/etc/consul.d/" \
   ${CONSUL_FLAGS} \
   >>/var/log/consul.log 2>&1
end script
$ sudo initctl start consul_server

Consul Template

Consul templateはConsulのクラスタ情報を元にファイルを生成してくれます。 クラスタに変化があると、ファイルを更新し、指定したコマンドを実行してくれます。

  • /etc/init/consul_template.conf
description "Consul template"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

script
  exec /usr/local/bin/consul-template \
      -consul 127.0.0.1:8500 \
      -template "/opt/templates/prometheus.ctmpl:/etc/prometheus/prometheus.yml:initctl restart prometheus" >> /var/log/ctemplate.log 2>&1
end script
$ sudo initctl start consul_template

Prometheus

テンプレートの用意

Consul TemplateでPrometheusのコンフィグを生成するためテンプレートを用意します。

  • /opt/templates/prometheus.ctmpl
global:
  scrape_interval:     1s
  evaluation_interval: 3s

  labels:
    monitor: 'web monitor'

scrape_configs:
  - job_name: 'prometheus'
    scrape_interval: 10s
    scrape_timeout: 10s
    target_groups:
      - targets: ['localhost:9090']

  - job_name: 'web'
    scrape_interval: 10s
    scrape_timeout: 10s
    target_groups:
      - targets: [{{range service "web"}}'{{.Address}}:9100',{{end}}]

service名は web としています。 この値は後述する Consul Agent とあわせる必要があります。

scrape_intervalは値を取得する間隔を指定します。

Prometheus にはConsulと連携する機能があるようなのですが、イマイチ使い方が判りませんでした。 これが使えれば、Consul Templateは不要かもしれません。

Prometheusのインストール

ここはまあ、普通に。 Ansible Playbookとかにしておくと良いかもしれません。

$ sudo yum install golang git mercurial gcc-c++ epel-release
$ sudo yum install --enablerepo=epel protobuf
$ cd /usr/local/src
$ git clone https://github.com/prometheus/prometheus.git
$ cd prometheus
$ make build
$ sudo useradd -s /bin/false -m prometheus
$ sudo mkdir /etc/prometheus

初期の設定ファイルがないと起動しないので、作成しておきます。

  • /etc/prometheus/prometheus.yml
global:
  scrape_interval:     1s
  evaluation_interval: 3s

  labels:
    monitor: 'web monitor'

scrape_configs:
  - job_name: 'prometheus'
    scrape_interval: 10s
    scrape_timeout: 10s
    target_groups:
      - targets: ['localhost:9090']

PrometheusもUpstartで起動させます。

  • /etc/init/prometheus.conf
description "Prometheus"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

script
  /usr/local/src/prometheus/prometheus -config.file=/etc/prometheus/prometheus.yml
end script
$ sudo initctl start prometheus

Consul Agentの設定とサービスの定義

Consul Agent

こちらもConsul Serverと同じく Upstart で起動させます。 起動する際に、Consul Serverのアドレスを AWS CLI を使って取得し、クラスタへJoinさせます。

  • /etc/init/consul_agent.conf
description "Consul"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

script
  if [ -f "/etc/service/consul" ]; then
    . /etc/service/consul
  fi

  # Make sure to use all our CPUs, because Consul can block a scheduler thread
  export GOMAXPROCS=`nproc`
  JOIN_TO="$(aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`].PrivateIpAddress' --output text --filters 'Name=tag:consul-leader,Values=true')"

  exec /usr/local/bin/consul agent \
   -data-dir="/var/lib/consul" \
   -config-dir="/etc/consul.d" \
   -join ${JOIN_TO} \
   ${CONSUL_FLAGS} \
   >>/var/log/consul.log 2>&1
end script

ついでにサービスの定義も行います。 Consulは簡易なサービスのチェックも行えるようになっております。

  • /etc/consul.d/web.json
{
  "services":[
    {
      "name": "Web",
      "port": 80,
      "check": {
        "script": "curl -s http://localhost/ -o /dev/null",
        "interval": "10s"
      },
      "tags": ["http"]
    }
  ]
}
$ sudo initctl start consul_agent

これらを組み込んだAMIを作っておいて、あとはインスタンスを起動していけば自動的にどんどん監視対象が増えていきます。

PromDash

PromDashというダッシュボード的なWebインターフェイスが提供されています。 PromDashはRailsで出来ており、動かすのがめんどうなので、Dockerで動かすのがオススメです。

PromDash内のデータベースには、PrometheusサーバのURLと表示するグラフに関する情報のみ記録されてるだけなので、Dockerコンテナが消えても、収集したメトリクスは消えません。

$ docker pull prom/promdash
$ docker run -v /tmp/prom:/tmp/prom -e DATABASE_URL=sqlite3:/tmp/prom/file.sqlite3 prom/promdash ./bin/rake db:migrate
$ docker run -d -p 3000:3000 -v /tmp/prom:/tmp/prom -e DATABASE_URL=sqlite3:/tmp/prom/file.sqlite3 prom/promdash

所感

監視を行うのに一通りの機能は揃っていますが、長期的に運用するときにどのような問題が出るか不透明な点はあります。 短期間使ってみた感じでは、短期間のメトリクス収集にはとても有用な感じがしました。 クエリによる値の集計なども簡単にできてよいです。

プロダクション環境では本格的に使ったわけではありませんが、イベントなどで使うインフラのメトリクス収集に何回か利用しています。

使い分けとしては、インスタントにメトリクスをとりたい場合は pcp + Vector, 短期間のメトリクス収集には Prometheus, 長期的な監視やメトリクス収集は Zabbix や Sensu + Graphite がよいかなと。

ほんとはデータの管理とかやりたくないので、Mackerel, Datadog が安くなればいいですね。