本日も乙

ただの自己満足な備忘録。

今からでも間に合う!うるう秒対策(2017/01/01、検証付き)

[toc]

ほとんどの人は昨日か今日で仕事納めかと思います。私も本日で仕事納めです。 短い年末年始をゆっくり過ごしたいところですが、2017年の元日はうるう秒が挿入されるということでシステム管理者はその対応に追われていたり、当日に待機になっているのではないかと思います。

プレスリリース | 「うるう秒」挿入のお知らせ | NICT-情報通信研究機構

前回のうるう秒が2015年7月1日だったのですが、その時にも対応していました。 今回は、前回の対応があるから特に対応が不要かなと思っていたら、最近サーバをリプレイスしたり新規稼働させていたのを失念していたため、慌てて対応しました。

そんな自分みたいに慌てて対応に迫られている方もいるかもしれませんし、次にうるう秒が来た場合の備忘録も兼ねて対応方法を本記事にまとめました。 また、検証としてうるう秒を挿入させて挙動を確認してみました。

Amazon Linux

デフォルトのNTPクライアントがntpdだったので起動オプションを変更するだけで完了です。

バージョン

$ rpm -q ntp
ntp-4.2.6p5-41.32.amzn1.x86_64

設定ファイル

# /etc/sysconfig/ntpd
-OPTIONS="-g"
+OPTIONS="-g -x"

再起動、確認

$ sudo service ntpd restart
$ ps aux | grep ntpd | grep -v grep
ntp      124055  0.0  0.0  43692  4352 ?        Ss   10:36   0:00 ntpd -u ntp:ntp -p /var/run/ntpd.pid -g -x
$ ntpq -pn
     remote           refid        st t when poll reach   delay   offset  jitter
==============================================================================
*xxx.xxx.xxx.xxx  xxx.xxx.xxx.xxx  2 u   64   64    1    0.385    0.258   0.000

CentOS 7

CentOS 7からデフォルトのNTPクライアントはntpdからchronyに変わりました。 leapsecmodeslew に指定する必要があります。

# バージョン
$ rpm -q chrony
chrony-2.1.1-1.el7.centos.x86_64

# 設定ファイル追記
$ sudo sh -c "echo 'leapsecmode slew' >> /etc/chrony.conf"
$ sudo sh -c "echo 'maxslewrate 1000' >> /etc/chrony.conf"
$ sudo sh -c "echo 'smoothtime 400 0.001 leaponly' >> /etc/chrony.conf"

# 再起動
$ sudo systemctl restart chronyd.service

# 確認
$ chronyd --version
chronyd (chrony) version 2.1.1 (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +DEBUG +ASYNCDNS +IPV6 +SECHASH)

$ chronyc sources
210 Number of sources = 2
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* xxxxxxxxxxxxxxxxxxxxxx     2   6   377    47   +764us[ +769us] +/-   18ms
^+ xxxxxxxxxxxxxxxxxxxxxx     2   6   377    47   -756us[ -751us] +/-   18ms

$  chronyc tracking
Reference ID    : xxx.xxx.xxx.xxx (xxxxxxxxxxxxxxxxxxxxxx)
Stratum         : 3
Ref time (UTC)  : Wed Dec 28 04:14:02 2016
System time     : 0.000103575 seconds slow of NTP time
Last offset     : -0.000027113 seconds
RMS offset      : 0.000056461 seconds
Frequency       : 22.818 ppm slow
Residual freq   : -0.006 ppm
Skew            : 0.042 ppm
Root delay      : 0.004841 seconds
Root dispersion : 0.020671 seconds
Update interval : 257.4 seconds
Leap status     : Normal

Ubuntu 14.04 LTS

こちらもChronyが入っていたので、CentOS 7と対応方法は同じですが、インストールされているバージョンが古いため、leapsecmodeが使えません。そのため、2.1.1 にバージョンを上げます。

$ dpkg -l | grep chrony
ii  chrony                              1.29-1                               amd64        Set the computer clock from time servers on the Net

$ wget http://launchpadlibrarian.net/226940367/chrony_2.1.1-1_amd64.deb
$ sudo DEBIAN_FRONTEND=noninteractive dpkg --force-confdef --force-confold -i chrony_2.1.1-1_amd64.deb
Preparing to unpack chrony_2.1.1-1_amd64.deb ...
Stopped /usr/sbin/chronyd (pid 1580).
Unpacking chrony (2.1.1-1) over (1.29-1) ...
Setting up chrony (2.1.1-1) ...
Creating '_chrony' system user/group for the chronyd daemon…
Starting /usr/sbin/chronyd...
chronyd is running and online.
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Processing triggers for ureadahead (0.100.0-16) ...

$ rm -f chrony_2.1.1-1_amd64.deb

$ dpkg -l | grep chrony
ii  chrony                              2.1.1-1                              amd64        Versatile implementation of the Network Time Protocol

設定変更はCentOS 7と同じですが、設定ファイルの場所が異なるので注意が必要です。

$ sudo sh -c "echo 'leapsecmode slew' >> /etc/chrony/chrony.conf"
$ sudo sh -c "echo 'maxslewrate 1000' >> /etc/chrony/chrony.conf"
$ sudo sh -c "echo 'smoothtime 400 0.001 leaponly' >> /etc/chrony/chrony.conf"

$ sudo service chrony restart
Restarting time daemon: Starting /usr/sbin/chronyd...
chronyd is running and online.

# 確認
$ chronyd --version
chronyd (chrony) version 2.1.1 (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP -DEBUG +ASYNCDNS +IPV6 +SECHASH)

$ ps aux | grep [c]hrony
_chrony   3523  0.0  0.0  19492  1048 ?        S    18:53   0:00 /usr/sbin/chronyd -r

$ chronyc sources
210 Number of sources = 2
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* xxxxxxxxxxxxxxxxxxxxxx     2   6   377    47   +764us[ +769us] +/-   18ms
^+ xxxxxxxxxxxxxxxxxxxxxx     2   6   377    47   -756us[ -751us] +/-   18ms

$ chronyc tracking
Reference ID    : xxx.xxx.xxx.xxx (xxxxxxxxxxxxxxxxxxxxxx)
Stratum         : 3
Ref time (UTC)  : Mon Dec 26 09:54:41 2016
System time     : 0.000011080 seconds slow of NTP time
Last offset     : -0.000018058 seconds
RMS offset      : 0.000018058 seconds
Frequency       : 12.449 ppm fast
Residual freq   : -0.012 ppm
Skew            : 0.400 ppm
Root delay      : 0.003197 seconds
Root dispersion : 0.006336 seconds
Update interval : 64.6 seconds
Leap status     : Normal

Ubuntu 16.04 LTS

Ubuntu 14.04 LTSと同じです。また、Chronyのバージョンも2.1.1になっているのでアップデートの必要もありません。

うるう秒を検証する

うるう秒が差し込まれるとどうなるのかを実際に検証してみました。

簡易SNTPサーバをたてる

うるう秒を発生させる簡易的なSNTPサーバをたてます。 今回はAmazon Linuxでつくります。

AMI: AMI amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2 (ami-9f0c67f8)

SNTPサーバのスクリプトは、Perl版SNTPサーバ うるう秒テスト用バージョン 2005.12.01からコピペして持ってきます。

このままだとタイムゾーンUTCで不便なので、2015年うるう秒の検証方法と検証結果 (Amazon Linux, CentOS) - tkuchikiの日記からパッチを持ってきます。

$ sudo yum install -y patch perl-DateTime perl-DateTime-Format-Strptime perl-Time-HiRes
$ wget https://gist.githubusercontent.com/tkuchiki/f9e1f94baa16fede3789/raw/8b0e47a2cdb500222dc621942e3136fcb927e6ec/sntp.pl.patch
$ patch sntp.pl < sntp.pl.patch
$ sudo perl ./sntp.pl 2016-12-27T13:00:00
"-T" is on the #! line, it must also be used on the command line at ./sntp.pl line 1.

シバンで指定されている-Tが使えないみたいです。 以下のような変更になりました(NICTのオリジナルスクリプトとの差分)。 また、今回のうるう秒に合わせて日時も修正しています。

@@ -1,18 +1,33 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl

+use warnings;
 use strict;
 use Socket;
 use Time::HiRes qw( gettimeofday );
-use Time::Local;
+use DateTime;
+use DateTime::Format::Strptime;

 my ( $rb, $sb, $vn, $client, $sec, $msec, $proto, $paddr );
 my ( $NTP_LI, $NTP_LEAP, $MODE, $FLAG, $STR, $POLL, $PREC );
 my ( $USO_LEAP, $USO_OFFSET );

-$NTP_LI = timegm( 0, 0, 0, 31, 12-1, 05 ); # 05/12/31 00:00:00 UTC
-$NTP_LEAP = timegm( 0, 0, 0, 1, 1-1, 06 ); # 06/01/01 00:00:00 UTC
-
-$USO_LEAP = timegm( 0, 0, 0, 11, 12-1, 05 ); # 05/12/11 00:00:00 UTC
+my $current_time_zone = DateTime::TimeZone->new(name => 'local')->name();
+my $format = new DateTime::Format::Strptime(
+    pattern   => '%Y-%m-%dT%H:%M:%S',
+    time_zone => 'UTC',
+);
+
+my $offset = 9;
+
+my $uso_leap_date = $format->parse_datetime($ARGV[0]);
+my $ntp_li_date   = $format->parse_datetime('2016-12-31T00:00:00');
+my $ntp_leap_date = $format->parse_datetime('2017-01-01T00:00:00');
+
+$uso_leap_date->set_time_zone('UTC');
+
+$NTP_LI   = $ntp_li_date->epoch;
+$NTP_LEAP = $ntp_leap_date->epoch;
+$USO_LEAP = $uso_leap_date->subtract(hours => $offset)->epoch;
 $USO_OFFSET = $NTP_LEAP - $USO_LEAP;

 $MODE = 4; # mode = 4 (server)

タイムゾーン変更

$ sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime
$ sudo -e /etc/sysconfig/clock
ZONE="Asia/Tokyo"
UTC=False

実行

UDP 123番ポートを使うので、ntpdを止めます。また、ウェルノウンポートなのでsudoが必要です。

$ sudo service ntpd stop
$ chmod +x sntp.pl
$ sudo perl ./sntp.pl 2016-12-27T13:00:00

検証サーバ側の設定

時刻サーバの設定変更

NTPサーバの向き先を先ほどの簡易版SNTPサーバのIPアドレスに変更します。

# /etc/chrony/chrony.conf

# 簡易SNTPサーバのIPアドレス
server xxx.xxx.xxx.xxx

再起動後、強制的に同期させます。

$ sudo service chrony restart

# 強制同期
$ sudo chronyc -a makestep

$ chronyc sources
210 Number of sources = 1
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* xxxxxxxxxxxxxxxxxxxxxx     1   6    37     0    -55us[  +64us] +/- 1413us

$ chronyc tracking
Reference ID    : xxx.xxx.xxx.xxx (xxxxxxxxxxxxxxxxxxxxxx)
Stratum         : 2
Ref time (UTC)  : Sat Jan  2 00:27:38 2016
System time     : 31112990.000000000 seconds fast of NTP time
Last offset     : +0.000904015 seconds
RMS offset      : 0.000904015 seconds
Frequency       : 50.384 ppm slow
Residual freq   : +14.642 ppm
Skew            : 0.841 ppm
Root delay      : 0.002819 seconds
Root dispersion : 0.000554 seconds
Update interval : 71.1 seconds
Leap status     : Normal

時刻推移を見るスクリプト

時刻推移を見るには、公開されているスクリプトを使った方が確認しやすいです。

$ wget http://www.cuspy.org/diary/2012-06-05/gettimeofday.pl
$ chmod +x gettimeofday.pl

結果

Stepモード

Slewモードに変更する前に検証した結果です。

$ perl ./gettimeofday.pl
08:59:58.060518
08:59:58.160714
08:59:58.260913
08:59:58.361108
08:59:58.461301
08:59:58.561501
08:59:58.661707
08:59:58.761906
08:59:58.862110
08:59:58.962311
08:59:59.062507 <- 1回目の08:59:59
08:59:59.162700
08:59:59.262898
08:59:59.363096
08:59:59.463289
08:59:59.563485
08:59:59.663684
08:59:59.763880
08:59:59.864092
08:59:59.964305
08:59:59.064486 <- 2回目の08:59:59
08:59:59.164725
08:59:59.264928
08:59:59.365239
08:59:59.465454
08:59:59.565635
08:59:59.665881
08:59:59.766090
08:59:59.866312
08:59:59.966522
09:00:00.066703
09:00:00.166948
09:00:00.267258
09:00:00.367536
09:00:00.467815
09:00:00.568130
09:00:00.668403

$ chronyc tracking
Reference ID    : xxx.xxx.xxx.xxx (xxxxxxxxxxxxxxxxxxxxxx)
Stratum         : 2
Ref time (UTC)  : Sun Jan  1 00:00:06 2017
System time     : 0.000000920 seconds slow of NTP time
Last offset     : +0.000007976 seconds
RMS offset      : 149.121963501 seconds
Frequency       : 36.156 ppm slow
Residual freq   : +0.002 ppm
Skew            : 0.248 ppm
Root delay      : 0.002686 seconds
Root dispersion : 0.000032 seconds
Update interval : 64.1 seconds
Leap status     : Insert Second

08:59:59 が2回差し込まれたことが分かります。 また、Leap status を見ると、08:59:59から09:00:00あたりでNormalからInsert Secondに変わったのでLeap Indicatorを受信したようです(しばらくしてNormalに戻りました)。

Slewモード

$ perl ./gettimeofday.pl
08:59:58.001852
08:59:58.102048
08:59:58.202270
08:59:58.302468
08:59:58.402665
08:59:58.502870
08:59:58.603064
08:59:58.703257
08:59:58.803457
08:59:58.903658
08:59:59.003856
08:59:59.104046
08:59:59.204280
08:59:59.304467
08:59:59.404701
08:59:59.504919
08:59:59.605106
08:59:59.705316
08:59:59.805534
08:59:59.905756
09:00:00.005993
09:00:00.106139
09:00:00.206279
09:00:00.306417
09:00:00.406558
09:00:00.506687
09:00:00.606823
09:00:00.706956
09:00:00.807125
09:00:00.907253

$ chronyc tracking
Reference ID    : xxx.xxx.xxx.xxx (xxxxxxxxxxxxxxxxxxxxxx)
Stratum         : 2
Ref time (UTC)  : Sat Dec 31 23:56:44 2016
System time     : 0.000000708 seconds fast of NTP time
Last offset     : +0.000002267 seconds
RMS offset      : 0.000026451 seconds
Frequency       : 36.238 ppm slow
Residual freq   : +0.000 ppm
Skew            : 0.078 ppm
Root delay      : 0.002741 seconds
Root dispersion : 0.000093 seconds
Update interval : 129.0 seconds
Leap status     : Insert second

08:59:59は1回のみ刻まれていました。 また、Leap Statusは09:00:00になる前からInsert Secondに変わっており、09:00:00を過ぎたあたりからNormalに戻りました。

最後に

うるう秒の対策および検証方法を紹介しました。何事もなく新年を迎えられるといいですね。

参考URL