この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
おはようございます、加藤です。Consulって名前は聞くけど、なんとなくしか出来る事を知らないなーと思っていました。 Consulのチュートリアルを見つけたので、実際に動かしながらブログにまとめていきます。
- Consul by HashiCorp
- Consulのメインページ
- Consul Curriculum - HashiCorp Learn
- Consulのチュートリアル
最初に書いた通り、Consulについて理解できていないので、Consulって何?的な説明は行いません。チュートリアルをおえて理解できたら別途書こうと思います。
やってみた
Consulのインストール
Consulを試す為にはインストールする必要がありますが、Dockerでいける気がしたのでDockerでやってみました。
イメージをPullして作業ディレクトリを作成します。
host_os
docker pull consul
mkdir -p ~/tmp/consul/getting-started && cd ~/tmp/consul/getting-started
コンテナを立ち上げconsul
コマンドが使用できることを確認します。バージョンはv1.4.4でした。
host_os
docker run --rm -it consul sh
container
consul version
# Consul v1.4.4
# Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
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
# 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
# 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
exit
Consulエージェントの実行
下記のコマンドでConsulエージェントを開発モードで起動したいです。
sample
consul agent -dev
Dockerで動かすので下記のコマンドで実行します。
host_os
docker run --rm --name consul_getting_started consul agent -dev
フォアグラウンドで起動しているので、もう1つターミナルを立ち上げてコンテナ内に入ります。
host_os
docker exec -it consul_getting_started sh
以降、先に立ち上げたターミナルをConsulを実行している方、後に実行した方をshを実行している方と呼称します。
shを実行している方で、プロセスを確認すると-data-dir
と-config-dir
オプションが追加されていますが検証に支障はなさそうなので、そのまま続けます。
container_sh
ps | grep consul
6 consul 0:03 consul agent -data-dir=/consul/data -config-dir=/consul/config -dev
30 root 0:00 grep consul
下記でdocker-entrypoint.sh
を確認するとわかりますが、この2つのオプションが追加されるのは意図した動作(このコンテナの仕様)です。
docker-consul/docker-entrypoint.sh at master · hashicorp/docker-consul
今、Consulに参加しているのは起動しているコンテナ1つだけのはずです。shを実行している方で、下記のコマンドを実行して確認してみましょう。
container_sh
# members Lists the members of a Consul cluster
consul members
# Node Address Status Type Build Protocol DC Segment
# 9d0e04963a24 127.0.0.1:8301 alive server 1.4.4 2 dc1 <all>
確認ができました。members
はConsul clusterに参加しているメンバーを列挙するオプションです。
Consulを実行している方を確認すると2019/03/25 15:25:21 [DEBUG] http: Request GET /v1/agent/members?segment=_all (646.265µs) from=127.0.0.1:53448
とリクエストが記録されています。
members
で確認できる内容はGossip Protocolというもので実装されているらしく、結果整合性です。
強整合性を求める場合はHTTP APIを使用してリクエストを行います。こちらでもコンテナ1つだけが参加している事を確認できました。
container_sh
curl localhost:8500/v1/catalog/nodes
[
{
"ID": "1d20d85f-c1f1-dece-4f30-f5e62fad9277",
"Node": "9d0e04963a24",
"Address": "127.0.0.1",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "127.0.0.1",
"wan": "127.0.0.1"
},
"Meta": {
"consul-network-segment": ""
},
"CreateIndex": 9,
"ModifyIndex": 10
}
]
DNSインターフェイスでもリクエストが可能です。${NODE}.node.consul
を名前解決してみます。
container_sh
# digを実行するために、bind-toolsをインストール
# NODEを環境変数に格納する為にjqをインストール
apk add bind-tools jq
# NODEを環境変数に格納
NODE=$(curl -s localhost:8500/v1/catalog/nodes | jq -r '.[].Node')
dig @127.0.0.1 -p 8600 ${NODE}.node.consul
# ;; QUESTION SECTION:
# ;9d0e04963a24.node.consul. IN A
#
# ;; ANSWER SECTION:
# 9d0e04963a24.node.consul. 0 IN A 127.0.0.1
#
# ;; ADDITIONAL SECTION:
# 9d0e04963a24.node.consul. 0 IN TXT "consul-network-segment="
#
# ;; Query time: 1 msec
# ;; SERVER: 127.0.0.1#8600(127.0.0.1)
# ;; WHEN: Tue Mar 26 07:58:19 UTC 2019
# ;; MSG SIZE rcvd: 105
127.0.0.1
で名前解決が正常に行われました。
コンテナを終了します。
Consulを実行している方でCtrl + C
で終了します。shを実行している方も、コンテナが終了し端末のターミナルに戻ります。
サービスを登録する
サービスは定義ファイルを作成する or HTTP APIにリクエストする事で登録ができます。 定義ファイルを作成して登録します。
サービス定義を作成します。webという名前でタグはrails、ポートは80番の定義です。
web.json
{
"service": {
"name": "web",
"tags": [
"rails"
],
"port": 80
}
}
host_os
mkdir ./consul.d
echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' \
> ./consul.d/web.json
このコンテナは/consul/config
からコンフィグを読み込む様にオプションが設定されているので、そこに作成したサービス定義をマウントします。
また、今回はバックグラウンドでコンテナを起動しています(-d
オプション)。コンテナを起動し、コンテナ内でshを起動して中に入ります。
host_os
docker run --rm --name consul_getting_started -v $(pwd)/consul.d/:/consul/config -d consul
docker exec -it consul_getting_started sh
DNSでリクエストしてみます。
container
apk add bind-tools jq
dig @127.0.0.1 -p 8600 web.service.consul
# ;; QUESTION SECTION:
# ;web.service.consul. IN A
#
# ;; ANSWER SECTION:
# web.service.consul. 0 IN A 127.0.0.1
#
# ;; ADDITIONAL SECTION:
# web.service.consul. 0 IN TXT "consul-network-segment="
#
# ;; Query time: 2 msec
# ;; SERVER: 127.0.0.1#8600(127.0.0.1)
# ;; WHEN: Tue Mar 26 09:24:18 UTC 2019
# ;; MSG SIZE rcvd: 99
dig @127.0.0.1 -p 8600 web.service.consul SRV
# ;; QUESTION SECTION:
# ;web.service.consul. IN SRV
#
# ;; ANSWER SECTION:
# web.service.consul. 0 IN SRV 1 1 80 53304c043d9a.node.dc1.consul.
#
# ;; ADDITIONAL SECTION:
# 53304c043d9a.node.dc1.consul. 0 IN A 127.0.0.1
# 53304c043d9a.node.dc1.consul. 0 IN TXT "consul-network-segment="
#
# ;; Query time: 0 msec
# ;; SERVER: 127.0.0.1#8600(127.0.0.1)
# ;; WHEN: Tue Mar 26 09:25:15 UTC 2019
# ;; MSG SIZE rcvd: 147
Aレコードで問い合わせると、サービスのIPアドレスが返ってきました。
SRVレコードで問い合わせると、サービスが80番ポートで53304c043d9a.node.dc1.consul
の上で動作している事が返ってきました。
タグで問い合わせを行います。今回はrailsタグが設定されているサービスが1つしか無いため、返ってきたIPアドレスは1つですが、タグが付いている全てのサービスのIPアドレスが返ってきます。
container
dig @127.0.0.1 -p 8600 rails.web.service.consul
# ;; QUESTION SECTION:
# ;rails.web.service.consul. IN A
#
# ;; ANSWER SECTION:
# rails.web.service.consul. 0 IN A 127.0.0.1
#
# ;; ADDITIONAL SECTION:
# rails.web.service.consul. 0 IN TXT "consul-network-segment="
#
# ;; Query time: 1 msec
# ;; SERVER: 127.0.0.1#8600(127.0.0.1)
# ;; WHEN: Tue Mar 26 09:33:49 UTC 2019
# ;; MSG SIZE rcvd: 105
HTTP APIでリクエストします。このAPIは Catalog Endpoint と言い、指定したサービスをホストしている全てのノード情報を返します(ヘルスチェックに失敗したノードも返す)。 Catalog - HTTP API - Consul by HashiCorp
container
curl http://localhost:8500/v1/catalog/service/web
# [
# {
# "ID": "2e1d9862-aef6-7652-2205-94301a804360",
# "Node": "53304c043d9a",
# "Address": "127.0.0.1",
# "Datacenter": "dc1",
# "TaggedAddresses": {
# "lan": "127.0.0.1",
# "wan": "127.0.0.1"
# },
# "NodeMeta": {
# "consul-network-segment": ""
# },
# "ServiceKind": "",
# "ServiceID": "web",
# "ServiceName": "web",
# "ServiceTags": [
# "rails"
# ],
# "ServiceAddress": "",
# "ServiceWeights": {
# "Passing": 1,
# "Warning": 1
# },
# "ServiceMeta": {},
# "ServicePort": 80,
# "ServiceEnableTagOverride": false,
# "ServiceProxyDestination": "",
# "ServiceProxy": {},
# "ServiceConnect": {},
# "CreateIndex": 10,
# "ModifyIndex": 10
# }
# ]
ヘルスチェックに成功しているサービスのみ探すには Health Endpoint を使用します。 Health - HTTP API - Consul by HashiCorp
container
curl 'http://localhost:8500/v1/health/service/web?passing'
# [
# {
# "Node": {
# "ID": "2e1d9862-aef6-7652-2205-94301a804360",
# "Node": "53304c043d9a",
# "Address": "127.0.0.1",
# "Datacenter": "dc1",
# "TaggedAddresses": {
# "lan": "127.0.0.1",
# "wan": "127.0.0.1"
# },
# "Meta": {
# "consul-network-segment": ""
# },
# "CreateIndex": 9,
# "ModifyIndex": 10
# },
# "Service": {
# "ID": "web",
# "Service": "web",
# "Tags": [
# "rails"
# ],
# "Address": "",
# "Meta": null,
# "Port": 80,
# "Weights": {
# "Passing": 1,
# "Warning": 1
# },
# "EnableTagOverride": false,
# "ProxyDestination": "",
# "Proxy": {},
# "Connect": {},
# "CreateIndex": 10,
# "ModifyIndex": 10
# },
# "Checks": [
# {
# "Node": "53304c043d9a",
# "CheckID": "serfHealth",
# "Name": "Serf Health Status",
# "Status": "passing",
# "Notes": "",
# "Output": "Agent alive and reachable",
# "ServiceID": "",
# "ServiceName": "",
# "ServiceTags": [],
# "Definition": {},
# "CreateIndex": 9,
# "ModifyIndex": 9
# }
# ]
# }
# ]
サービスを更新する
サービス定義はAgent起動後に更新されても反映されません。反映するにはSIGHUP
を送信するか、Agentを再起動する必要があります。
サービス定義を更新して、SIGHUP
送信前後でレスポンスを比較して見ました。
container
echo '{"service": {"name": "web", "tags": ["rails","demo"], "port": 80}}' > /consul/config/web.json
dig +short @127.0.0.1 -p 8600 demo.web.service.consul
kill -HUP $(pgrep -f "consul agent")
dig +short @127.0.0.1 -p 8600 demo.web.service.consul
# 127.0.0.1
あとがき
Consulを起動してサービス登録する所まで行えました。まだ、理解したには程遠いので引き続きチュートリアルを進めて行きまーす。