午前2時、スマートフォンが震えた——Grafanaからのアラートが、3台のサーバーのログタイムスタンプが最大5分もずれていることを知らせていた。TLS証明書がエラーを吐き始め、cronjobは誤った時刻に実行され、binlogタイムスタンプのズレでデータベースレプリカのラグが急増した。すべての原因はタイム同期の障害だった。
これは15台のサーバーからなるクラスターを管理していた際に実際に経験した出来事だ。その教訓として学んだのは、NTPは「一度設定して忘れる」ものではなく、正しく設定し継続的に監視する必要があるということだ。
なぜタイム同期はそれほど重要なのか?
NTPをオプション扱いにするsysadminは少なくない——「サーバーが動いていれば問題ない」というわけだ。しかし、クロックドリフトは予測しにくい形で静かにシステムを蝕んでいく:
- ログの不一致:インシデントのトレース中、サーバーAのログがサーバーBより3分先行していて、フローを再現できない
- TLS証明書エラー:TLSはハンドシェイク時に時刻を検証する——5分以上のズレがあると即座に拒否される
- 分散システムの不安定化:Kafka、Cassandra、etcdはいずれも合意形成と順序付けに時刻を利用している
- 認証の失敗:KerberosトークンやJWT、OAuthはいずれも有効な時間ウィンドウが短い
- cronジョブの誤実行:サーバーの時刻がタイムゾーンからずれているため、バックアップがピーク時間帯に実行される
sysadminになりたての頃、2つのマイクロサービス間での認証失敗のせいで丸半日潰したことがある。ログを何度見返してもおかしなところが見当たらない。結局、ソースサーバーとデスティネーションサーバーの時刻がちょうど8分ずれていてJWTトークンが拒否されていたのが原因だった。それ以来、新しいサーバーを立ち上げたら最初にNTPを確認するのが習慣になった。
chrony vs ntpd — どちらを使うべきか?
RHEL 7、CentOS 7、Ubuntu 16.04以降では、chronyが旧来のntpdに代わるデフォルトの選択肢となっている。実際のメリットは以下の通りだ:
- 起動後の同期が速い——通常数秒で完了するのに対し、ntpdは数分かかることがある
- 仮想化環境での動作が優れている——VMはベアメタルよりクロックドリフトが発生しやすい
- フットプリントが小さい——プロセスのメモリ使用量は5MB未満で、512MB RAMのVPSでも適している
ntpdも引き続き使用できる。ただし、chronyはRHEL 7とUbuntu 16.04以降のデフォルトであるため、本番環境では日常的に目にすることになる。
chronyのインストール
Ubuntu/Debianの場合
# インストール
sudo apt update && sudo apt install -y chrony
# 有効化して起動
sudo systemctl enable --now chronyd
# ステータスを確認
sudo systemctl status chronyd
CentOS/RHEL/Rocky Linuxの場合
# インストール(RHEL 8+はdnf、CentOS 7はyum)
sudo dnf install -y chrony
# 有効化して起動
sudo systemctl enable --now chronyd
始める前の注意点として、古いシステムによってはntpdとchronydが同時に動いている場合がある——この2つのデーモンは競合し、予測不能な結果をもたらす。事前にクリーンアップしておこう:
# ntpdが動作しているか確認
sudo systemctl status ntpd
# 動いている場合は停止して無効化
sudo systemctl stop ntpd
sudo systemctl disable ntpd
sudo systemctl mask ntpd # 自動起動しないようにマスク
詳細な設定
メインの設定ファイルは/etc/chrony.conf(Ubuntu: /etc/chrony/chrony.conf)だ。
NTPクライアントの基本設定
# NTPサーバー——冗長性のため単一サーバーではなくプールを使用
pool 0.pool.ntp.org iburst
pool 1.pool.ntp.org iburst
pool 2.pool.ntp.org iburst
pool 3.pool.ntp.org iburst
# クラウド上で動作している場合、プロバイダーのNTPを優先使用(レイテンシが低い)
# AWS: server 169.254.169.123 prefer iburst
# GCP: server metadata.google.internal prefer iburst
# ドリフトファイル——再起動後に素早く同期できるようクロックドリフト情報を保存
driftfile /var/lib/chrony/drift
# 1秒以上ずれている場合はステップ補正を許可(起動後の最初の3回のみ)
makestep 1.0 3
# ハードウェアクロック(RTC)と同期
rtcsync
# ログディレクトリ
logdir /var/log/chrony
クラスター全体向けの内部NTPサーバーの設定
複数サーバーのクラスターを管理している場合、推奨するアーキテクチャは次の通りだ:
- 1〜2台のサーバーがパブリックNTP(インターネット)と同期
- 残りのすべてのサーバーは内部NTPサーバーと同期
この構成により外向きのトラフィックを削減し、パブリックネットワークのレイテンシへの依存を避けられる。NTPマスターサーバーでは、/etc/chrony.confの末尾に以下を追加する:
# このサブネット内のクライアントが時刻同期することを許可
allow 192.168.1.0/24
allow 10.0.0.0/8
# インターネット接続が切れた場合でも、ローカルクロックを使ってクライアントに時刻を提供
local stratum 10
クライアントサーバーでは、パブリックプールを内部NTPアドレスに置き換える:
# pool.ntp.orgの行をコメントアウトまたは削除
# pool 0.pool.ntp.org iburst
# 内部NTPサーバーのみと同期
server 192.168.1.10 iburst prefer
server 192.168.1.11 iburst # バックアップ
makestep 1.0 3
driftfile /var/lib/chrony/drift
rtcsync
設定を変更したら、サービスを再起動する:
sudo systemctl restart chronyd
ファイアウォール——最も忘れがちな設定
NTPはUDPポート123を使用する。内部NTPサーバーをセットアップする場合、クライアントからの接続のためにファイアウォールを開放する:
# UbuntuのUFW
sudo ufw allow 123/udp
# CentOS/RHELのfirewalld
sudo firewall-cmd --permanent --add-service=ntp
sudo firewall-cmd --reload
確認と監視
インストール直後の同期状態の確認
# NTPソースとその状態を一覧表示
chronyc sources -v
出力例:
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* ntp1.example.com 2 6 377 43 +12us[ +34us] +/- 456us
^+ ntp2.example.com 2 6 377 44 -8us[ +12us] +/- 234us
行頭の記号の意味:
*= 使用中のソース(最良)+= 良好なソース、組み合わせて使用中?= 到達不能——即座にデバッグが必要x= 時刻が誤っている可能性——このソースは無視
# トラッキング情報——現在のオフセットとストラタムを確認
chronyc tracking
Reference ID : C0A80101 (192.168.1.1)
Stratum : 3
System time : 0.000012345 seconds fast of NTP time
Last offset : +0.000008234 seconds
RMS offset : 0.000015678 seconds
Frequency : 12.345 ppm fast
Leap status : Normal
注目すべき数値はSystem time(オフセット)だ。100ms未満であれば許容範囲、10ms未満であれば良好だ。etcdやCassandraのような分散データベースを運用している場合は1ms未満が必要——これは推奨ではなく要件だ。
オフセット確認とアラートのスクリプト
このシンプルなスクリプトをcronで使ったり、Nagios/Zabbixに組み込んだりしている:
#!/bin/bash
# /usr/local/bin/check-ntp-offset.sh
THRESHOLD=0.5 # 秒——オフセットが500msを超えた場合にアラート
offset=$(chronyc tracking | grep "System time" | awk '{print $4}')
offset_abs=$(echo "$offset" | tr -d '-')
if (( $(echo "$offset_abs > $THRESHOLD" | bc -l) )); then
echo "CRITICAL: NTPオフセット ${offset}s が閾値 ${THRESHOLD}s を超えています"
exit 2
else
echo "OK: NTPオフセットは ${offset}s です"
exit 0
fi
chmod +x /usr/local/bin/check-ntp-offset.sh
/usr/local/bin/check-ntp-offset.sh
chronyが同期できない場合のデバッグ
chronyc sourcesに?ばかり表示されるのは、障害の最も明確なサインだ。ケースの90%を占める2つの原因は、ファイアウォールがUDP 123をブロックしているか、DNSが解決できていないかだ。順番に確認しよう:
# ログをリアルタイムで確認
sudo journalctl -u chronyd -f
# NTPサーバーへの到達確認
ntpdate -q 0.pool.ntp.org 2>&1 | head -5
# DNSの確認
nslookup 0.pool.ntp.org
# 即座に強制同期(大きなオフセットを素早く修正したい場合に使用)
sudo chronyc makestep
新規サーバーへのNTPセットアップチェックリスト
- chronyをインストールし、ntpdが動作していれば確認して停止する
- 適切なNTPプールを設定する(クラウド上にある場合はクラウドプロバイダーのNTPを優先)
- クラスターがある場合:1〜2台の内部NTPサーバーをセットアップし、残りのサーバーはそこから同期する
- 内部NTPサーバーのファイアウォールでUDP 123を開放する
chronyc sources -vとchronyc trackingで確認する- オフセットが閾値を超えた際にアラートを出す監視を追加する
次にクラスターへ新しいサーバーをオンボードする際は、最初からNTPを確認しておこう——かつての自分のように、午前2時になってから発見する羽目にならないように。

