新しい中華GPSモジュールとChronyで作るNTPサーバ (中編)

前編では怪しい中華GPSモジュールを買っちゃったこととArmbian最新ソースからビルドしたPPS対応イメージについて書いた。一応今回が本題の内容になる。

構成

NMEA → gpsd → Chrony
1PPS → Chrony

Armbian(Debian, Ubuntu)の新しいバージョンではChronyは最初からシステムに入っている。オプション等を指定して自分でビルドする必要もなしでそのまま使える。

Chronyはネットワーク上の時刻ソースからの同期はとても簡単だが、ntpdと違ってNMEAなどのリファレンスクロックドライバは揃っていないようで、gpsd等の補助を必要とするみたい。gpsd以外で小型で単体のNMEA用ドライバのようなものが無いかと思ってググったけど見つけられなかった。
1PPSはChronyだけでもいけるっぽい。ググったところ、他の人はNMEAと1PPSの両方をgpsdに読ませて、Chronyではその2つをgpsdから貰うような設定が多いようだが、「がとらぼ」ではNMEAだけをgpsdに読ませてChronyに渡し、1PPSは直接Chronyに読ませることにする。どちらが精度が高いのかは不明。
ntpdではNMEAも1PPSもntpdで直接読める(それでもgpsdでNMEAを読ませる設定にしてる人が多い)ので「がとらぼ」で1PPSを使ったNTPサーバではgpsdなしで両方ntpdに読ませる設定でやっていた。余計なものは極力使いたくないのでgpsdはなしにしたいところだが、現在のChronyではできないっぽい(知らないだけ?)ので気に入らないが諦めてgpsdを使うことにする。

gpsdの設定

gpsdはArmbianのシステムには入っていないが、パッケージは用意されているのでそれを使うことにする。
$ sudo apt update                       #パッケージ情報を最新に更新
$ sudo apt install gpsd gpsd-clients    #パッケージインストール

gpsd-clientsは衛星の捕捉状況を表示したい等gpsd-clientsに入っているツールをどうしても使いたいということでなければ特には不要。

この記事では接続したGPSモジュールのシリアルポートが/dev/ttyS1とする。
シリアルポート名は使っているPC, シングルボードコンピュータ, OSで違うので実際にNMEAを受信できているポートを指定する。/devにあるttyで始まるデバイスで sudo cat /dev/ttyS0 などでNMEAセンテンスがズラズラ表示され続けるポートを見つければ良い。(Linuxのシリアルポート名にはttyS*みたいに大文字のSが付くみたい)

設定ファイルはArmbianのパッケージでインストールすると /etc/default/gpsd になるよう。この設定ファイルのpathは/lib/systemd/system/gpsd.serviceで指定されているので気に入らなければ変更。(要サービスの再有効可)

/etc/default/gpsd
1
2
3
4
5
START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/ttyS1"
GPS_BAUD=115200
GPSD_OPTIONS="-n"

この内、4行目は要注意。次回の記事で予定のGPSモジュールの設定変更を実施しなければ多くの安価なGPSモジュールは初期値が4800/9600bps程度なので115200bpsを指定するとおそらく通信できなくなる(gpsd側が通信できないだけでGPSモジュールやPC/シングルボードコンピュータが壊れるわけではない)。GPSモジュールの通信速度の初期値を指定するか4行目自体を無しにする方が良い。

1PPSをgpsdで受けたいのであれば2行目は DEVICES="/dev/ttyS1 /dev/pps0" のような指定になる。

gpsdサービスを起動する。
$ sudo systemctl enable gpsd.socket  (有効化されていなければ実行,おそらく不要)
$ sudo systemctl enable gpsd.service  (次が実行できなければ実行,おそらく不要)
$ sudo systemctl start gpsd.service
gpsdサービスを動かすにはgpsd.serviceとgpsd.socketの2つが要る。メインのサービスはgpsd.serviceだが元から起動・停止したいならgpsd.socket。 すでにサービスが動いているなら「start」の代わりに「restart」。
gpsdの起動ステータスを確認する。
$ sudo systemctl status gpsd.socket
● gpsd.socket - GPS (Global Positioning System) Daemon Sockets
   Loaded: loaded (/lib/systemd/system/gpsd.socket; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-07-09 19:29:38 JST; 15h ago
   Listen: /var/run/gpsd.sock (Stream)
           [::1]:2947 (Stream)
           127.0.0.1:2947 (Stream)
    Tasks: 0 (limit: 851)
   Memory: 44.0K
   CGroup: /system.slice/gpsd.socket

Warning: Journal has been rotated since unit was started.

これはgpsd.serviceではダメでgpsd.socketを指定する。問題が発生していればこの後にエラー等が表示される筈。

gpsdでのGPS衛星の補足情報を確認したいならgpsmoncgps -sを使う。(要gpsd-clientsパッケージ)。まぁ、見る必要は無いんだけど。

Chronyの設定

最新のArmbian (Debian, Ubuntu)ではChronyはシステムに入っているし逆にntpdは入っていないのでChronyを設定するだけ。他のディストリビューションや古いArmbian(Debian, Ubuntu)では標準がntpdが動いていてChronyが入っていないのでChronyをインストールしてntpdを停める(アンインストールする)必要があるかもしれない。Chronyとntpdはコンフリクトするので同時使用はできない。

Chronyサービスの制御ファイルは/lib/system/system/chrony.serviceだが、/etc/systemd/system/chronyd.serviceからシンボリックリンクになっているのでサービス名としてはchrony.serviceとchronyd.serviceの2つがあることになる。実体は1つ。ややこしいのでこういうのはやめて欲しい。

Chronyの設定ファイルはパッケージでインストールすると /etc/chrony/chrony.conf になる。

/etc/chrony/chrony.conf (設定例)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
server ntp1.v6.mfeed.ad.jp prefer
server ntp2.v6.mfeed.ad.jp
server ntp3.v6.mfeed.ad.jp

keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
logdir /var/log/chrony
log measurements statistics tracking refclocks
local stratum 1

allow 192.168.0.0/24

initstepslew 15 ntp1.v6.mfeed.ad.jp ntp2.v6.mfeed.ad.jp
maxupdateskew 100.0
rtcsync
makestep 1 3

#NMEA
refclock SHM 0 refid NMEA

#PPS
refclock PPS /dev/pps0  refid PPS trust

こんな感じ。ntpdと似た感じな設定に見えるが、ntpd用そのままではダメなのでドキュメントを参照しながらの設定になる筈。
このNTPサーバへの参照許可は192.168.0.0/24にしている。NMEA/PPSのoffset, delayの設定は入れていない。個体差があるので普通は暫く動かして統計情報を録った上で必要に応じて変更することになる筈。

設定行の後にコメントをつけるとChronyがエラーで起動しない。この書き方はntpdではエラーにならないので最初chronyが起動しない理由が判らなかった。

#これは問題ない
#comment
blah blah

#こんな書き方はエラーになる
blah blah   #comment
chronyは設定ファイルで指定した入出力ファイルが存在しないとエラーになるっぽい。(停まりはしない)
/var/lib/chrony/chrony.drift.tmp
/var/log/chrony/measurements.log
/var/log/chrony/statistics.log
/var/log/chrony/tracking.log
この辺りのファイルは存在とパーミッションを確認。

何のファイルを入出力するかは利用者それぞれだと思うけどdriftファイル辺りは設定する人が多いと思うのでファイルを作成してchronyが読み書きできるパーミッションに設定する。
最初、driftファイルと統計用に出力設定したファイルを用意し忘れてchronyのサービスを再起動するとNMEA, PPSの値が入らないなど何か変な挙動を示して意味がわからなかったけど、これが原因だった。chronyは標準で入ってるのでdriftファイルはあるものだと思い込んでたし統計用ファイルは設定で指定すれば自動的に作成されるものだと思いこんでいた。

$ sudo systemctl status chrony
● chrony.service - chrony, an NTP client/server
   Loaded: loaded (/lib/systemd/system/chrony.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-07-09 19:31:13 JST; 3h 41min ago
     Docs: man:chronyd(8)
           man:chronyc(1)
           man:chrony.conf(5)
  Process: 1307 ExecStartPre=/bin/mkdir /tmp/chrony (code=exited, status=0/SUCCESS)
  Process: 1308 ExecStartPre=/bin/chown _chrony:_chrony /tmp/chrony (code=exited, status=0/SUCCESS)
  Process: 1309 ExecStartPre=/bin/chmod 600 /tmp/chrony (code=exited, status=0/SUCCESS)
  Process: 1310 ExecStart=/usr/sbin/chronyd $DAEMON_OPTS (code=exited, status=0/SUCCESS)
  Process: 1319 ExecStartPost=/usr/lib/chrony/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
 Main PID: 1312 (chronyd)
    Tasks: 2 (limit: 851)
   Memory: 1.2M
   CGroup: /system.slice/chrony.service
           ├─1312 /usr/sbin/chronyd -F -1
           └─1313 /usr/sbin/chronyd -F -1

Jul 09 19:31:07 hoge chronyd[1312]: Loaded seccomp filter
Jul 09 19:31:11 hoge chronyd[1312]: Could not open log file /var/log/chrony/statistics.log
Jul 09 19:31:11 hoge chronyd[1312]: System's initial offset : 0.001967 seconds fast of true (slew)
Jul 09 19:31:13 hoge systemd[1]: Started chrony, an NTP client/server.
Jul 09 19:32:00 hoge chronyd[1312]: Selected source PPS
Jul 09 20:32:04 hoge chronyd[1312]: Could not open temporary driftfile /var/lib/chrony/chrony.drift.tmp for writing

chronyのサービスを起動してステータスを確認し、ファイルが開けないというエラーが発生していないことを確認する。上の例では黄字が指定されたファイルが開けないことを示している。

1
2
3
4
5
6
7
8
9
/var/log.hdd/chrony/*.log {
    compress
    missingok
    nocreate
    sharedscripts
    postrotate
        /usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
    endscript
}

Chronyのログローテーションの設定は自動で入っているが、そのログ用ディレクトリの想定が /var/log.hdd/chrony になっている。この記事では /var/log/chrony にログを置くことを想定しているので1行目の黄色字の「.hdd」部分を削除する。

$ sudo logrotate -dv /etc/logrotate.conf
$ service logrotate restart

1行目を実行してエラーが発生しないことを確認。意外とディレクトリのパーミッション等でエラーが出るので必要に応じて修正。
エラーが無いか修正したら2行目でログローテートのサービスを再起動。

ChronyのNTPサーバとしての稼働状況の確認

chronyc sources 時刻ソース別の状態 -vを付けると簡易説明付きになる -nを付けるとIPアドレスで表示
chronyc sourcestats 時刻ソース別の状況 -vを付けると簡易説明付きになる
chronyc activity 時刻ソースの種類別の状態
sudo chronyc clients このNTPサーバを参照しているホストの参照状況
sudo chronyc serverstats パケットやコマンドの送受信状況
chronyc -a 対話式で状態表示や一時的な設定変更を行う

chronycはいろいろできるけどよく使いそうな確認用の5種と対話式の1つを例として挙げた。この5つの内、clientsとserverstatsを表示するには権限が必要。ntpq -pの代わりのようにchronyc sourcesを使うことが多いかな。(ちょっと違うんだけど)

次回はGPSモジュールの設定を行う。調整はその後かな。

関連記事: