Dockerインストール時のdpkgエラー

# はじめに

RaspberryPi4 ModelBにDockerを入れようとした際に`E: Sub-process /usr/bin/dpkg returned an error code (1)`というエラーが発生したため、このエラーの内容を調べた話です。

## 環境

- OS: Raspbian GNU/Linux 10 (buster)
- arch: armv7l

# やったこと

## Dockerインストール

Docker公式のインストールスクリプトを使用してDockerのインストールを試みます。

```
$ curl -sSL https://get.docker.com | sh
# Executing docker install script, commit: 0e685c6ac0bddd7b2ba7bcaaeb519746ad249a29
+ sudo -E sh -c apt-get update -qq >/dev/null
[sudo] password for crow:
+ sudo -E sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sudo -E sh -c curl -fsSL "https://download.docker.com/linux/raspbian/gpg" | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
gpg: WARNING: unsafe ownership on homedir '/home/crow/.gnupg'
+ sudo -E sh -c echo "deb [arch=armhf signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/raspbian buster stable" > /etc/apt/sources.list.d/docker.list
+ sudo -E sh -c apt-get update -qq >/dev/null
+ sudo -E sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends  docker-ce-cli docker-ce >/dev/null
E: Sub-process /usr/bin/dpkg returned an error code (1)
```

ここで、`E: Sub-process /usr/bin/dpkg returned an error code (1)`というエラーが発生しています。

`docker -v`を実行してみます。

```
$ docker -v
Docker version 20.10.8, build 3967b7d
```

どうやらインストール自体は成功している様子です。

では、`docker.service`は正常に動作しているのか確認します。

```
$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Thu 2021-08-12 01:40:44 BST; 9min ago
     Docs: https://docs.docker.com
  Process: 6380 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/
 Main PID: 6380 (code=exited, status=1/FAILURE)
```

`Active: failed`となっており、少なくとも正常起動はできなかったとわかります。
ここで、サービスのrestartを試みるもstatusはfailedのままでした。

なお、インストールスクリプトを使用せずに手動でリポジトリ設定を行う方法も試行しましたが、結果は同じでした。

## 困ったときの再起動

`reboot`コマンドにより、一旦マシンを再起動してみます。
その後、`docker.service`の動作を確認します。

```
$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2021-08-12 02:05:10 BST; 2min 28s ago
     Docs: https://docs.docker.com
 Main PID: 559 (dockerd)
    Tasks: 10
   CGroup: /system.slice/docker.service
           └─559 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
```

何故か動いています。

`hello-world`コンテナの実行も試行します。

```
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2c7ed585684a: Pull complete
Digest: sha256:0fe98d7debd9049c50b597ef1f85b7c1e8cc81f59c8d623fcb2250e8bec85b38
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm32v7)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

どうやら正常に動作したようです。

## dpkgのエラーを片付ける

さて、dockerが動くようにはなりましたが、冒頭に発生した`E: Sub-process /usr/bin/dpkg returned an error code (1)`というエラーが気にかかります。

`dpkg --audit`というコマンドにより、どこでコケたのかの確認ができるようです。

```
$ sudo dpkg --audit
The following packages are only half configured, probably due to problems
configuring them the first time.  The configuration should be retried using
dpkg --configure <package> or the configure menu option in dselect:
 docker-ce            Docker: the open-source application container engine
```

docker関連のパッケージであることは察していたのですが、`docker-ce`がエラーを吐いたとわかります。
このままだと、今後のパッケージ管理に支障をきたす恐れがあるため、このエラーを片付けておきます。

本来なら設定ファイルを消し飛ばしたりするところなのですが、dockerが正常に動作するようになったことですし、恐らく再設定を走らせるだけで成功するのではという目算を立てます。

パッケージ設定を行うには`dpkg --configure <package>`というコマンドを使用するようです。

```
$ sudo dpkg --configure docker-ce
Setting up docker-ce (5:20.10.8~3-0~raspbian-buster) ...
```

この後、再度`dpkg --audit`を実行します。
何も出力されなければ、設定は正常に行われています。

## 解決法、というか今回のオチ

インストールにコケたら悩む前に取り敢えず再起動すれば動く場合がある。
とはいえ、インストールにコケたらパッケージ管理の設定をやり直そう。

# おまけ

~~記事執筆中に予想外の解決をしてしまったので、~~これ以降の内容は記事執筆前、実際に筆者がハマった際に行ったものとなります。
前述の方法で解決できる以上、ここから下は的外れな作業にはなるのですが、お時間のある方は生暖かい目でご覧いただければ幸いです。

## その他試したこと

### dpkgによる設定の再試行

`E: Sub-process /usr/bin/dpkg returned an error code (1)`というエラーに着目して、dpkg周りのエラーを調べます。
`dpkg --audit`コマンドにより、どこでコケたのか確認します。

```
$ sudo dpkg --audit
The following packages are only half configured, probably due to problems
configuring them the first time.  The configuration should be retried using
dpkg --configure <package> or the configure menu option in dselect:
 docker-ce            Docker: the open-source application container engine
```

`docker-ce`が`only half configured`であることから、インストール時のパッケージ設定に失敗していることがわかります。
再設定のため、`/var/lib/dpkg/info`配下の`docker-ce`関連の一部のファイルを削除します。

- `/var/lib/dpkg/info/docker-ce.postinst`
- `/var/lib/dpkg/info/docker-ce.postrm`
- `/var/lib/dpkg/info/docker-ce.prerm`

その後、`dpkg --configure docker-ce`コマンドにより再設定を行います。

### `nftables`のインストール

dockerdのエラーをjournalctlで確認したところ次のようなログが記録されていました。

```
$ sudo journalctl --no-pager | grep 'failed to start daemon'
Aug 11 16:58:04 dandelion.crow31415.net dockerd[5753]: failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables/1.8.2 Failed to initialize nft: Protocol not supported
```

後半のiptables及びnftablesのエラーから、debian 10(buster)にてiptablesがnftablesに置き換えられた件が関係しているのではないかと考えられます。
よって、`nftables`のインストールを行います。

それでも結果が変わらなかったため、更新のためにマシンごと再起動することにしました。
この結果正常に動作するようになりました。
~~なので、nftablesが原因で動いていなかったものと勘違いしていました。~~

# 参考
[dpkgやapt-get関連でエラーが出た時の対処法 - Qiita](https://qiita.com/yukari-n/items/d1b17bd37036f120153c)
[Raspbianをbuster化したら、iptablesでちょっとだけハマる - Soukaku&#039;s HENA-CHOKO Blog](https://www.downtown.jp/~soukaku/archives/2019/0728_185332.html)