Humanity

Edit the world by your favorite way

Rundeck ジョブの実行ノード一覧を Consul から取得する

長い前置き

最近 Consul, Prometheus などを試す記事が続いてますが、 なぜかというと、私はサーバ監視などに Hinemos を使っており、いい加減別のシステムに移行したい欲が強まってきたからです。

tyru.hatenablog.com

Hinemos はオールインワンのため、ジョブ管理やら死活監視やら CPU やメモリなどの使用率をグラフで表すなどの機能が全部入ってます。 しかし Hinemos リッチクライアントと呼ばれるツールが Windows しか対応してなくて Windows からしか設定をいじったり見ることができなかったり、あと重かったり、UI がいけてなかったりでストレスが溜まっていました。

Hinemos 5 からは Hinemos Web クライアントという HTTP で見れるクライアントが提供されたらしいので試したかったのですが、 Hinemos 4 からの移行はどうやら無理のようでした(できるオプションは有償)。

そんな感じで心底嫌気がさしていたのでいい加減普通の今流行りの OSS に移行したい、ということで最近勢いで色々試しているというわけです。

最近は Consul + Prometheus(監視システム)とか、あと記事には書いてないですが Prometheus + Grafana(CPU やメモリなどの使用率をグラフ描画)*1を試してきました。 そこで次は良いジョブ管理システムがないか探したところ、前もちょこっとだけ試した Rundeck というジョブ管理システムを試すことにしました。

導入記事などはこちら。

dev.classmethod.jp

しかし実行ノードの一覧を追加するには ssh ログインしてファイルを編集しなければならないと書いてあり、 なんとかならんもんかとドキュメントを漁ってみたら結構色んなリソースからのノード一覧取得に対応しているみたいでした。

公式ドキュメントによると

  • file
  • url
    • 指定された URL に GET してノード一覧を取得
  • directory
    • 指定されたディレクトリの中のファイルの内容からノード一覧を取得
  • script

そこで今回はこの中の script を使って、Consul に join しているノードが自動的に実行対象になるようにしてみます(実行ノードはプロジェクトページで絞り込むこともできます)。

Rundeck のインストール、SSH 鍵の配置、等々

省略します。 上の導入記事などを見てください。

スクリプト配置

以下のスクリプトを実行権限付きで置いておきます(rundeck ユーザから見えるパスにしてください)。 自分は /var/rundeck/list-consul-nodes.sh に置きました。

※今後けっこう更新するかもしれないので一応この記事を書いた段階のリビジョンを伝えておくと、9d6c7d0 です。

ちなみに出力する YAML の設定ファイルの書式は以下のページを参考にしました。

RESOURCE-YAML

Rundeck でスクリプトを指定

プロジェクトの編集ページからスクリプト追加。

f:id:tyru:20170804231251p:plain

f:id:tyru:20170804231300p:plain

f:id:tyru:20170804231359p:plain

f:id:tyru:20170804231406p:plain

これで設定は完了です。

ちなみにスクリプトを指定したけど動かない(ノード一覧に何も出ない、もしくは前回のスクリプトのノード一覧出力結果から変わらない)って場合はスクリプトの終了コードが 0 以外で終了してるなどが多いです。 画面上では全くエラーが出ないのですが… /var/log/rundeck/service.log のログを見れば分かります。

こんなエラーが出ます

ERROR ExceptionCatchingResourceModelSource: [ResourceModelSource: 1.source (script), project: test2]
com.dtolabs.rundeck.core.resources.ResourceModelSourceException: failed to execute: /var/rundeck/list-consul-nodes.sh: Script execution failed with result: 1
        at com.dtolabs.rundeck.core.resources.ScriptResourceModelSource.getNodes(ScriptResourceModelSource.java:170)
        at com.dtolabs.rundeck.core.resources.ExceptionCatchingResourceModelSource.getNodes(ExceptionCatchingResourceModelSource.java:57)
        at com.dtolabs.rundeck.core.common.ProjectNodeSupport.getNodeSet(ProjectNodeSupport.java:113)
        at com.dtolabs.rundeck.core.common.ProjectNodeSupport$ProjectNodesSource.getNodes(ProjectNodeSupport.java:327)
        at com.dtolabs.rundeck.core.resources.ExceptionCatchingResourceModelSource.getNodes(ExceptionCatchingResourceModelSource.java:57)
        at com.dtolabs.rundeck.core.resources.ResourceModelSource$getNodes.call(Unknown Source)
        at rundeck.services.nodes.CachedProjectNodes.reloadNodeSet(CachedProjectNodes.groovy:42)
        at rundeck.services.nodes.CachedProjectNodes$reloadNodeSet.call(Unknown Source)
        at rundeck.services.NodeService$_loadNodes_closure3.doCall(NodeService.groovy:261)
        at rundeck.services.NodeService$_loadNodes_closure3.doCall(NodeService.groovy)
        at sun.reflect.GeneratedMethodAccessor1515.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1207)
        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
        at groovy.lang.Closure.call(Closure.java:423)
        at groovy.lang.Closure.call(Closure.java:417)
        at com.codahale.metrics.Timer.time(Timer.java:99)
        at com.codahale.metrics.Timer$time$0.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
        at com.codahale.metrics.Timer$time$0.call(Unknown Source)
        at MetricswebGrailsPlugin$_addDynamicMetricMethods_closure26.doCall(MetricswebGrailsPlugin.groovy:190)
        at sun.reflect.GeneratedMethodAccessor338.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1207)
        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
        at groovy.lang.Closure.call(Closure.java:423)
        at org.codehaus.groovy.runtime.metaclass.ClosureStaticMetaMethod.invoke(ClosureStaticMetaMethod.java:59)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
        at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoMetaMethodSiteNoUnwrap.invoke(PogoMetaMethodSite.java:230)
        at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:68)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callSafe(AbstractCallSite.java:96)
        at rundeck.services.NodeService$_loadNodes_closure4.doCall(NodeService.groovy:268)
        at rundeck.services.NodeService$_loadNodes_closure4.doCall(NodeService.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1207)
        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
        at groovy.lang.Closure.call(Closure.java:423)
        at groovy.lang.Closure.call(Closure.java:417)
        at groovy.lang.Closure.run(Closure.java:504)
        at org.springframework.core.task.SimpleAsyncTaskExecutor$ConcurrencyThrottlingRunnable.run(SimpleAsyncTaskExecutor.java:251)
        at java.lang.Thread.run(Thread.java:748)
Caused by: com.dtolabs.rundeck.core.resources.ResourceModelSourceException: Script execution failed with result: 1
        at com.dtolabs.rundeck.core.resources.ScriptResourceUtil.executeScript(ScriptResourceUtil.java:147)
        at com.dtolabs.rundeck.core.resources.ScriptResourceModelSource.getNodes(ScriptResourceModelSource.java:156)
        ... 55 more
WARN  LoggingResourceModelSourceCache: [ResourceModelSource: 1.source (script), project: test2] Returning cached model data

テスト実行

さっそくテスト実行してみましょう。 偶然チャックノリスの API を見つけたのでランダムなテキストを表示させて無駄に複数のノードで実行してる感を出してみました。

実行するコマンド

今回このために jq コマンドインストールした。 どうでもいいけど最近コマンドラインJSON 整形する必要が出てきて jq コマンド便利というのを知った。

curl -s https://api.chucknorris.io/jokes/random | jq -r '.value'

実行結果

ちゃんとランダムでチャックノリスの情報が表示されているのが分かります(ホスト名は伏せました)。

f:id:tyru:20170804233633p:plain

*1:Grafana はインストールも簡単なのでこの記事とか見ればすぐできるでしょう

MSYS2 から Bash on Windows + Cmder に移って、その後 Bash on Windows + wsltty に変えた

Bash on Windows が beta 外れたから MSYS2 から BoW + Cmder な環境に移った。 移ってたんだけど、コピペが Ctrl-C, Ctrl-V とかありえないショートカットキーだったり、 まぁそれは変えればいいんだけど、そもそも重いしウインドウをリサイズすると画面真っ白になったりするから mintty/wsltty に変えた。

github.com

wsltty は WSL 用の mintty で、タブは使えないけどこれまで MSYS2 で mintty 使ってたこともあって操作に慣れ親しんでるし、 変えた設定といえば、フォントを Ricty Diminished Discord に変えたのと、 bash のプロンプトに色が付かなかったので $TERM を xterm から xterm-256color に変えたくらい。

f:id:tyru:20170801222445p:plain

マルチプレクサも特に使わない。 自分の場合そういうのを使うと意味なく無駄に開いてしまう悪い癖があって、ただでさえ少ない脳のリソースが無駄に割かれてしまう。

というわけでまだ切り替えて一日目だけど、これで大分満足してしまった。

Consul を Prometheus と連携させてみる

前回まで Prometheus による監視や、Alertmanager によるアラート通知などを書いてきた。

tyru.hatenablog.com

tyru.hatenablog.com

ただ設定ファイルを見ると分かる通り、監視対象のノードが増える度に手動で設定ファイルに追記していくのはとても面倒。自動化したい。 幸いにも Prometheus には監視対象を連携システムから取得するための機能が豊富にある。 今回は Consul と連携してノードが増える度に自動で監視対象も増やせるようにする。

サーバとエージェントを同じノードで動かすのは無理のようなので Consul server と Consul agent は別ノードにインストールします。 前回に引き続いてこんな構成になってます。

  • 監視サーバ(ホスト名:promhost)
    • Prometheus server, Alertmanager, node_exporter, Consul server
  • 監視対象のサーバ(ホスト名:targethost)
    • node_exporter, Consul agent

Consul とは?

散々解説はあると思うのでそちらで(詳しい解説ができないだけ)。 以下は素晴らしい連載記事。

gihyo.jp

あと公式の Getting Started も分かりやすくていい。

prometheus.io

自分の理解だと

  • サーバ・クライアント型
  • KVS 機能を持っていて以下の情報等を格納している
  • サーバに接続しているノード一覧の情報
  • どんなサービスがどこで稼働しているか(サービスディスカバリ)
  • サービスの検出のために監視機能はあるがアラート機能はない

サービスディスカバリによって得たノード一覧とかの情報を KVS に蓄えているので、 それを Prometheus に渡してアラートはそいつにやってやろうみたいなノリです(実際は Prometheus から情報を Pull するので逆ですが)。

Consul のインストール

Consul のバイナリは Prometheus と違い GitHub の releases には置いてない(ソースコードのみ)。 公式サイトのダウンロードページからダウンロードしてくる。 zip で配布されているので、Linux 上で展開するなら unzip をインストールする必要があるかもしれない。

$ sudo yum install unzip  # なければインストール
$ curl -LO https://releases.hashicorp.com/consul/0.9.0/consul_0.9.0_linux_amd64.zip
$ unzip consul_0.9.0_linux_amd64.zip

展開すると consul というバイナリが一つだけカレントディレクトリに展開される。 これを /opt/consul/consul としてインストールする。

$ sudo mkdir /opt/consul
$ sudo mv consul /opt/consul/
$ sudo chmod 755 /opt/consul
$ sudo chown -R root:root /opt/consul

バイナリのインストール終わり。 このバイナリ単体でサーバとエージェント両方兼ねている。 ちなみにインストールの簡単さから想像できる通り Consul も Go 製。

あとは systemd で起動できるように設定ファイルを作る。

Consul エージェント用

エージェント用のノードにインストールするファイル。 まだエージェントとクライアントの違いが分かってない… ともかくまずは設定ファイル用ディレクトリを作っておく。

$ sudo mkdir /etc/consul.d

次に設定ファイルを作る。

  • /etc/systemd/system/consul-agent.service
[Unit]
Description=Consul Agent
After=network.target

[Service]
Type=simple
EnvironmentFile=-/etc/default/consul-agent
ExecStart=/opt/consul/consul agent $OPTIONS
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • /etc/default/consul-agent

-data-dir はデータディレクトリ。 -node は Consul クラスタ上で重複しない名前。自分はホスト名を設定した(これ後でエージェントごとにインストールする時自動生成したいなぁ)。 -config-dir は設定ファイル用のディレクトリ。 -join は Consul サーバのIPアドレスかホスト名。

OPTIONS="-data-dir=/var/lib/consul-agent -node=targethost -config-dir=/etc/consul.d/ -join=promhost"

ちなみに -node に指定する値を $(hostname) にしたらまんま $(hostname) ってノード名で追加されてしまった。 systemd の EnvironmentFile に指定するのってシェルスクリプトじゃないのね…(SysVinit ならいけたような?)

OPTIONS="-data-dir=/var/lib/consul-agent -node=$(hostname) -config-dir=/etc/consul.d/ -join=promhost"

で、こんな感じになった。

$ sudo /opt/consul/consul members
Node         Address              Status  Type    Build  Protocol  DC
promhost     xxx.xxx.xxx.xxx:8301  alive   server  0.9.0  2         dc1
$(hostname)  zzz.zzz.zzz.zzz:8301  alive   client  0.9.0  2         dc1

ノード名修正したら今度はこんな風になった。 Status が failed になってるけど一覧から削除されてない。

Node         Address              Status  Type    Build  Protocol  DC
$(hostname)  xxx.xxx.xxx.xxx:8301  failed  client  0.9.0  2         dc1
promhost     yyy.yyy.yyy.yyy:8301  alive   server  0.9.0  2         dc1
targethost   xxx.xxx.xxx.xxx:8301  alive   client  0.9.0  2         dc1

こういう時は consul force-leave を行うと left 状態にはできる(failed と left の違いはこちら)。 ただそれでも一覧からは削除されない。

$ sudo /opt/consul/consul force-leave '$(hostname)'
$ sudo /opt/consul/consul members
Node         Address              Status  Type    Build  Protocol  DC
$(hostname)  xxx.xxx.xxx.xxx:8301  left    client  0.9.0  2         dc1
promhost     yyy.yyy.yyy.yyy:8301  alive   server  0.9.0  2         dc1
targethost   xxx.xxx.xxx.xxx:8301  alive   client  0.9.0  2         dc1

公式サイトによると、

Q: Are failed or left nodes ever removed?

To prevent an accumulation of dead nodes (nodes in either failed or left states), Consul will automatically remove dead nodes out of the catalog. This process is called reaping. This is currently done on a configurable interval of 72 hours. Reaping is similar to leaving, causing all associated services to be deregistered. Changing the reap interval for aesthetic reasons to trim the number of failed or left nodes is not advised (nodes in the failed or left state do not cause any additional burden on Consul).

Frequently Asked Questions - Consul by HashiCorp

72時間ごとに failed や left になったノードを一覧から削除する reaping と呼ばれる処理が実行されるとのこと。 一覧に残ってて見た目上気になるからこの間隔を変えるのは推奨されないとまで書いてある。 というわけで気にしないことにする。 ただ consul-server を再起動したら $(hostname) がいなくなってたので、もしかしたら再起動すると自動的に reaping が行われるのかもしれない。

  • systemd で起動
$ sudo systemctl daemon-reload
$ sudo systemctl enable consul-agent  # 今回は検証のためなので自分の環境ではやらなかった
$ sudo systemctl start consul-agent

Consul サーバ用

サーバ用のノードにインストールするファイル。

  • /etc/systemd/system/consul-server.service
[Unit]
Description=Consul Server
After=network.target

[Service]
Type=simple
EnvironmentFile=-/etc/default/consul-server
ExecStart=/opt/consul/consul agent -server $OPTIONS
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • /etc/default/consul-server

-data-dir はデータディレクトリ。 -bootstrap-expect は Consul サーバの数。 ネットワークインターフェースが複数ある環境では -bind=IPアドレス も付けないといけないらしいです。

ちなみにサーバー側のサービス定義も公開するならエージェントと同じく -config-dir=/etc/consul.d/ を付ければ良い。 サービス定義の設定ファイルに関しては後述。

OPTIONS="-bootstrap-expect=1 -data-dir=/var/lib/consul-server"
  • systemd で起動
$ sudo systemctl daemon-reload
$ sudo systemctl enable consul-server  # 今回は検証のためなので自分の環境ではやらなかった
$ sudo systemctl start consul-server

Consul サービス設定

※サービス設定は多分 Prometheus で監視するならいらない。理由は後述。

先ほど空の /etc/consul.d ディレクトリを作っておいたが、その中に Web サーバなどのサービス用の設定ファイルを作っていく。 サーバ側で管理するんじゃなくノード側に自分を監視する設定を置くのは新鮮。 あと設定ファイルが JSON なのも割と新鮮。 以下は第6回の記事からの引用。

  • /etc/consul.d/web.json
{
  "service": {
    "name": "web",
    "tags": [ "nginx" ],
    "port": 80,
    "check": {
      "script": "curl http://127.0.0.1:80/consul.html >/dev/null 2>&1",
      "interval": "10s",
      "timeout": "5s"
    }
  }
}

今回のために nginx 用意するのもだるかったので前回インストールした node_exporter が HTTP でメトリクス情報を公開してるので、 それを監視することにする(というか Prometheus はここを監視してるのですでにアラートは行く状態になってるけど、今回はテストなので)。 テストのつもりで追加しましたが、Prometheus に監視させるために必要でした。理由は後述。

設定ファイルはこんな感じ。

  • /etc/consul.d/node_exporter.json
{
  "service": {
    "name": "node_exporter",
    "tags": ["node_exporter"],
    "port": 9100
  }
}

まだ詳しく分かってないけどこれでサービスの定義はできる。 監視もするなら

{
  "service": {
    "name": "node_exporter",
    "tags": ["node_exporter"],
    "port": 9100,
    "check": {
      "script": "curl http://targethost:9100 >/dev/null 2>&1",
      "interval": "10s"
    }
  }
}

みたいにするって Getting Started でも書いてあったんだけど動かなかった。

ちなみに失敗した際のログ

$ sudo systemctl status -l consul-agent.service
● consul-agent.service - Consul Agent
   Loaded: loaded (/etc/systemd/system/consul-agent.service; disabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since 日 2017-07-30 18:39:58 JST; 1s ago
  Process: 4575 ExecStart=/opt/consul/consul agent $OPTIONS (code=exited, status=1/FAILURE)
 Main PID: 4575 (code=exited, status=1/FAILURE)

 7月 30 18:39:58 targethost consul[4555]: 2017/07/30 18:39:58 [INFO] Exit code:  0
 7月 30 18:39:58 targethost systemd[1]: Started Consul Agent.
 7月 30 18:39:58 targethost systemd[1]: Starting Consul Agent...
 7月 30 18:39:58 targethost consul[4575]: ==> Starting Consul agent...
 7月 30 18:39:58 targethost consul[4575]: ==> Error starting agent: Failed to register service '': Check types that exec scripts are disabled on this agent
 7月 30 18:39:58 targethost systemd[1]: consul-agent.service: main process exited, code=exited, status=1/FAILURE
 7月 30 18:39:58 targethost systemd[1]: Unit consul-agent.service entered failed state.
 7月 30 18:39:58 targethost systemd[1]: consul-agent.service failed.

まぁ監視は Prometheus でやるからいいか、って思ったのでとりあえず今回はやらないことにした。

ちなみに無事設定がうまくいったらサーバ側で以下のコマンドで node_exporter がいるのを確認できるはずです。

$ sudo /opt/consul/consul catalog services
consul
node_exporter

Prometheus との連携

で、上でサービスの定義とか書いてみたんだけど、ぶっちゃけ Prometheus で監視するためには必要ない。 なぜかというと Prometheus としては exporter が動いてるノード一覧を取得することが目的なので、サービスが定義されていなくても大丈夫(のはず)。 ただオプションで監視対象のサービスを Prometheus で絞り込むことはできる(参照:/scrape_configs/consul_sd_config/services)。

…と思ってたんですが、どうやら監視対象はサービスで決まる様子。 つまり services で絞り込んでやらないとデフォルトで提供される consul のサービスを見に行ってしまう(8300 は consul が RPC に使うポートなので Prometheus に見に行ってもらっても困るんですが…)。 ということで上記で定義した node_exporter で絞り込むことにする。つまりこう。

scrape_configs:
  - job_name: 'consul_sd_configs'
    consul_sd_configs:
      - server: 'localhost:8500'
        services:
          - 'node_exporter'  # node_exporter というタグを持つサービスのみ監視

監視対象のホスト名を表示する

そのままだと http://<prometheus host>/targets に表示されるノードは IP アドレスで表示される。 またアラートが来た時も同じ。

IP アドレスだとパッと見どのノードなのか分かりづらい。 なので代わりにホスト名で表示する。

Controlling the instance label | Robust Perception

この記事を参考に書いた Consul 用の設定は以下の通り。

relabel_configs:
  - source_labels: [__meta_consul_node]
    regex:  '(.*)'
    target_label: __address__
    replacement: '${1}:9100'
  - source_labels: [__meta_consul_node]
    target_label: instance

…と思ったんだけどこれだとポートが 9100 固定になっている。 それ以外のポートで動作させたり、この記事で書いたように複数の exporter を同じノード上で動作させることができない。 というわけで以下の設定になった。

relabel_configs:
  - source_labels: [__meta_consul_node, __meta_consul_service_port]
    separator: ':'
    target_label: __address__
  - source_labels: [__meta_consul_node]
    target_label: instance

これでちゃんと Consul エージェント側で定義したポートを見に行ってくれる。

Prometheus が監視しにいく URL を見る方法は?

http://<Prometheus>/targets で見れる。

f:id:tyru:20170730224109p:plain

監視対象のポートが違うんだけど…

先ほどエージェント側に置いた /etc/consul.d/node_exporter.json のファイルの port をチェックすること。

Consul が公開しているサービスの情報

curl http://<Consul server>:8500/v1/catalog/service/<service> で見れる(例: = node_exporter)。 JSON 見づらいので jq コマンド必須。

$ curl http://<Consul server>:8500/v1/catalog/service/node_exporter | jq .

Consul が使うポート

参考に Consul が使うポートをこちらの記事から引用。

機能 TCP/UDP ポート 説明
Server RPC TCP 8300 Server が他の Agent からRPCのリクエストを受け付ける
Serf LAN TCP & UDP 8301 LAN用のゴシッププロトコル。全 Agent 同士が使う
Serf WAN TCP & UDP 8302 WAN用のゴシッププロトコル。Server 同士が使う
CLI RPC TCP 8400 consulコマンド実行時にローカルの Agent との通信に使われる
HTTP API TCP 8500 Client が HTTP リクエストを受け付ける
DNS TCP & UDP 8600 Agent が DNSクエリを受け付ける

雑感

最近 Go 製のツールを構築してく中で思ったのは、Go 製のツールってあえて明示的に設定ファイルを指定する必要があったり、 暗黙的に色々参照したりしない傾向があるような気がする(サンプル数少ないけど)。 Go の文化なのかな。