インフラエンジニアと謎のサーバ


この記事は[闇の魔術に対する防衛術 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/yami)の6日目の記事です。

# あらすじ

この世には歴史的経緯により何が動いているか分からない謎のサーバというものが存在する。
謎のサーバには、気の利いたドキュメントだの仕様だのGitHubにコードが上がってるだの、そういう甘っちょろい物は一切ない。謎のサーバは殆ど変更される事なく、あまりトラブルを起こす事なく、しかし何かのサービスによって必要とされてひっそりと動いている。

インフラエンジニアは時にこういった謎のサーバを調査して、ドキュメントに起こすか、コード化するか、ひっそりと退役させるか、はたまたリプレイスするか、といった対応に追われる。
私はこういったタスクの事を”考古学”とか”遺跡発掘”とか呼んだりする。

(考古学の成果の一例)
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">uptime2700日超えのサーバにshutdown -h nowをカマした</p>&mdash; かんが (@kanga333) <a href="https://twitter.com/kanga333/status/1021203525538177024?ref_src=twsrc%5Etfw">2018年7月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


この記事では”考古学”における調査方法を紹介する。
調査方法は筆者の経験に基づくものなので特定のコンテキストに偏っている可能性がある。しかしこれから考古学を行う人達への一助となれば幸いである。

# 事前準備

遺跡調査だ！となっていきなり遺跡に乗り込むのは早計だ。まずは事前準備をしっかりしよう。

## 仕様や動作を知っていそうな人へのヒアリング

チームには古くから在籍する長老的ポジションのエンジニアが大抵いるはずだ。そういった人を捕まえて、サーバで動いてそうな処理や関連するサービスなどの情報をヒアリングしよう。もしそういう人が居なくても、きっと口伝で伝承されたエンジニアはいるはずだ。頑張って探そう。

インフラ的観点で仕様を知ってそうな人だけではなく、アプリケーション的観点で仕様を知ってそうな人からもヒアリングするようにしよう。どういう意図で作られていて何に使われているかが明らかになれば後の調査は楽になる。

ヒアリング結果は議事録にして社内のオープンな場に記録しておこう。謎を明らかにする仕事はすでに始まっている。

### ヒアリングにおける重要なポイント

ヒアリングにおいて最も大事な事は相手にリスペクトを払うことだ。この手の調査タスクはふとした闇に囚われる事が多々ある。しかし、そういったサーバは好き好んで作られている訳ではない。サービスが立ち上がるか不確かな中、限られたリソースによって開発を進めてきた結果なのだ。過去の当事者たちにも敬意を払おう。

# 調査実施

いよいよ遺跡調査である。慎重に、しかし時に思い切りを持って進めよう。

## サーバに入ったらまずする事

それはサーバの負荷の確認である。高負荷なサーバであればより慎重な調査が必要となる。
しかし案ずる事はない。謎のサーバは大半が低負荷である。
なぜなら高負荷なサーバであれば往々にしてトラブルが発生しやすいので、謎のサーバのままで放置される事は少ない。手をかける必要が殆どないサーバだからこそ、謎のサーバは謎のままでいられるのだ。

閑話休題。

兎にも角にも負荷の確認である。CPU使用率とディスクの使用率はマストで確認しておこう。

```console:cpu使用率の確認
# vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 843784   8060  59944    0    0     8     1    9   10  0  0 100  0  0
 0  0      0 843784   8060  59944    0    0     0     0   11    7  0  0 100  0  0
 0  0      0 843784   8060  59944    0    0     0     0   11   12  0  0 100  0  0
 0  0      0 842216   8060  59944    0    0     0     0   45   62  2  1 97  0  0
```

```console:ディスク使用率の確認
# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      7.8G  752M  6.7G  10% /
tmpfs           498M     0  498M   0% /dev/shm
```

### 古さの確認

謎のサーバは大概が古い。時代のロマンを感じるためにもいつの時代に建立されたサーバなのか確認しよう。

定番のuptime 。(適当に立てたEC2インスタンスで実行しているのでuptimeは短い)

```console:
# uptime
08:52:44 up  1:44,  3 users,  load average: 0.00, 0.00, 0.00
```

`uname -a`でカーネルバージョンの確認ができる。

 ```console
# uname -a
Linux somehost 2.6.32-696.30.1.el6.x86_64 #1 SMP Tue May 22 03:28:18 UTC 2018 x86_64 x86_64 x86_64 GNU/Linu
```

`/etc/*-release`を探せばOSバージョンがわかる。

```console
# ls /etc/*release
/etc/centos-release  /etc/redhat-release  /etc/system-release
# cat /etc/redhat-release
CentOS release 6.9 (Final)
```

### プロセス一覧の確認

どんなプロセスが動いてるか把握しよう。
さしあたり、どのユーザでどんなコマンドのプロセスが実行されているか知りたいだけなので
`ps -A o user,command --no-header --sort command | grep -v -e '\s\['`とかを使っている。

```console
# ps -A o user,command --no-header --sort command | grep -v -e '\s\['
root     /usr/sbin/acpid
root     /sbin/agetty /dev/ttyS0 115200 vt100-nav
root     /usr/sbin/anacron -s
root     auditd
centos   -bash
root     /bin/bash
centos   -bash
root     /bin/bash
root     crond
root     /sbin/dhclient -1 -q -cf /etc/dhcp/dhclient-eth0.conf -lf /var/lib/dhclient/dhclient-eth0.leases -pf /var/run/dhclient-eth0.pid eth0
root     grep -v -e \s\[
root     /sbin/init
root     /usr/libexec/postfix/master
root     /sbin/mingetty /dev/tty1
postfix  pickup -l -t fifo -u
root     ps -A o user,command --no-header --sort command
postfix  qmgr -l -t fifo -u
root     /sbin/rsyslogd -i /var/run/syslogd.pid -c 5
root     /usr/sbin/sshd
root     /sbin/udevd -d
root     /sbin/udevd -d
```

### Cronの確認

動いているプロセスを網羅したから一安心かと思いきや古いサーバでは大抵Cronが動いていたりする。
以下のディレクトリを確認してCronのジョブが設定されていないか確認しよう。

```
/var/spool/cron/
/etc/crontab/
/etc/cron.d/
/etc/cron.hourly/
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
```

### 通信の確認

`netstat`でなんのポートで待ち受けているか確認しよう。

```console
# netstat -lnptu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1230/sshd
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1330/master
tcp        0      0 :::22                       :::*                        LISTEN      1230/sshd
tcp        0      0 ::1:25                      :::*                        LISTEN      1330/master
udp        0      0 0.0.0.0:68                  0.0.0.0:*                               950/dhclient
```

`ss`コマンド？そんなものは謎の（古い）サーバにはない。

### インストールパッケージの確認

もしサーバのリプレイスを目的としているのなら、なんのパッケージがインストールされているか確認する必要がある。
パッケージリストを確認する場合はインストールした日時も出力すると調査に役に立つ。後からインストール/アップデートされたかを否か判断できるからだ。

Redhat系は以下のコマンドで確認できる。

```console
# rpm -qa --last
vim-minimal-7.4.629-5.el6_8.1.x86_64          Sat Oct  6 20:18:38 2018
rootfiles-8.1-6.1.el6.noarch                  Sat Oct  6 20:18:38 2018
bind-utils-9.8.2-0.68.rc1.el6_10.1.x86_64     Sat Oct  6 20:18:38 2018
yum-plugin-ovl-1.1.30-42.el6_10.noarch        Sat Oct  6 20:18:37 2018
（略）
```

残念ながらDebian系には`rpm -qa --last`に該当するコマンドがないらしい。(Debian系の遺跡を調査した事がないので詳しくは知らない）
ログが残ってれば以下のコマンドで履歴が確認できるっぽい。

```console
# grep install /var/log/dpkg.log
2014-01-29 17:01:03 startup archives install
2014-01-29 17:01:03 install base-passwd <none> 3.5.22
2014-01-29 17:01:03 status half-installed base-passwd 3.5.22
2014-01-29 17:01:03 status installed base-passwd 3.5.22
2014-01-29 17:01:03 startup archives install
（略）
```

参考: https://unix.stackexchange.com/questions/12578/list-packages-on-an-apt-based-system-by-installation-date

### ファイルの調査

後は稼働しているプロセスやインストールされたパッケージに応じた設定ファイルをコピーしておこう。
大半の設定ファイルは`/etc`の下を見ておけばOKだ。

が、場合によっては個人ユーザのホームディレクトリに`make install`とかでインストールされたパッケージがあったりなかったりする。そういった怪しいファイルを探すための方法をいくつか紹介する。

#### データサイズが大きい順にディレクトリを表示する

データサイズが大きいディレクトリを確認することで、謎のDBが実は/home配下で動いていた、とかそういうのをあぶり出す。
うっかり際限なく探してしまわないように`--max-depth=3`などつけてduコマンドで探っていこう。

```console
# du -m / --max-depth=3 --exclude="/proc*" | sort -k1 -n -r
736	/
326	/usr
179	/lib
143	/var
117	/usr/lib
116	/var/cache/yum
116	/var/cache
(略)
```


#### 更新日が新しい順にファイルを表示する

更新日時が比較的新しいファイルを確認することで、後から変更が入ったであろうファイルをあぶり出す。
うっかり際限なく探してしまわないように`-maxdepth`などつけてfindで探っていこう。

```console
# find /etc -maxdepth 3 -type f -printf "%p %TY-%Tm-%Td\n" | sort -k2 -r
/etc/sysconfig/network 2018-12-06
/etc/sysconfig/i18n 2018-12-06
/etc/sudoers.d/90-cloud-init-users 2018-12-06
/etc/ssh/sshd_config 2018-12-06
/etc/ssh/ssh_host_rsa_key.pub 2018-12-06
(略)
```

### その他確認

他にもいろいろあるがキリがないのでこの辺にしておく。

# 調査の先に...

調査が終わったら、いよいよ対応だ。
ドキュメントを残して再び封印するも、リプレイスを進めるのも貴方の自由だ。ぜひステークホルダーと相談して決めて欲しい。

なお、この先に関するノウハウの記述はない。なぜならこの先は使ってるミドルウェアやチームの状況など環境による所が特に大きいからだ。決して飽きた訳では無い。

しかし恐れる事はない、謎のサーバは先の調査によって明らかになり、貴方の目の前にはもう謎は無いのだから...