地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Consul】入門する

背景/概要

Consulを使う機会が出てきたのでメモ。「Prometheusから利用できそうだね」くらいを理解のゴールとして設ける。

この記事でやれることはconsulの入門とdnsでサーバのIPを引けるようになるまで。dnsは別で立ててますが閉じた検証にしたいのでとりあえずdnsmasqを入れて代用してます。

Consulとは

www.consul.io

インフラ上のサービス設定とサービスディスカバリのためのツール。Consul自体は複数のコンポーネントがあるが全体としてサービスディスカバリのツールって認識で良さそう。

github.com

HashiCorpが公開していて実装言語はGolangとなっている。主な機能としては以下

ざっくりアーキテクチャは以下のような感じ。

f:id:ryuichi1208:20210717211528p:plain

(Hashicorp が提供しているデータセンタ管理ツール群 ATLAS の一部で、クラスタリングと分散KVS、オーケストレーションの基礎となる機能をいくつか提供してくれるとあるがメイン機能がどれなのかとても迷いそうなアーキテクチャ図だなと感じた。。)

公式のはこっち

f:id:ryuichi1208:20210718000602p:plain

サービス・ディスカバリってなんだっけ

サービス・ディスカバリ(Service Discovery)とは、日本語では「サービスの発見」や「検出」という意味あいで使われる。サービスディスカバリの機能はConsulを通してどのサーバでどのようなサービスが動作しているかやIPやポートをリアルタイムで知ることができる機能

Consulノードはサービス状況に変化が発生すると、「Consulサーバ」に対してデータを送信します。consulサーバは受け取ったデータとkvsに保存し情報を知りたい側のクライアントがhttpやcliを使ってサーバの検出を行います。

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クエリを受け付ける

障害検知

Consul node がヘルスチェックを実施する、検出済みのサービスに対する障害発生を検出する。監視間隔や対象は、ノードが主体的に対象ホスト内部から監視

HTTP または DNS インターフェース、Web UI で確認できるといった仕組み。

qiita.com

ざっくり触る

スタンドアロン構成で動かしてみます。

install

公式に方法があるのでそのままやってみます。

www.consul.io

$ sudo yum install -y yum-utils
$ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
$ sudo yum -y install consul

[root@master ~]# consul version
Consul v1.10.1
Revision db839f18b
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

usage

多機能が売りというだけあってhelpだけでも盛りだくさん機能が伺えます。とりあえずagentぐらいが見れれば良さそう。

[root@master etc]# consul --help
Usage: consul [--version] [--help] <command> [<args>]

Available commands are:
    acl            Interact with Consul's ACLs
    agent          Runs a Consul agent
    catalog        Interact with the catalog
    config         Interact with Consul's Centralized Configurations
    connect        Interact with Consul Connect
    debug          Records a debugging archive for operators
    event          Fire a new event
    exec           Executes a command on Consul nodes
    force-leave    Forces a member of the cluster to enter the "left" state
    info           Provides debugging information for operators.
    intention      Interact with Connect service intentions
    join           Tell Consul agent to join cluster
    keygen         Generates a new encryption key
    keyring        Manages gossip layer encryption keys
    kv             Interact with the key-value store
    leave          Gracefully leaves the Consul cluster and shuts down
    lock           Execute a command holding a lock
    login          Login to Consul using an auth method
    logout         Destroy a Consul token created with login
    maint          Controls node or service maintenance mode
    members        Lists the members of a Consul cluster
    monitor        Stream logs from a Consul agent
    operator       Provides cluster-level tools for Consul operators
    reload         Triggers the agent to reload configuration files
    rtt            Estimates network round trip time between nodes
    services       Interact with services
    snapshot       Saves, restores and inspects snapshots of Consul server state
    tls            Builtin helpers for creating CAs and certificates
    validate       Validate config files/directories
    version        Prints the Consul version
    watch          Watch for changes in Consul

起動

bindとclientあたりはよしなに。(consul は基本ローカルアドレスからのアクセスしか受け付けませんのでその辺は注意)

$ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul --bind 192.168.1.15 --client=0.0.0.0

これで準備は完了。consulコマンドでmembersやらを打つことで自信が参加していることを確認可能となります。サーバ側の準備ができたので次はクライアントをここへ参加させます。

$ consul agent -data-dir /tmp/consul -bind <IPアドレス> -join <ConsulサーバのIPアドレス>

正常に通信ができると、自動的にクラスタが構成されます。「consul members」コマンドを実行すると、次のように複数のホスト情報が確認できます。

[root@master ~]# consul members
Node    Address             Status  Type    Build   Protocol  DC   Segment
master  192.168.1.15:8301   alive   server  1.10.1  2         dc1  <all>
slave   192.168.1.207:8301  alive   client  1.10.1  2         dc1  <default>

httpでjsonを取ることとかもできる。APIとかアプリケーションからsdしたいケースだとこっちになるんでしょうか。

curl -s http://192.168.39.5:8500/v1/kv/hello/?recurse | jq '.'
[
  {
    "Value": "b3BlbiB0aGUgbmV4dA==",
    "Flags": 0,
    "Key": "hello/key2",
    "ModifyIndex": 16,
    "CreateIndex": 16
  },
  {
    "Value": "aGVsbG8sIHdvcmxkIQ==",
    "Flags": 0,
    "Key": "hello/key",
    "ModifyIndex": 14,
    "CreateIndex": 14
  }
]

dnsで引けるようにする

consulにはDNSクエリを受け付ける機能もあるので以下のようにメンバーを引くことができる。ただポート指定したりDNSサーバを指定したりと面倒なのでdnsmasqを導入することでそのような手間を解決することもできる。

$ dig @localhost -p 8600 master.node.consul

dnsmasqをセットアップする。resolve.confも自サーバを向くように修正しておく

$ yum -y install dnsmasq
$ echo  "server=/consul/127.0.0.1#8600" >> /etc/dnsmasq.conf
$ echo  "strict-order" >> /etc/dnsmasq.conf

このように設定しておけばdnsの指定をしなくてもdigで自宅内のサーバのIPを引けるようになる。

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;slave.node.consul.     IN  A

;; ANSWER SECTION:
slave.node.consul.  0   IN  A   192.168.1.207

;; ADDITIONAL SECTION:
slave.node.consul.  0   IN  TXT "consul-network-segment="

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 土  7月 17 09:04:12 EDT 2021
;; MSG SIZE  rcvd: 98

サービスを使ってみる

サービスを使うことでサーバをグルーピングして死活監視などを行うことができます。prometheusとかで監視する際にはこの設定は必須になりそうなやつですね。以下のように監視対象のサーバにファイルを作成します。概要としてはchecksで書いた内容を監視しつつserviceに名前を登録するという感じです。適当に80でhttp通信を可能な状態にしておきます。

{
    "service": {
        "name": "web",
        "tags": [
            "rails"
        ],
        "port": 80,
        "check": {
            "args": [
                "curl",
                "localhost"
            ],
            "interval": "10s"
        }
    }
}

上記を設定した上で以下のようにconsulを起動します。"-config-dir", "-enable-script-checks"がポイントです。

consul agent -data-dir /tmp/consul -bind 192.168.1.207 -join 192.168.1.15 -config-dir /etc/consul.d -enable-script-checks=true

こんな感じで起動することでhttp:80の通信が可能なサーバは以下のようにdnsの名前引きで引くことが可能となります。このレコードを使うことで例えばLBのバックエンドを動的に決めたりすることが可能だったりprometheusとしてはwebというサービスでグルーピングして監視が可能になったりします。とても便利!

;; ANSWER SECTION:
web.service.consul. 0   IN  A   192.168.1.15
web.service.consul. 0   IN  A   192.168.1.207

KVS機能

kvs機能もconsulは持っている。これのユースケースとしてはconsulサーバにkvを登録しておけばconsulクライアント側がこの値をみにいく。ここの値に例えばミドルウェアとかで有効な値を設定しておくことでユーザが設定値をpostするとミドルウェアが動いているサーバがその値を元にサービスを再起動したりみたいなことが可能となる。

# post
$ curl -X PUT http://localhost:8500/v1/kv/$(hostname)/test -d "test_data"
true

# get(base64でエンコードされているのでデータをみるには以下の作業が必要)
$ curl -s http://localhost:8500/v1/kv/$(hostname)/test | jq .[].Value | tr -d '"' | base64 -d
test_data

メンテナンスを試す

バックエンドのサービスのうち1台だけをメンテモードにしてLBから切り離すみたいなことも可能。(LBを経由しないラウンドロビンをクライアントで実装してるみたいな場合はきちんとレコード以外を見るみたいなことを自分で実装する必要があるっぽいのでそこは注意。memd-perlとかそのあたりは怪しい。)

[root@master tmp]# consul maint

[root@master tmp]# dig web.service.consul
;; ANSWER SECTION:
web.service.consul. 0   IN  A   192.168.1.207
web.service.consul. 0   IN  A   192.168.1.15

# この状態でmasterサーバをメンテモードに入れてみると以下のようにレコードから削除される
[root@master tmp]# consul maint -enable
Node maintenance is now enabled

[root@master tmp]# dig web.service.consul
web.service.consul. 0   IN  A   192.168.1.207

感想/これから

とりあえずしばらくはお家のサーバには全て適用してみようかなと思います。DNSの登録とかが自動でされるのはとても便利ですね〜。sd機能があるのでprometheusからも簡単に監視が導入できそうなのでそれにいずれ挑戦しようと思います。

おまけ

consul-tempateとconsul-alertsという関連サービスもあったりする。

github.com

github.com

ざっくりcousul-templateにも触れてみる

ハンズオン

# 監視対象テンプレートファイルを作成する
$ cat nginx.ctmpl

{{ key "master/test" }}

# データをconsulへ投入する
$ curl -X PUT http://localhost:8500/v1/kv/test -d "test_data3"

# この状態でconsul-templateを起動する。
# -templateは"templateファイル":コピー先のパス: "コピー後に実行したいコマンド"
$ ./consul-template -consul-addr localhost:8500 -template "./nginx.ctmpl:/etc/test.conf:pwd"

この状態でkeyを更新したりすると自動的にファイルが更新され指定したコマンドが実行される。pwdにしてるが運用ケースとかだとgraceful restartとかになるんだと思う。こりゃ便利。