俺様サーバー構築記 - dhcp サーバ冗長化@デスクトップパソコン

「[俺様サーバー構築記 - 基本方針](https://qiita.com/katz_engineer/items/dbabcff4e14e9db2b10f)」以来構築を続けてきた俺様パソコン環境ですが、[```/etc``` のバージョン管理](https://qiita.com/katz_engineer/items/357e9d8efa71b17deec8)も仕込んで本格的にサービスを設定する段階になりました。アドベントカレンダーで賑わっているQiita界隈の今日この頃ですが、私は独り、己の道を歩んでいきます。

何だかカッコ良さげですが、要するにぼっちです:expressionless:

え〜と。

最初に DHCP サーバの冗長化を図ります。

# 能書き

一般的な家庭においては、家庭内 LAN に接続されるマシンの IP アドレスは無線 LAN ルータなどの内蔵 DHCP サーバが割り振る事になります。これを無効化する設定も可能ですけど、まあ普通はしませんよね。わざわざ手間を掛けて、今時どうでもいいような枯れた技術である DHCP サーバをインストール・設定する人は居ないでしょう。

今回はその点でちょっとしたイタズラです。

ちょっとやそっとでは機能を停止しないような、可用性の高いパソコン環境を家庭内に構築する事は私の長年の夢でした。というか今まで何度も痛い目に遭って不本意ながら涙目の思い出を積み上げてきてしまった私としては、堅牢な環境の構築は非常に重要な目標なのです！（力説）

ちなみに [```/etc``` のバージョン管理](https://qiita.com/katz_engineer/items/357e9d8efa71b17deec8)は高可用性環境構築とは関係ありません。様々なサービスの運用や設定試行錯誤における覚え書きが目的です。

という訳で。

家庭向け高可用性環境構築の第一歩として、 DHCP サーバの多重化を試みます。同時に IP アドレス設定に関する覚え書きを残せるようにします。家庭向け無線 LAN ルータの内蔵 DHCP サーバでは、コメントを残す機能なんてありませんので。AirMac では残せたんですがね。

# IP アドレス体系

DHCP サーバを立てる前に、家庭内の IP アドレス体系を見直します。下記のような形に再定義する事にしました。クラスBにして、第3オクテットで色々と使い分ける方針です。

我が家のネットワークアドレス: **172.16.0.0/16**

<dl>
<dt>172.16.0.*<dt>
<dd>NIC 毎の固定 IP アドレス</dd>
<dt>172.16.1.*</dt>
<dd>MAC アドレス毎に DHCP サーバが固定的に割り当てる IP アドレス</dd>
<dt>172.16.2.*</dt>
<dd>無線 LAN ルータ内蔵の DHCP サーバによる動的割り当ての IP アドレス</dd>
<dt>172.16.3.*</dt>
<dd>現在構築中のデスクトップパソコンの DHCP サーバによる動的割り当ての IP アドレス</dd>
<dt>172.16.4.*</dt>
<dd>将来構築予定の待機系サーバマシンの DHCP サーバによる動的割り当ての IP アドレス</dd>
</dl>

DHCP プロトコル自体は、LAN 内に複数の DHCP サーバが在っても問題無く動く作りになっているそうです。問題は DHCP サーバの IP アドレス管理が同期されない事で、 IP アドレスが重複して発行されてしまう事態になりかねない点にあります。だから DHCP サーバ毎に IP アドレス範囲を分離する事で、多重発行を防ぐようにすれば良い、との事。

# 現状の確認

現在のルータの設定内容を確認して、現状を把握します。これ大事。気が逸るのもわかりますがね、準備期間の確保が命を救います。

主な確認内容は下記2点です。

- IP アドレスの割り当て（MAC アドレスに対して固定で割り振っている分）
- WAN からのポートフォワーディング

我が家は現在 AirMac を使っているので、設定内容のテキスト出力とかちょっと無理そうです。仕方が無いので1件ずつ手作業でテキスト化しました。高々30〜40件程度なので何とかなります。かつて調子に乗ってサーバを立てまくった名残です。そのサーバ群も1つ潰れ2つ消え… 夏草やつわものどもが夢の跡。

# 作業

準備が完了したら、いよいよ設定作業です。
一時的に切断されても大丈夫なマシン（正確にはNIC）から順番に作業します。

## FreeNAS

GUI が整備されているので、 Web ブラウザでアクセスしてネットワークの設定画面から IP アドレスとネットマスクを設定します。

- ゲートウェイ: 172.16.0.1
- DHCP: OFF
- IP アドレス: 172.16.0.2
- ネットマスク: /16(255.255.0.0)

## デスクトップパソコン

ウチのサーバ用デスクトップパソコンは2枚の NIC を持っています。

参考文献: [LinuxネットワークTip: MACアドレスを取得する](https://qiita.com/katz_engineer/items/c2a2441aec05a0babdc2)

```console:デスクトップパソコン
# find /sys/devices \! -path "*/virtual/*" -path "*/net" -exec ls {} \;
enp0s25
enp2s1
```

片方はオンボードで、もう片方はギガビットイーサのPCIネットワークカードです。オンボードの方は遅いのでケーブルを外してあります。

```console:デスクトップパソコン
# ip addr 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp2s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.121/24 brd 10.0.1.255 scope global dynamic enp2s1
       valid_lft 82380sec preferred_lft 82380sec
    inet6 fe80::216:1ff:fe5c:19df/64 scope link 
       valid_lft forever preferred_lft forever
3: enp0s25: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 66:77:88:99:aa:bb brd ff:ff:ff:ff:ff:ff
```

こうしてみると enp2s1 の方が動いている NIC のようです。こちらに固定 IP アドレスを振ります。 enp0s25 は放置でも良いんですが、こちらも固定で割り振っておきましょう。IP アドレス空間を広く取っているので無駄遣いしても問題ありませんし。

```console:デスクトップパソコン
# cd /etc/systemd/network
# ls
all.network
# cat all.network 
[Match]
Name=*

[Network]
DHCP=ipv4
# rm all.network 
# cat >enp2s1.network <<___
> [Match]
> Name=enp2s1
> 
> [Network]
> Address=172.16.0.3/16
> Gateway=172.16.0.1
> DNS=172.16.0.1
> ___
# cat >enp0s25.network <<___
> [Match]
> Name=enp0s25 
> 
> [Network]
> Address=172.16.0.4/16
> Gateway=172.16.0.1
> DNS=172.16.0.1
> ___
```

```[Match]``` には MAC アドレスを指定できるみたいなので、そちらでも良さそうですね。そこはお好みで。ファイル名も何でも良さそうですけども、凝った名前にしても後でわからなくなりますし、NIC 名にでもしておくのが一番無難と考えました。

設定が終わったらネットワークを再起動します。が、その瞬間にアクセス不可となりますので気を付けましょう。

```console:デスクトップパソコン
# systemctl restart systemd-networkd
```

## 無線 LAN ルータ

無線 LAN ルータの設定方法は、各機種のマニュアルを読みましょう。DHCP サーバの範囲指定も同時に設定します。

私の場合は同時にルータを交換したので、インターネットプロバイダの PPPoE なども設定しました。

- ルータ自身の LAN 側 IP アドレス: 172.16.0.1/16
- DHCP の設定: 先頭アドレス= 172.16.2.2、割当数= 可能な限り大きくする

これも、設定した瞬間にアクセスできなくなります。

## 確認

設定作業に使っているノートパソコンのネットワークを再起動し、念の為に IP アドレスを確認します。

```console:ノートパソコン
# systemctl restart systemd-networkd
# hostname -i
172.16.2.2 
```

上記の通りで IP アドレスが 172.16.2.2 なら OK でしょう。外部へのアクセスも確認。

```console:ノートパソコン
# ping -c2 archlinux.jp
PING archlinux.jp (160.16.119.98) 56(84) bytes of data.
64 bytes from tk2-235-27344.vs.sakura.ne.jp (160.16.119.98): icmp_seq=1 ttl=54 time=10.5 ms
64 bytes from tk2-235-27344.vs.sakura.ne.jp (160.16.119.98): icmp_seq=2 ttl=54 time=9.36 ms

--- archlinux.jp ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 9.362/9.942/10.523/0.589 ms
```

念の為に Web ブラウザで、キャッシュが効いてないはず（これ重要）の外部サイトにアクセスしてみます。 Google 等の検索サイトで適当なキーワードを検索してみるのが簡単でしょう。

また家庭内のサーバにもアクセスします。

## ```/etc``` のバージョン管理

家庭内IPアドレス体系を一新したら、ネットワーク関連の設定を書き換えます。
差し当たって現状では ```/etc``` バージョン管理を Subversion にしていてIPアドレスを直接指定しているので、これを変更します。

具体的には ```/etc``` をバージョン管理している全マシンで下記を実行。

```console:全マシン
# cd /etc
# svn relocate svn+ssh://172.16.0.3/etcmgr/$(hostname)/etc
```

## DHCP サーバ

デスクトップパソコンへ dhcpd をインストールする前に、アップグレードしておきましょう。
その後スナップショットを撮って、それからインストールします。

```console:デスクトップパソコン
# pacman -Syu
＜省略＞
# zfs snapshot tank/main@$(date +%Y%m%d_%H%M%S)_before_dhcpd   
# zfs list -t snapshot -o name -S name | head -n2
NAME
tank/main@20191206_151759_before_dhcpd
# pacman -S dhcp
＜省略＞
```

インストールに成功したら ```/etc``` を Subversion commit しときましょう。

```console
# cd /etc
# svn st  
M       .updated
?       dhcpd.conf
?       dhcpd6.conf
M       group
M       group-
M       gshadow
M       gshadow-
M       passwd
M       passwd-
M       shadow
M       shadow-
```

アカウントが増えている様子なので、ちょっと中身を確認。

```console
# svn di --diff-cmd diff -x -U0 group gshadow passwd shadow
Index: group
===================================================================
--- group       (revision 38)
+++ group       (working copy)
@@ -46,0 +47 @@
+dhcp:x:976:
Index: gshadow
===================================================================
--- gshadow     (revision 38)
+++ gshadow     (working copy)
@@ -46,0 +47 @@
+dhcp:!!::
Index: passwd
===================================================================
--- passwd      (revision 38)
+++ passwd      (working copy)
@@ -17,0 +18 @@
+dhcp:x:976:976:DHCP daemon:/:/usr/bin/nologin
Index: shadow
===================================================================
--- shadow      (revision 38)
+++ shadow      (working copy)
@@ -17,0 +18 @@
+dhcp:!!:18236::::::
```

```dhcp``` というユーザーとグループが追加されたようです。
それ以外は特別な変更は無さそうですので、このまま ```/etc``` を ```svn commit``` します。

```console
# svn st | grep "^?" | cut -b9- | xargs -I{} find {} -type f -or -type d -or -type l | xargs -t svn add
svn add dhcpd.conf dhcpd6.conf 
A         dhcpd.conf
A         dhcpd6.conf
# svn ci -m"installed dhcp"
Sending        .updated
Adding         dhcpd.conf
Adding         dhcpd6.conf
Sending        group
Sending        group-
Sending        gshadow
Sending        gshadow-
Sending        passwd
Sending        passwd-
Sending        shadow
Sending        shadow-
Transmitting file data ...........done
Committing transaction...
Committed revision 39.
```

いよいよ DHCP サーバを設定します。

参考文献：[dhcpd - ArchWiki](https://wiki.archlinux.jp/index.php/Dhcpd)

```/etc``` はバージョン管理しているので、盛大に書き換えましょう。

```console
# cat >dhcpd.conf <<___
> option domain-name-servers 172.16.0.1;
> option subnet-mask 255.255.0.0;
> option routers 172.16.0.1;
> subnet 172.16.0.0 netmask 255.255.0.0 {
>   range 172.16.3.2 172.16.3.254;
> }
> ___
# systemctl start dhcpd4
```

エラーが出てないので大丈夫と思いますが、一応、起動を確認。

```console
# systemctl status dhcpd4
* dhcpd4.service - IPv4 DHCP server
   Loaded: loaded (/usr/lib/systemd/system/dhcpd4.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2019-12-06 16:29:38 JST; 40s ago
  Process: 2456 ExecStart=/usr/bin/dhcpd -4 -q -cf /etc/dhcpd.conf -pf /run/dhcpd4/dhcpd.pid (code=exited, status=0/SUCCESS)
 Main PID: 2458 (dhcpd)
    Tasks: 1 (limit: 9519)
   Memory: 4.5M
   CGroup: /system.slice/dhcpd4.service
           `-2458 /usr/bin/dhcpd -4 -q -cf /etc/dhcpd.conf -pf /run/dhcpd4/dhcpd.pid

Dec 06 16:29:38 anju dhcpd[2458]: Wrote 0 leases to leases file.
Dec 06 16:29:38 anju dhcpd[2458]: 
Dec 06 16:29:38 anju dhcpd[2458]: No subnet declaration for enp0s25 (no IPv4 addresses).
Dec 06 16:29:38 anju dhcpd[2458]: ** Ignoring requests on enp0s25.  If this is not what
Dec 06 16:29:38 anju dhcpd[2458]:    you want, please write a subnet declaration
Dec 06 16:29:38 anju dhcpd[2458]:    in your dhcpd.conf file for the network segment
Dec 06 16:29:38 anju dhcpd[2458]:    to which interface enp0s25 is attached. **
Dec 06 16:29:38 anju dhcpd[2458]: 
Dec 06 16:29:38 anju dhcpd[2458]: Server starting service.
Dec 06 16:29:38 anju systemd[1]: Started IPv4 DHCP server.
```

イケたようなので、実際に利く所を見てみましょう。

無線LANルーターに内蔵されている DHCP サーバを切る…のも操作が面倒なので、私は物理的にケーブルを外しました。自室だと手を伸ばせば届く所に無線LANルーターがありまして、物理的な断線の方が早いんです:stuck_out_tongue_winking_eye:

それから、有線でつながっているクライアントマシンでネットワーク設定を再起動します。

```console:ノートパソコン
$ su
パスワード:
# systemctl restart systemd-networkd
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:22:68:1b:95:35 brd ff:ff:ff:ff:ff:ff
    inet 172.16.3.2/16 brd 172.16.255.255 scope global dynamic ens5
       valid_lft 42528sec preferred_lft 42528sec
    inet6 fe80::222:68ff:fe1b:9535/64 scope link 
       valid_lft forever preferred_lft forever
```

DHCP サーバの設定通り、IP アドレスは 172.16.3.2 になりました。

成功したので ```/etc``` を Subversion 登録します。

```console
# pwd
/etc
# svn st
M       dhcpd.conf
# svn ci -m"setting DHCP server"
Sending        dhcpd.conf
Transmitting file data .done
Committing transaction...
Committed revision 40.
```

これで、無線LANルーターが潰れたとしても、有線でつながっているLANの範囲はネットワークがきちんと機能する状態になりました！家庭内環境の高可用性への第一歩です。やったね！:thumbsup_tone2: