Raspberry Pi 4B+にAsterisk+FreePBX入りの公式イメージをインストールしてハマった話

みなさんこんばんわ。
アドベントカレンダーも終わり年末を迎えていますが、如何お過ごしでしょうか？

私は冬休みの宿題として記事を一本書こうと以前から計画していましたので実行します。
ネタは表題の通りです。

#概要
[以前の記事](https://qiita.com/hidekko/items/ddefadc9cc27afe1498f)でも書いたRaspberry Pi 4B+にAsteriskとFreePBXをインストールし、ひかり電話にスマートフォンを内線収容した話のインストール編になります。
実はインストール後のアップデートとディスク容量の拡張の2点でドハマりしてまして、解決はしたのですが方法が曖昧だったので年末に調べて記事にしようと思っていました。
昨日無事原因がわかり再現性のある解決策を見つけましたのでここでご報告です。
この記事を書くまでに記録しているだけで20回やり直しました。
[以前の記事](https://qiita.com/hidekko/items/ddefadc9cc27afe1498f)の環境を構築した際にも本記事と同様のポイントでハマったんですが、どうやって解決したか覚えておらず、本記事掲載のために検証環境を構築しました。
解決策は見いだせたのですが、結果として記事の掲載順序と実際の作業順序とが入れ違いになってしまいました。

#前提条件
表題にある**Asterisk+FreePBX入りの公式イメージ**が[RasPBXの公式サイト](http://www.raspberry-asterisk.org/)に上がっています。
RasPBXという団体はドイツのミュンヘンに本部のある有志のプロジェクトのようです。
ダウンロードするイメージは2021年12月30日時点での最新版がRasbian 10 BusterというOSで動作している2020年10月10日に公開されています。
今から1年以上前に作られたイメージなので、モジュール類はアップデートが必要です。
また[公式ドキュメンテーション](http://www.raspberry-asterisk.org/documentation/)でもまずはイメージ本体が4GBで作られているためそれ以上のサイズのSDカードを使っている場合はルートパーティ―ションの拡張を行いましょう、と案内されています。
公式の案内では最低要件として8GBのSDカードを挙げているのでルートパーティ―ションの拡張は必須作業になります。
実際にAsteriskとして動作させる前に以下の2点を行うことが必須でありかつ前提条件です。

**１．ルートパーティ―ションの拡張を行う**
**２．OSや各種モジュールのUpdateを行う**

なぜこの順序かというと、OSや各種モジュールのUpdateを行うにも現時点でOSで取り扱える領域が狭いとUpdate用のデータもダウンロードできません。
ですのでまずは領域拡張を行い、次にUpdateを行う、という手順になります。
前提条件も何も当たり前ですね。

#どこにハマったのか
はい。
前提条件に挙げた2つ、どっちもハマります。
順番に見ていきましょう。

##ハマりポイント１．ルートパーティ―ションの拡張
イメージをSDカードに書き込み、SSHで接続します。
私は基本的にヘッドレスインストールなので何も考えずにsshとwpa_supplicant.confファイルをboot配下に配置します。
RasPBXで公開されているイメージの初期のログインID、パスワードはRaspberry Pi財団公式のイメージと違っており、
root
raspberry
となっています。
ヘッドレスインストールを行ってSSHで接続します。
まぁRaspberry PiでかつRaspbianなんで、領域拡張は普通に考えて

```sh:
raspi-config
```
コマンドを実行し、[6 Advanced Options]から
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/89402238-b576-4f35-ad2c-0720d7ab1069.png)

[A1 Expand Filesystem]を選択して実行しますよね？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/136931ae-d8eb-b6f3-4280-cfcd58167c8f.png)

はい。
これでおかしくなります。
少なくともRaspberry Pi 4B+ RAM:8GB版ではおかしくなりました。
手元の3台で試しましたが全てで同じ現象が起きたので、同じ機種では同様の事象が起きる可能性が高いと思います。

###何がどうおかしくなるのか？
プロンプトが返ってきません。
何をしても反応がなくなります。
ICMP通信は返答があり、新たにSSHセッションを張ることもできますが、`raspi-config`を実行したSSHセッションの反応がなくなります。
新たに接続したSSHから`PS`で確認すると`raspi-config`は終わっておらず、領域拡張を実際に行っている`resize2fs`も実行しっぱなしになっています。
仕方が無いので再起動コマンドを実行すると正常に領域拡張が終っているように見えるのですが、やはり<font color="red">**領域拡張やフォーマットは完了しているのか？**</font>というシステムの根幹であり、信用に関する疑問を抱えたまま、無停止で動作し続けていることを前提とした音声システムを構築し運用し続けることは許容できません。
仮にプロンプトが返ってこないのが仕様だとしても、**何分待ったら処理が正常に終了しているのか？**という疑問の回答がでません。
`raspi-config`と相性が悪いのかと思い、`fdisk`を試しましたが結果は同じでした。
他のコマンドで

```sh:
parted
```

というコマンドがあるので、これでうまくいきました。
が、最終的にはこのコマンドでなく`raspi-config`で動作するようになるので早まって`parted`コマンドを実行して領域拡張しないでください。
しかし最終的な解決策にたどり着くまでは以下のように領域拡張を行っていました。

```sh:
parted /dev/mmcblk0
#以下、partedコマンド内で実行
p free
#p freeの結果、現在のパーティーション内容が出力されるので確認する
resizepart 2
#どのくらいの容量をresizeするのか聞いてくるので%表記で回答する
100%
#resize結果を出力して確認する
p free
#指定した領域が最初のp freeで確認したSDカードの残領域のすべてを割り当てられて拡張されていることを確認し、決定した上でpartedコマンドを終了する
q
```
`parted`コマンドはすぐに完了するので、

```sh:
resize2fs /dev/mmcblk0p2
```
を実行して領域拡張を行っていました。
この方法だとセッションが返ってこなくなったりコマンドが実行されっぱなしになることはありませんでした。
先ほども記載していますが、この方法は根本的な解決策ではありません。
しかし一つの叶えたい要望を満たす方法を複数知っていることは現場でとても役に立つことですし、少々面倒ですがこの方法で領域拡張を行っても問題ないと思います。
実際に私はpartedコマンドで領域拡張を行いました。

##ハマりポイント２．Update
はい。
これもハマります。
しかもこっちもハマりポイント１．の`raspi-config`のプロンプトが返ってこないのと同じで何分も何時間も待たされ、より悪いのは再起動すると**OSが壊れる**ことです。
まぁ普通に考えてUpdate中に再起動を行うとOSの一つも壊れますよね。
しかも処理が停止する部分が毎回同じで、カーネルを入れ替える部分です。
[前述の公式サイトのイメージダウンロード](http://www.raspberry-asterisk.org/downloads/)にある、公式推奨のUpdateコマンド、

```sh:
raspbx-upgrade
```
でコケますし、

```sh:
apt-get update
apt-get upgrade
```
でもコケますし、

```sh:
apt update
apt upgrade
```

でもコケます。
update時点でエラーが出ていたので回避のためにオプションを付けてみました。
それでも

```sh:
apt-get update　--allow-releaseinfo-change
apt-get upgrade
```
でコケて

```sh:
apt update　--allow-releaseinfo-change
apt upgrade
```
でもコケます。

他にもaptの証明書期限切れに関するエラーもupdate時点で出るので、このエラーも解消するために

```sh:
apt-key list
```
を実行してexpired(期限切れ)とある証明書のフィンガープリントの下から16桁を確認し、以下のコマンドを実行します。

```sh:
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys xxxxxxxxxxxxxxxx
```

これでupdate時点でエラーがでなくなるので、最終的に

```sh:
#証明書期限切れのフィンガープリント確認
apt-key list
#期限が切れていた証明書を更新
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys xxxxxxxxxxxxxxxx
apt-get update --allow-releaseinfo-change
apt-get update -y
```
となるのですが、それでもコケます。
もちろん

```sh:
apt-key list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys xxxxxxxxxxxxxxxx
apt update --allow-releaseinfo-change
apt update -y
```
でもコケます。

しかもコケるまでにまだエラーが・・・
なんかどうもaptの参照先が怪しいっぽいので、


```sh:
mv /var/lib/apt/lists /var/lib/apt/lists_org
```
でaptの参照先をリネームして`apt update`コマンド実行時に自動で再作成させます。

はい。
ここまで準備して

```sh:
mv /var/lib/apt/lists /var/lib/apt/lists_org
apt-key list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys xxxxxxxxxxxxxxxx
apt update --allow-releaseinfo-change
apt update -y
```
エラーは消えましたが・・・それでもコケます。
もはやどうあってもコケます。

はい。
コケ倒してますね。
見事にハマってます。

本記事では省略していますが`sudo`有りとか無しとか、デフォルト設定だとrootでログインしてて`sudo`不要なんで一般ユーザ作ってsudoersに作ったユーザをツッコんでってわざわざ`sudo`付けなアカン状況作り出したり、色々試行錯誤しました。

しかもコケる場所に行きつくまでに結構時間がかかるんですよね。
時間がガンガン溶けていきました。

###どうコケてたの？
はい。
画像が無かったのでコマンドっぽい表記になってしまいますがご容赦くださいね。

```sh:
進捗: [ 63%] [#######################################################################################################.............................................................] libpython3.7-minimal:armhf (3.7.3-2+deb10u3) を設定しています ...
raspberrypi-kernel (1:1.20211201~buster-1) を設定しています ...
'rpikernelhack による /boot/kernel.img から /usr/share/rpikernelhack/kernel.img への退避 (divert)' を削除しています

進捗: [ 63%] [#############################################################################################.......................................................]
```

・・・いや、もうね・・・ホンマ、63%まで毎回待つんですよ・・・
・・・記録してるだけで20回待ったんですよね・・・
しかもこれ`apt-get upgrade`や`apt upgrade`まで行きついてからコケるんで、その前にある`apt-get update`も`apt update`もめっちゃ時間かかるんですよ。
うちの回線がなんと<font color="red">**100Mbps**</font>で、かつRaspberry Pi設置位置と無線LANアクセスポイントの位置関係から電波状況が芳しくないのがコケるに至るまでに時間がかかる原因なんで、一概にコケ倒すから悪いんだとも言えないんです。
言えないんですが・・・それでも・・・

まぁインフラエンジニアあるあるですね。
こういうのも楽しめる(めげない？)のもインフラエンジニアを長く続ける特性なのかなと思ったりもしています。

いや、ホンマにマジで時間かかりました。
三日くらい、それもほとんど寝ずにやって原因を見つけたので結構やったった感はあります。
ここまでマニアックになるとGoogle先生でも答えてくれないんですよね。
検索方法が悪い、という可能性も捨てきれませんが・・・

###で、コケてる原因はなんなん？
元々以前の記事を書いた時点でupdateもupgradeも終わっている奇跡の筐体(検証機と同じRaspberry Pi 4B+ RAM:8GB)があったので見比べてみました。
コケてる個所からカーネルが原因なんでしょ？ってのは思ってたんで(Qiitaなんでライトな表現ですが、仕事だと仰々しく**被疑箇所**なんて言い方してます)調べる箇所は決まっています。
奇跡の筐体と検証用の筐体とで、以下のコマンドを実行して動作しているカーネルバージョンを確認します。

```sh:
uname -a
```

結果、検証用の筐体

```sh:
Linux raspbx 5.4.51-v7l+ #1333 SMP Mon Aug 10 16:51:40 BST 2020 armv7l GNU/Linux
```
奇跡の筐体

```sh:
Linux raspbx-rabp4b 5.10.63-v8+ #1455 SMP PREEMPT Mon Sep 20 17:10:42 BST 2021 aarch64 GNU/Linux
```
はい。
ご覧の通りカーネルバージョン違います。
奇跡の筐体は直近でもカーネルバージョンアップしてますね。
確かに記憶はあったんですよね。
**RasPBXのイメージだと32bitなんで、RAMが8GB搭載していると4GBまでしか認識しないだろうから64bit化しておこう**と思って実施した記憶が。
ただ奇跡の筐体を作った当時、2020年10月か11月だったんですが、同じようにこの問題にハマってトラブルシュート中に64bit化を思いつき、他にも色々脱線して色々やっててなんかようわからん間にこのエラーが解消していました。
なのでカーネルの64bit化と今回のハマりポイント１．２．の解決策がリンクしていなかったんですよね。
64bit用のカーネル落としてきた記憶もぼんやりあるんですが、当時のログを見ても64bit化のログが出てきませんでした。


##解決策
何気なく

```sh:
ls /boot
```
を実行してみると、64bit版カーネルは実装されていました。
ですので後は64bitカーネルで起動するだけで済みます。
/boot/config.txtに1行
`arm_64bit=1`
と追加するだけでいいので、viやvimで開いて手動で追記しても良かったんですが、~~viがデフォルトだとそのまま使えなくて、使えるように作業するのが邪魔くさかった~~「作業ミスを減らす」という尤もらしい、かつ歴戦のインフラエンジニアっぽく見せる為に、ここでは敢えてコマンドで記載します。

```sh:
echo "arm_64bit=1" >> /boot/config.txt
cat /boot/config.txt
```

はい。
お目当てのコマンド実行後に変更が反映されているか`cat /boot/config.txt`で確認します。
歴戦のインフラエンジニアっぽくなりましたかね。
この変更を反映させるために再起動が必須なので、最終的にはこうなります。

```sh:
cat /boot/config.txt
echo "arm_64bit=1" >> /boot/config.txt
cat /boot/config.txt
reboot
```

最初に念のため`cat /boot/config.txt`で64bitで動作するフラグが立っていないか確認しています。
どうですか？
インフラエンジニアっぽいでしょ？
~~なんならif文とかで64bitフラグの有無確認するところまで作ってシェルスクリプト化しちゃいます？~~

はい。
無事再起動したら念のため`uname -a`でデフォルトで起動しているカーネルから変更されていることを確認します。
カーネルが変更されていたら後は[前提条件](https://qiita.com/hidekko/items/1f819cc91b23e184cd22#前提条件)に記載した通りの段取りで作業を行います。
これでハマりポイントを克服し、`raspi-config`での領域拡張もコケませんし、`apt upgrade`も63%でコケません。

参考として、私が実際に実行した手順を記載します。
一部`raspi-config`を使って操作している部分はコメントをご覧ください。

初回ログオン時。
Time Zone変更と64bit化を行う。

```sh:
date
cat /etc/*release*
uname -a
free
df -h
raspi-config
##4Localization Option内のロケール設定からログの時刻をわかりやすくするため、まずはTime Zoneを日本(Asia/Tokyo)に合わせる
date
echo "arm_64bit=1" >> /boot/config.txt
date
cat /boot/config.txt
reboot
```
2回目のログオン。
領域拡張とロケール設定変更

```sh:
date
cat /etc/*release*
uname -a
free
df -h
date
sudo parted /dev/mmcblk0
#ここからpartedコマンド内での操作
p free
resizepart 2
100%
p free
q
#ここまでpartedコマンド内での操作
df -h
date
sudo resize2fs /dev/mmcblk0p2
date
df -h
date
apt install locales-all
#この直後の処理でコケてしまうことを防止するために予めlocalesetを全てインストールしておく
date
sudo raspi-config
##4Localization Option内のロケール設定から言語と国をja_jp、文字コードをUTF8、キーボードレイアウト、WLANをJPにそれぞれ日本語化
date
reboot
```
3回目のログオン。
Updateを行う。

```sh:
date
sudo cat /etc/*release*
uname -a
free
df -h
date
sudo apt-key list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys xxxxxxxxxxxxxxxx
sudo apt-key list
date
mv /var/lib/apt/lists /var/lib/apt/lists_org
sudo apt update --allow-releaseinfo-change
sudo apt update -y
date
apt full-upgrade -y --fix-missing
date
apt autoremove -y
date
apt clean
date
reboot
```


本日はここまで。

それではみなさん、良いお年を。