HashiCorp Consulを活用してメンテナンス効率化
はじめに
三菱UFJインフォメーションテクノロジー株式会社の鵜飼健史と申します。
Zennでのテックブログは初投稿となります。
よろしくお願いいたします。
最近の分散系システムにおけるサービスディスカバリー製品について記事を書きました。
今回、プラットフォームに依存しない形で運用できる「HashiCorp Consul」を使った実際の運用例を紹介します。
本記事の趣旨
- HashiCorp ConsulとDNSを組み合わせてサービスディスカバリとして利用できる
- メンテナンス作業はHashiCorp Consulを活用して一括コマンド投入
- EOS対応もHashiCorp Consulを使えば無停止で可能なものもある
利用したバージョンなど
- HashiCorp Consul 1.20.2
- RedHat Enterprise Linux 9.1
サービスメッシュ、サービスディスカバリとは
サービスメッシュとは「アプリケーション内のサービス間通信を管理するための仕組み」です。
サービスディスカバリーは「アプリケーション内のサービスの位置情報を見つける仕組み」であり、サービスメッシュの一部となります。
マイクロサービスの考え方が浸透していくに従って「アプリケーション内でのサービス」の構造が非常に複雑になっています。
2010年くらいまではAPサーバとDBサーバが決まった場所に配置されていることが多かったのですが、最近ではAPの中だけでもAPIやWeb層が分割されたり、ドメインごとにサーバ自体も分割されたりしています。
サービスメッシュの例
そうすると、それぞれのサービスがどのようにして通信相手となるサービスを見つけるか、といったサービスディスカバリに関して運用管理の負荷が上がることが課題になります。
それを解決するための仕組みとして、サービスメッシュやサービスディスカバリの製品があります。
HashiCorp Consulとは
本記事で紹介するHashiCorp Consul(以下、Consul)は、HashiCorp社が主に開発するOSSのサービスディスカバリ、サービスメッシュ製品となります。
Consulの特徴としては以下があげられます。
- クラウドや基盤に依存せず、マルチプラットフォームで稼働
- 動的なロードバランスや障害時の切り替えが可能
- Observabilityの仕組みとも連携でき、メトリクスを取得可能
Consulの基本構成
Consulは3台以上のserver
と配下に属する任意の台数のclient
から構成されます。
client
は管理対象となるサーバに導入され、そのサーバでどのようなサービスが稼働しているかを管理してserver
に報告します。
server
はclient
が保持ししているサービス情報を収集し、client
からの問い合わせに回答します。
また、高可用性担保のため3台以上のサーバで稼働させることで、生存確認や管理情報の同期を行います。
構成図
Consulの導入
Server
パッケージをインストールします。
$ dnf install -y consul
設定ファイルを以下の通り書き換えます。
{
"datacenter": "consul-sample",
"data_dir": "/opt/consul",
"client_addr": "0.0.0.0",
"bind_addr": "10.10.10.1",
"start_join": ["10.10.10.1", "10.10.10.2", "10.10.10.3"],
"enable_script_checks": true,
"domain": "mesh.sample.com",
"alt_domain": "consul",
"disable_remote_exec": false,
"connect": {
"enabled": true
},
"ports": {
"https": 8501,
"grpc": 8502,
"grpc_tls": 8503
},
"disable_update_check": true,
"enable_central_service_config": true,
"tls": {
"defaults": {
"cert_file": "/etc/pki/consul/tls.crt",
"key_file": "/etc/pki/consul/tls.key",
"tls_cipher_suites": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
}
},
"server": true
}
datacenter
はConsulが管理する単位を定義する設定値です。
管理単位で任意の文字を設定します。
"datacenter": "consul-sample",
data_dir
はConsulがデータの永続化に利用するKey-Valueストアの配置場所を指定します。
"data_dir": "/opt/consul",
client_addr
はConsulとして通信をする送信元IPアドレスを記載します。
ここでは特に制御しないため、0.0.0.0
を設定します。
"client_addr": "0.0.0.0",
bind_addr
はConsulとして通信をする受信IPアドレスを記載します。
ここでは自分自身のIPアドレスを設定します。
"bind_addr": "10.10.10.1",
start_join
はConsul起動時のserver
のIPアドレスをリストで指定します。
3台以上の設定が必須になります。
"start_join": ["10.10.10.1", "10.10.10.2", "10.10.10.3"],
enable_script_checks
はスクリプトを使ってサービス状態監視を行う際に設定します。
"enable_script_checks": true,
domain
はConsulが管理するサービス群の親ドメインをしています。
"domain": "mesh.sample.com",
alt_domain
はドメイン名の別名を登録します。
こちらのドメインでもDNSを引けるようになります。
"alt_domain": "consul",
disable_remote_exec
はリモートでのコマンド実行を禁止する設定です。
今回こちらを利用するのでfalseで設定します。
"disable_remote_exec": false,
connect
はサービスメッシュの定義を設定します。
今回はサービスディスカバリのみのため、以下のみとします。
"connect": {
"enabled": true
},
ports
にて各通信のポートを指定します。
デフォルト設定でかまいません。
"ports": {
"https": 8501,
"grpc": 8502,
"grpc_tls": 8503
},
tls
にて証明書や鍵の場所、CipherSuitesなどを指定します。
"tls": {
"defaults": {
"cert_file": "/etc/pki/consul/tls.crt",
"key_file": "/etc/pki/consul/tls.key",
"tls_cipher_suites": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
}
},
server
にてこのNodeがserver
かどうかを判定します。
この設定ではserver
のためtrueを指定します。
"server": true
設定出来たら、Consulを起動します。ついでに自動起動設定もしておきましょう。
$ systemctl start consul
$ systemctl enable consul
これでserver
は完成です。これを3サーバ分実施します。
Client
続いてclient
も同様にインストールし、設定ファイルを以下として起動します。
{
"datacenter": "consul-sample",
"data_dir": "/opt/consul",
"client_addr": "0.0.0.0",
"bind_addr": "10.10.10.11",
"start_join": ["10.10.10.1", "10.10.10.2", "10.10.10.3"],
"enable_script_checks": true,
"domain": "mesh.sample.com",
"alt_domain": "consul",
"disable_remote_exec": false,
"connect": {
"enabled": true
},
"ports": {
"https": 8501,
"grpc": 8502,
"grpc_tls": 8503
},
"server": false
}
client
のため、以下の設定がserver
との差分となります。
"server": false
これで準備は完了しました。
稼働確認
ちゃんとserver
とclient
が稼働しているか確認するコマンドがあります。
$ consul members
Node Address Status Type Build Protocol DC Partition Segment
server1 10.10.10.1:8301 alive server 1.20.2 2 consul-sample default <all>
server2 10.10.10.2:8301 alive server 1.20.2 2 consul-sample default <all>
server3 10.10.10.3:8301 alive server 1.20.2 2 consul-sample default <all>
client1 10.10.10.11:8301 alive client 1.20.2 2 consul-sample default <default>
client2 10.10.10.12:8301 alive client 1.20.2 2 consul-sample default <default>
client3 10.10.10.13:8301 alive client 1.20.2 2 consul-sample default <default>
サーバのリストが出てくれば成功です。
どれがserver
かclient
かも一目でわかります。
Consulを使ったサービスディスカバリ
サービス設定
サービスをclient
に登録する際は/etc/consul.d/
フォルダに任意の設定ファイルを新規作成します。
ここでは一例としてNginxのサービスを登録する例となります。
{
"service": {
"address": "10.10.10.11",
"enable_tag_override": false,
"id": "nginx",
"name": "nginx",
"port": 443
}
}
サービス名やIPアドレス、ポートなどを定義します。
ファイルを追加した場合は以下コマンドで設定を反映します。
$ consul reload
サービスアクセス
ConsulにはDNSの機能もあるため、digコマンドで8600ポートに対して確認すると以下のように応答してくれます。
$ dig -p 8600 nginx.serivce.consul
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el8 <<>> nginx.service.consul
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42302
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx.service.consul. IN A
;; ANSWER SECTION:
nginx.service.consul. 0 IN A 10.10.10.11
;; Query time: 5 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 木 2月 13 10:20:10 JST 2025
;; MSG SIZE rcvd: 70
これは同じdatacenter内のどのclient
に問い合わせても同じ答えが返ってくるようになります。
また、同じサービス名のclient
が2台以上ある場合は、DNSのリストに2台とも含まれます。
よって、Webサーバ製品とConsulを連携させることで先ほど定義したサービスファイルで動的にサービスの増強や追加、切り替えができるようになります。
また、トラブルがあった場合に自動切り離しをしたい、ということであればサービスファイルにcheckの定義を追加して任意の確認コマンドを登録できます。
メンテナンスでの一括コマンド投入
ConsulはCLIも用意されており、consul exec
機能を使うことで配下サーバに対してまとめてコマンドを投入できます。
これを使うことで、全サーバの状態確認や、設定値の横断確認、セキュリティアップデートの適用などが一括でできるようになります。
例えば、javaバージョン確認がしたい場合は以下コマンドを実行します。
$ consul exec "java --version"
==> server1: finished with exit code 0
server1: openjdk 11.0.16 2022-07-19 LTS
server1: OpenJDK Runtime Environment (Red_Hat-11.0.16.0.8-1.el8_6) (build 11.0.16+8-LTS)
server1: OpenJDK 64-Bit Server VM (Red_Hat-11.0.16.0.8-1.el8_6) (build 11.0.16+8-LTS, mixed mode, sharing)
==> server2: finished with exit code 127
server2: /bin/bash: java: コマンドが見つかりません
==> server3: finished with exit code 0
server3: openjdk 17.0.9 2023-10-17 LTS
server3: OpenJDK Runtime Environment (Red_Hat-17.0.9.0.9-1) (build 17.0.9+9-LTS)
server3: OpenJDK 64-Bit Server VM (Red_Hat-17.0.9.0.9-1) (build 17.0.9+9-LTS, mixed mode, sharing)
上記結果からそれぞれserver1はJava11、server2はインストールされておらず、server3はJava17であることが分かります。
運用をしていると「全サーバには投入したくないがある程度まとめてやりたい」という要望も出てくると思います。
弊社のシステムでは以下のノードタグをつけて運用しています。
...
"node_meta": {
"env": "dev",
"os": "Red Hat Enterprise Linux release 9.1 (Plow)",
"lang": "ja_JP.UTF-8",
"parity": "odd"
},
...
- 提供用サービスかどうか
- OSバージョン
- デフォルト言語設定
- サーバ号機の偶奇
node_mataを使って順次偶数号機→奇数号機と半分ずつバージョンアップしたい場合は以下のコマンドをそれぞれタイミングをずらして実行します。
$ consul exec -node="$(consul catalog nodes -node-meta="parity=even" | cut -d ' ' -f 1 | sed '1d' | head -c -1 | tr '\n' '|')" "dnf upgrade -y nginx
$ consul exec -node="$(consul catalog nodes -node-meta="parity=odd" | cut -d ' ' -f 1 | sed '1d' | head -c -1 | tr '\n' '|')" "dnf upgrade -y nginx
他にもsshdが落ちてしまって、動かなくなったサーバを復旧するためのコマンドを投入したり、自動構築スクリプトを配布して一括インストールをしたりなど、メンテナンスで活躍します。
Consulを利用したEOS対応
RHEL8にて運用しているサービスをRHEL9にバージョンアップするといったEOS対応が数年に一度発生します。
従来のやり方だと、大規模な案件を計画して、今のサーバ構成をそのままRHEL9で作り直してテストを実施、サービス停止時間を設けてデータ移行等を行った上で切り替えという対応がほとんどでした。
これをConsulを使ってサービス単位でEOSができるようになります。
例えば、Nginx、JakartaEE Server、Databaseの3つで構成されるアプリケーションがあった場合、
Nginxのみや、JakartaEE Serverのみ、といった単位でEOS対応を進めることが可能です。
実施イメージ
RHEL9サーバを構築して、そこにConsulをインストールします。
Nginxもそこにインストールして、稼働に問題ないかテストを行います。
問題なければ、サービスファイルを作成・登録するとRHEL8とRHEL9どちらにも通信が来るようになります。
もし問題があれば以下コマンドですぐにメンテナンスモードとして切り離すこともできます。
$ consul maint -service nginx -enable
メンテナンスモードを有効化するという意味なので、enable
にするとサービスとしては無効になります。
よく間違えるので、注意が必要です。
両現用で稼働させておいて、RHEL8とRHEL9の稼働に遜色がなければRHEL8側をメンテナンスモードにしましょう。
しばらく期間をおいて問題なければRHEL8サーバは廃止して対応完了になります。
サービスごとの自動テストが組み込まれていれば、EOS対応も非常に簡単にできるようになります。
まとめ
- HashiCorp Consulを使ってサービスファイルを設定することで簡単にサービスディスカバリを実現できます
- 動的に設定ファイルを切り替えたり、CLIで制御したりして運用が簡単になります
- メンテナンス作業やEOS対応にも使えます
これら以外にもKubernetesとの連携など、Consulには様々な機能があり、弊社でもまだまだ活用しきれていないため、引き続き運用管理の改善に努めようと思います。
Discussion