OpenRC から systemd に移行する

Gentoo Linux に systemd をインストールする方法です。
systemd がプロファイルに登録されてはいますが、デフォルトの状態 (OpenRC環境) からの移行に若干コツが必要です。
システム設定は記事の範囲外 (気が向けば記事を書くかも) ですが、sshd が動かせる程度の設定はこの記事内で扱います。
設定は x86-64、ARM (Raspberry Pi) で確認しています。他でも、systemd がサポートしているアーキテクチャなら動くんじゃないかな？

## 作業を開始する前に

移行作業は、できればローカル接続環境で行うことを推奨します。リモート接続でも作業を行えますが、systemd は OpenRC で行ったネットワーク設定を引き継いでくれないため、設定ミスによって接続できなくなる恐れがあります。また、ネットワーク以前に、そもそもうまく立ち上がってくれない場合に備え、Gentoo インストールメディアも用意しておくと精神衛生上安らかに作業を行えます。


## 概要

 1. プロファイルを systemd を含むものに変更する。
 2. 必要ならばカーネルを再構築しておく。
 3. sys-fs/udev をアンインストールする (`emerge -C sys-fs/udev`)
 4. パッケージをインストール する(`emerge -uDN world`)。
 5. カーネル起動オプションに `init=/usr/lib/systemd/systemd` を追加する。
 6. (オプション) 次回起動時に sshd が起動できるように、ネットワーク、sshd 起動設定をする。

## プロファイル変更

`eselect profile` を使います。

    # eselect profile list
    Available profile symlink targets:
      [1]   default/linux/amd64/13.0 *
      [2]   default/linux/amd64/13.0/selinux
      [3]   default/linux/amd64/13.0/desktop
      [4]   default/linux/amd64/13.0/desktop/gnome
      [5]   default/linux/amd64/13.0/desktop/gnome/systemd
      [6]   default/linux/amd64/13.0/desktop/kde
      [7]   default/linux/amd64/13.0/desktop/kde/systemd
      [8]   default/linux/amd64/13.0/desktop/plasma
      [9]   default/linux/amd64/13.0/desktop/plasma/systemd
      [10]  default/linux/amd64/13.0/developer
      [11]  default/linux/amd64/13.0/no-multilib
      [12]  default/linux/amd64/13.0/systemd
      [13]  default/linux/amd64/13.0/x32
      [14]  hardened/linux/amd64
      [15]  hardened/linux/amd64/selinux
      [16]  hardened/linux/amd64/no-multilib
      [17]  hardened/linux/amd64/no-multilib/selinux
      [18]  hardened/linux/amd64/x32
      [19]  hardened/linux/musl/amd64
      [20]  hardened/linux/musl/amd64/x32
      [21]  default/linux/uclibc/amd64
      [22]  hardened/linux/uclibc/amd64

上記の実行例では、5、7、9、12 に systemd が含まれています。
利用するデスクトップ環境に合わせて選択して下さい。デスクトップ環境が不要なら、デスクトップ環境が含まれていないもの (上記例では 12) を選びます。

    # eselect profile set 12

## カーネル再構築

カーネルを構築するにあたり、オプションを2点チェックしておきます。

 - Gentoo Linux -> Support for init systems, sistem and service managers -> systemd にチェックを入れる。
   
   ![kernel-enable-systemd.png](https://qiita-image-store.s3.amazonaws.com/0/108915/64df2522-2284-d35e-6d9b-5516d8a187b9.png)

 - Device Drivers -> Generic Driver Options -> path to uevent helper を空文字列にする (デフォルトでは /sbin/hotplug となっています)
   
   ![kernel-empty-uevent-helper.png](https://qiita-image-store.s3.amazonaws.com/0/108915/72c095c0-5021-67c3-e3b8-01eeee905dfc.png)

これらの設定を行い、カーネルの再構築・インストールを行っておきます。既に上記の通りであれば再構築の必要はありません。

### (genkernel 移行)
sys-kernel/genkernel を利用している場合は、代わりに sys-kernel/genkernel-next を使う必要があるそうです。プロファイルを切り替えると、sys-kernel/genkernel がマスクされます。普段使っていないので、両者がどう異なるのかはよく分かっていません。

    # emerge --depclean -a sys-kernel/genkernel   (もしかすると --depclean ではなく -C の必要があるかも)
    # emerge -tva sys-kernel/genkernel-next

## sys-fs/udev アンインストール
**注意: ここから先の作業は、一度行ってしまうと、元に戻すか、systemd 移行を完了しなければ正常に起動できなくなります。慎重に。**

sys-fs/udev をアンインストールします。これを行わないと、systemd 関連パッケージと衝突してブロックが発生してしまいます。

    # emerge -Ca sys-fs/udev

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

通称うどんワールド (-tva を付けるのは筆者の趣味)。これで systemd 一式が導入と関連パッケージのリビルドが行われます。

    # emerge -tvauDN world


## 起動パラメータ設定
カーネルの起動パラメータに `init=/usr/lib/systemd/systemd` を追加します。

### GRUB2 の場合

/etc/default/grub の GRUB_CMDLINE_LINUX_DEFAULT に起動パラメータを追加します。

```ini:/etc/default/grub
# ...
GRUB_CMDLINE_LINUX_DEFAULT="init=/usr/lib/systemd/systemd (今まで設定していたオプション...)"
# ...
```

設定ファイルを編集したら、 `grub2-mkconfig` を実行します。

    # grub2-mkconfig -o /boot/grub/grub.cfg

### Raspberry Pi の場合

第1パーティション (/dev/mmcblk0p1) 直下の cmdline.txt に起動パラメータ `init=/usr/lib/systemd/systemd` を追加します。

```text:cmdline.txt
init=/usr/lib/systemd/systemd (今まで設定していたオプション...)
```


以上で systemd 環境が最低限立ち上がる環境は構築できました。しかし、このままではネットワーク接続もできません。リモートで作業しているのなら、次の再起動で詰みます。
再起動前に、以下の設定を行うことで、次回以降の起動時に IP アドレスが設定され、 sshd が有効になります。

## (オプション) ネットワーク設定

ここでは、基本的な設定のみ記述します。
VLAN 設定、ブリッジ設定、ルーティングのスコープ設定など複雑な設定が必要な場合は、 man systemd.network や man systemd.netdev を参照しつつ設定して下さい。[Arch Wiki の systemd-networkd 解説記事](https://wiki.archlinuxjp.org/index.php/Systemd-networkd) も参考になります。

### 設定ファイル

大体、OpenRC のひとつのインターフェイスに対応する一連の \*_*(インターフェイス)*=... が、systemd の設定ファイルの1ファイル (\*.network 、場合によっては \*.netdev にも) に対応します。

#### 例1: DHCP によるアドレス設定
OpenRC では、以下のような設定になっていたとします。

```bash:/etc/conf.d/net
config_eth0="dhcp"
```
systemd (systemd-networkd) では、以下のようになります。

```ini:/etc/systemd/network/eth0.network
[Match]
Name=eth0

[Network]
# DHCPv6 が不要なら both の代わりに v4 とする。
DHCP=both
```

#### 例1.5: eth* をまとめて DHCP 設定
OpenRC では多分できない設定。(とはいえ、DHCP がデフォルトでしたっけ？)

```ini:/etc/systemd/network/eth0.network
[Match]
# ethから始まるインターフェイスすべてにこのファイルの設定を適用する。
Name=eth*

[Network]
DHCP=both
```


#### 例2: 静的アドレス設定
OpenRC では、以下のような設定になっていたとします。[^net-example]

[^net-example]: 複数アドレスや複数ルーティングを1ファイルに収めたかったため、かなり無茶な例に。これ、普通は別インンターフェイスに分けるか VLAN 切るよなぁ……

```bash:/etc/conf.d/net
config_eth0="192.168.1.1/24 10.1.2.1/16"
routes_eth0="default via 192.168.1.254
10.2.0.0/24 via 10.1.0.254"
dns_servers_eth0="192.168.1.100 192.168.1.101"
domains_eth0="example.com"
```

systemd (systemd-networkd) では、以下のようになります。

```ini:/etc/systemd/network/eth0.network
[Match]
Name=eth0

[Network]
DHCP=none
DNS=192.168.1.100
DNS=192.168.1.101
Domains=example.com

[Address]
Address=192.168.1.1/24

[Address]
Address=10.1.2.1/16

[Route]
Gateway=192.168.1.254

[Route]
Destination=10.2.0.0/16
Gateway=10.1.0.254
```

### 設定ファイルの内容について

 - ファイルパス: /etc/systemd/network/ に置きます。
 - ファイル名: *(好きなファイル名)*.network とします。今回は eth0.network としました。
 - `[Match]` セクション: どのインターフェイスに対する設定なのかを記述します。ここではデバイス名 (`Name`) で指定しましたが、MAC アドレス等による指定も行えます。また、ワイルドカード (`*`) も使えます[^glob]。
 - `[Network]` セクション: DHCPやDNSの設定を記述します。
 - `[Address]` セクション: 割り振る IP アドレスを記述します。複数の IP アドレスを設定したい場合は、例のように複数回記述します。また、IP アドレスがひとつだけなら、`[Address]` セクションを記述せずに、 `[Network]` セクションに `Addres=` を含めることもできます。
 - `[Route]` セクション: ルーティング設定を記述します。これも `[Address]` セクションのように複数回記述できます。また、デフォルトゲートウェイひとつだけなら、`[Route]`セクションを記述せずに、`[Network]` セクションに `Gateway=` を含めることもできます。

[^glob]: 正確には、シェルの glob のパターンが使えます。

最後に、上記設定に従った resolv.conf は、/run/systemd/resolve/resolv.conf にできるので、 /etc/resolv.conf をシンボリックリンクにしておきます。

    # rm /etc/resolv.conf
    # ln -s /run/systemd/resolve/resolv.conf /etc/

### ネットワーク関連サービス有効化

次回起動時にネットワーク関連の設定がされるように、 systemd-networkd サービスと systemd-resolved サービスを有効化します。
本来、サービス有効化には `systemctl` コマンドを利用しますが、 `systemctl` コマンドは、システムが systemd で起動していなければ仕事をしてくれません。システムはまだ OpenRC 上で動いているので、`systemctl` が行うことを手動で行います。

    # cd /etc/systemd/system/multi-user.target.wants
    # ln -s ../../../../usr/lib/systemd/system/systemd-networkd.service
    # ln -s ../../../../usr/lib/systemd/system/systemd-resolved.service

## (オプション) sshd 設定
/etc/ssh/sshd_conf の設定は端折ります。大体デフォルトで大丈夫でしょ？ `PermitRootLogin` は `no` にしといた方がいいかな？
というわけで、ここでやるべきことはサービスを有効化するだけ。 

### sshd サービス有効化
これもネットワーク関連サービスと同様に、手動でサービスを有効化します。

    # cd /etc/systemd/system/multi-user.target.wants
    # ln -s ../../../../usr/lib/systemd/system/sshd.service