・ntp_exporter.py
from flask import Flask, Response
import subprocess
import os
import threading
import time
app = Flask(__name__)
# 環境変数から NTP サーバ取得(なければデフォルト)
ntp_server = os.getenv("NTP_SERVER", "ntp.nict.jp")
offset_value = 0.0
interval_seconds = 60 # 取得間隔(秒)
def get_offset():
try:
result = subprocess.check_output(
["ntpdate", "-q", ntp_server],
stderr=subprocess.STDOUT
).decode()
print("[DEBUG] ntpdate raw output:", flush=True)
print(result, flush=True)
for line in result.splitlines():
# 例: "2025-07-30 12:22:41.249283 (+0000) -0.000071 +/- 0.001241 ..."
if line and line[0].isdigit():
parts = line.split()
offset = float(parts[3]) # offset は 4番目(インデックス3)
print(f"[INFO] Current offset: {offset}", flush=True)
return offset
except Exception as e:
print(f"[ERROR] Failed to get NTP offset: {e}", flush=True)
return 0.0
def update_offset_loop():
global offset_value
while True:
offset_value = get_offset()
time.sleep(interval_seconds)
@app.route("/metrics")
def metrics():
return Response(
f"# HELP ntp_offset_seconds Current NTP offset\n"
f"# TYPE ntp_offset_seconds gauge\n"
f"ntp_offset_seconds {offset_value}\n",
mimetype="text/plain"
)
if __name__ == "__main__":
print(f"[INFO] Starting NTP Exporter with NTP_SERVER={ntp_server}", flush=True)
thread = threading.Thread(target=update_offset_loop, daemon=True)
thread.start()
app.run(host="0.0.0.0", port=9100)
・Dockerfile
FROM python:3.9-slim
RUN apt-get update && apt-get install -y ntpdate && pip install flask && apt-get clean
COPY ntp_exporter.py /ntp_exporter.py
EXPOSE 9100
ENV NTP_SERVER=ntp.nict.jp
CMD ["python", "/ntp_exporter.py"]
・ntp-exporter-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ntp-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: ntp-exporter
template:
metadata:
labels:
app: ntp-exporter
spec:
containers:
- name: ntp-exporter
image: xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ntp-exporter:latest # ← 必要に応じて修正
imagePullPolicy: Always
ports:
- containerPort: 9100
name: metrics
env:
- name: NTP_SERVER
value: "ntp.nict.jp"
・ntp-exporter-service.yaml
apiVersion: v1
kind: Service
metadata:
name: ntp-exporter
namespace: monitoring
labels:
app: ntp-exporter
spec:
selector:
app: ntp-exporter
ports:
- name: metrics
port: 9100
targetPort: 9100
・ntp-exporter-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: ntp-exporter
namespace: monitoring
labels:
release: kube-prometheus-stack # ← kube-prometheus-stack ならこのラベルが必要
spec:
selector:
matchLabels:
app: ntp-exporter
endpoints:
- port: metrics
interval: 30s
namespaceSelector:
matchNames:
- monitoring
・README
# Docker イメージビルド&プッシュ
docker build -t xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ntp-exporter:latest .
docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ntp-exporter:latest
# Kubernetes へ適用
kubectl create ns monitoring
kubectl delete -f ntp-exporter-daemonset.yaml
kubectl apply -f ntp-exporter-daemonset.yaml
kubectl apply -f ntp-exporter-service.yaml
kubectl apply -f ntp-exporter-servicemonitor.yaml
kubectl get pod -n monitoring