SadServers解法メモ

# これは何？

Linuxサーバのトラブルシューティング問題集 [SadServers](https://sadservers.com/scenarios) の解法メモ。
使用したコマンドなどについて書き残します。
完全にネタバレなので問題を見ていない人はブラウザバックを推奨します。

Linux初学者なのでところどころ理解が怪しい部分などがあります。ご指摘歓迎です。

## 1. what is writing to this log file?
ログに書き込み続けているプロセスを特定し、killコマンドで終了する。

### ps
プロセス一覧の表示。
ps auxfやps -efで確認するのが主流らしい。
ps auxfの方が情報量が多いが、ps -ef はPPID(親プロセスID)を表示できる。

### lsof

ファイルを開いているプロセスを確認できる。

```
ubuntu@ip-172-31-32-108:/$ lsof /var/log/bad.log 
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
badlog.py 632 ubuntu    3w   REG  259,1    19541 67701 /var/log/bad.log
```

さらにプロセスIDを指定することで、cwdなどが調べられる。

```
ubuntu@ip-172-31-32-108:/$ lsof -p 632
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
badlog.py 632 ubuntu  cwd    DIR  259,1     4096 258156 /home/ubuntu
...
```


## 3. counting IPs
ファイル内で登場頻度が一番多い単語を特定する。

### awk
スペースやタブで区切られた文字列の、1つ目の要素を取り出す
```
awk '{print $1}'
```

Fオプションで区切り文字を指定可能
```
awk -F'[:]' '{print $1}'
```

### uniq -c
各要素を出現回数と一緒に表示できる
```
    482 66.249.73.135
    364 46.105.14.53
    357 130.237.218.86
    273 75.97.9.59
    113 50.16.19.13
```


## 4. can't serve web file
ファイアウォールの修正。

```
root@ip-172-31-21-14:/# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       tcp  --  anywhere             anywhere             tcp dpt:http

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  
```

設定を確認すると、httpのINPUTをすべてDROP(パケットを破棄)する設定になっている。
また、Chain INPUT (policy ACCEPT)とあることから、ルールが指定されていないパケットについては一律でACCEPT(パケットを許可)する状態。

このため、当該設定を削除すれば良い。

```
root@ip-172-31-21-14:/# iptables -D INPUT 1
root@ip-172-31-21-14:/# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination 
```

ついでにChain INPUTの設定をpolicy DROPに変更して問題を解いてみる。

```
root@ip-172-31-21-14:/# iptables -P INPUT DROP
```

コマンドを打った瞬間プロンプトが動かなくなった。
policy DROPにしたのでこの瞬間にサーバーへの接続が弾かれてしまったらしい（それはそう）。
policyをDROPに変更するときは先にACCEPTの設定を行わないといけない。

ACCEPTにSSHとか入れればpolicy DROPにしても動くのでは…？と考えたが、これ以上リトライして問題サーバを起動するのは無作法なので、一旦ここまで。


## 5. can't write data into database.
PostgreSQLが立ち上がらないエラーの解消。

### df
ディスクの空き領域のサイズを表示する。(disk freeの略)

```
root@ip-172-31-46-78:/# df -h
Filesystem       Size  Used Avail Use% Mounted on
udev             224M     0  224M   0% /dev
tmpfs             47M  1.5M   46M   4% /run
/dev/nvme1n1p1   7.7G  1.2G  6.1G  17% /
tmpfs            233M     0  233M   0% /dev/shm
tmpfs            5.0M     0  5.0M   0% /run/lock
tmpfs            233M     0  233M   0% /sys/fs/cgroup
/dev/nvme1n1p15  124M  278K  124M   1% /boot/efi
/dev/nvme0n1     8.0G  8.0G   28K 100% /opt/pgdata
```

さらにlsコマンドで/opt/pgdataを見ると、7GBのバックアップファイルが幅を利かせている。

```
root@ip-172-31-46-78:/# ls -lh /opt/pgdata
total 8.0G
-rw-r--r--  1 root     root       69 May 21 22:20 deleteme
-rw-r--r--  1 root     root     7.0G May 21 22:06 file1.bk
-rw-r--r--  1 root     root     923M May 21 22:17 file2.bk
-rw-r--r--  1 root     root     488K May 21 22:23 file3.bk
drwx------ 19 postgres postgres 4.0K May 21 22:24 main
```

これを削除して再起動する。
問題文からbkファイルの要不要は判断できないけれど、ディレクトリ一番上のファイルにdeletemeと書いてあるので消して良い。

## 6. Borked Nginx
/etc/systemd/system配下にあるnginxの設定ファイルを修正する。

## 7. Docker container won't start.
Dockerfileの修正。

ポート8888でexposeをする必要があるが、8888は既に別のアプリが使っている。ポートを使用しているプロセスを特定して削除する。

### netstat
ホストのネットワーク接続状態を確認できる。
pオプションをつけるとそれぞれの接続を使っているプロセスが表示できる。

```
admin@ip-172-31-41-254:~/app$ sudo netstat -pa | grep 8888
tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      617/nginx: master p 
tcp6       0      0 [::]:8888               [::]:*                  LISTEN      617/nginx: master p 
```

## 8. it's always DNS.
/etc/nsswitch.confで名前解決の設定を修正する。
（DNS周りのエラーなのでresolv.confに問題があるのか…？と色々調べていたが不正解。そもそもDNSサーバに問い合わせができていないので見当違いだった）


## 9. Docker web container can't connect to db container.

WORDPRESS_DB_HOSTがデフォルト値の'mysql'のままになっているので、これを修正する。

inspectでIPAddressを確認。

```
admin@ip-172-31-19-232:/$ sudo docker inspect mariadb | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",
```

mariadbコンテナは3306番ポートをexposeしているので、このIPアドレスを指定すればDBへの接続ができる。

ここからどう対処するか考える。
wp-config.phpには

```
define( 'DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'mysql') );
```

とあるので、以下のように環境変数WORDPRESS_DB_HOSTを追加してコンテナを再起動すれば、コンテナ間の通信は通るようになる。

```
admin@ip-172-31-19-232:/$ sudo docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED        STATUS         PORTS                    NAMES
6ffb084b515c   wordpress:sad    "docker-entrypoint.s…"   3 months ago   Up 3 minutes   0.0.0.0:80->80/tcp       wordpress
0eef97284c44   mariadb:latest   "docker-entrypoint.s…"   3 months ago   Up 3 minutes   0.0.0.0:3306->3306/tcp   mariadb

admin@ip-172-31-19-232:/$ sudo docker rm -f 6ffb084b515c
6ffb084b515c

admin@ip-172-31-19-232:/$ sudo docker run -d -e WORDPRESS_DB_HOST=172.17.0.1 --name wordpress -p 80:80 wordpress:sad
e38fcd8eae5b629898d8d72b7ef539669d7bf60098f958e2a31573e74bef5659

admin@ip-172-31-19-232:/$ sudo docker exec wordpress env | grep WORDPRESS_DB_
WORDPRESS_DB_HOST=172.17.0.2
WORDPRESS_DB_PASSWORD=password
WORDPRESS_DB_USER=root
```


しかし、この設問は以下のテストが通ることを要求している。

> Test: `sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping` . The wordpress container is able to connect to the database in the mariadb container and returns `mysqld is alive`.

テストでホスト名に -h mysql を指定しているので、このままではテストが通らない。
これを通すために、/etc/hostsに一行追加する。

```
admin@ip-172-31-19-232:/$ sudo docker exec -ti wordpress bash
root@da9ad9f3ad05:/var/www/html# echo "172.17.0.1 mysql" >> /etc/hosts
```

これでテストも通る。

```
admin@ip-172-31-19-232:/$ sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping
mysqld is alive
```

## 10. Docker and Kubernetes web app not working.
ImagePullBackOffでPodが立ち上がらない状態なので、プライベートのDocker Registryにイメージをpushする。
また、`curl localhost:8888` のリクエストを成功させるためにPodのポートフォワーディングを行う必要がある。

```
admin@ip-10-0-0-64:~$ kubectl port-forward deployments/webapp-deployment 8888 -n web
Forwarding from 127.0.0.1:8888 -> 8888
Forwarding from [::1]:8888 -> 8888
```

## 11. WTFIT – What The Fun Is This?
wtfitという名前の謎のファイルがあるので、どうにか実行できるようにする。
（CTFチックな問題だ）

```
admin@ip-172-31-36-138:~$ file wtfit 
wtfit: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=_iHDgQr9_DkcDPzFkdEV/KeopbEbY41Cs4Jx-plaD/bLd_UQ3kiokG80g9hhbY/qtKkikMAZmQbLl9qoMCF, not stripped
```
とりあえず実行可能ファイルではあるらしい。

```
admin@ip-172-31-36-138:~$ ls -l
total 6236
drwxr-xr-x 2 admin admin    4096 Sep 13 18:18 agent
-rw-r--r-- 1 admin admin 6381234 Sep 13 18:17 wtfit
```
実行権限がないのでchmodする。

```
admin@ip-172-31-36-138:~$ chmod 755 wtfit 
bash: /usr/bin/chmod: Permission denied
```
ええ…
chmodをカレントディレクトリにinstallする。

```
admin@ip-172-31-36-138:~$ install -m 755 /usr/bin/chmod .
admin@ip-172-31-36-138:~$ ./chmod 755 wtfit
admin@ip-172-31-36-138:~$ ls -l
total 6300
drwxr-xr-x 2 admin admin    4096 Sep 13 18:18 agent
-rwxr-xr-x 1 admin admin   64448 Nov  6 16:57 chmod
-rwxr-xr-x 1 admin admin 6381234 Sep 13 18:17 wtfit
```
chmodできた。
再実行。
```
admin@ip-172-31-32-154:~$ /home/admin/wtfit
ERROR: can't open config file
```

config fileが開けないとだけ出力されている。
straceで再確認。

```
admin@ip-172-31-36-138:~$ strace /home/admin/wtfit
...
openat(AT_FDCWD, "/home/admin/wtfitconfig.conf", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(1, "ERROR: can't open config file\n", 30ERROR: can't open config file
) = 30
exit_group(1)                           = ?
+++ exited with 1 +++
```

wtfitconfig.confを開こうとしているが、ファイルが存在していない。
空ファイルを作成して再実行。
```
admin@ip-172-31-36-138:~$ touch /home/admin/wtfitconfig.conf
admin@ip-172-31-36-138:~$ /home/admin/wtfit 
ERROR: can't connect to server
```

サーバーに接続できないらしい。
tcpdump -i loを実行し、自分自身へのパケットをキャプチャする。

```
admin@ip-172-31-36-138:~$ sudo tcpdump -i lo
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:05:12.868414 IP localhost.34996 > localhost.7777: Flags [S], seq 534663709, win 65495, options [mss 65495,sackOK,TS val 383227227 ecr 0,nop,wscale 6], length 0
17:05:12.868426 IP localhost.7777 > localhost.34996: Flags [R.], seq 0, ack 534663710, win 0, length 0
17:05:12.868414 IP localhost.34996 > localhost.7777: Flags [S], seq 534663709, win 65495, options [mss 65495,sackOK,TS val 383227227 ecr 0,nop,wscale 6], length 0
17:05:12.868425 IP localhost.7777 > localhost.34996: Flags [R.], seq 0, ack 534663710, win 0, length 0
```

ポート7777に何らかのリクエストを送っている。
問題文に書いてあった `wtfit needing to communicate to a service in order to start` の処理らしい。

ポート7777で適当なサーバーを立ち上げる。
```
admin@ip-172-31-36-138:/$ python3 -m http.server 7777
Serving HTTP on 0.0.0.0 port 7777 (http://0.0.0.0:7777/) ...
```

```
admin@ip-172-31-36-138:/$ /home/admin/wtfit
OK.
```
何がOKなのかはよく分からないけれど、題意は満たせたらしい。


## 12. can't write data into database.

### /etc/fstab
マウントするファイルシステムを管理するファイル。

```
# /etc/fstab: static file system information
UUID=5db68868-2d70-449f-8b1d-f3c769ec01c7 / ext4 rw,discard,errors=remount-ro,x-systemd.growfs 0 1
UUID=72C9-F191 /boot/efi vfat defaults 0 0
/dev/xvdb /opt/pgdata xfs defaults,nofail 0 0
```

この設定だと「/dev/xvdb」デバイスを「/opt/pgdata」ディレクトリにマウントする。

```
root@ip-172-31-25-11:/# lsblk -f
NAME         FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
nvme0n1      xfs          9a2e1bf9-50e8-41a9-9f8c-5dd837869c50                
nvme1n1                                                                       
├─nvme1n1p1  ext4         5db68868-2d70-449f-8b1d-f3c769ec01c7      6G    16% /
├─nvme1n1p14                                                                  
└─nvme1n1p15 vfat         72C9-F191                             123.5M     0% /boot/efi
```

lsblkでnvme0n1がunmountになっていることが分かるので、「/dev/xvdb」を「/dev/nvme0n1」に書き換えてsystemctl daemon-reloadで設定を反映する。