【作業メモ】ラズパイ3ubuntu serverをインストールしてpython開発環境を構築

# 概要
自宅のラズベリーパイ３にubuntu serverをインストールして、pythonを使えるようにして、flaskアプリを起動するようにしたので、同じことをやりたいときのための作業メモ。

# ubuntu serverのインストール
## OSの選定
raspbianとubuntu serverで迷ったが、Web上の情報量の多さからubuntuのほうが何かと使いやすそうだと判断し、ubuntu serverを選択した。昔はraspbianしか使ったことなかったが、最近はubuntuも公式でraspberrypiへのインストールにしたらしいので。

デスクトップは不要なので、ubuntu desktopではなく、ubuntu serverを選択した。

軽く調べた感じ、デスクトップを使わないならubuntu server on ラズパイ3は、重たいということはなさそう。

## SDカードへの焼き込み

[raspberrypi imager](https://www.raspberrypi.com/software/)を使った。環境はmac（M1)。昔はddコマンドでやっていたが、GUIでできるのでこちらのほうが便利そうだった。

やり方は以下を参考にした。
https://qiita.com/RYO_/items/eb008b44363dbec8b6f0

基本、GUIから直感的に操作可能だった。
ubuntuのバージョンは24.04 LTSを選択した。
「SSHを有効化：パスワード認証を行う」は別タブにあるので注意。

上記参考ページでは、OS Customizationをすると不具合が生じたと記載されているが、今回のトライでは問題なく、成功した。

## 初回ログイン
SDイメージの焼き込みが完了したらラズパイ3ハードに挿して、電源に繋いだ。
WiFiの設定もSDカードへの焼き込み時に済んでいるので、同じWiFiに繋いだPCから、初期設定した`ユーザ名@ホスト名`でsshをした。問題なくログインできた。

# ラズパイ初期設定
sshのあと、必要なソフトウェアなどのインストールや各種設定をする。
## git

インストール

```
sudo apt-get update
sudo apt-get install git
```

gitのインストールで以下のエラーが発生した。

```
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2483 (unattended-upgr)
N: Be aware that removing the lock file is not a solution and may break your system.
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
```

検索するとlockファイルを削除すると解決したという記事がいくつか見つかったので試してみたが、改善しなかった。

エラーメッセージに`Be aware that removing the lock file is not a solution and may break your system.`と書いてあったのでlockファイルは削除しないほうが良かったかもしれない。反省。

process 2483はunattended-upgrというプロセスで、パッケージを自動更新しているらしい。
10分ほどまったら、2483のprocessがなくなった。

再度、apt-getでgitをインストールすると、成功した。ただ`git is already the newest version (1:2.43.0-1ubuntu7.1).`というメッセージが表示されており、gitはすでにインストール済みだったらしい。最初からインストール済みだったのか、エラー改善の試行錯誤の何処かでインストールされていたのかは不明。

ユーザの設定

```
git config --global user.name [任意のユーザ名]
git config --global user.email [任意のユーザ名]
```

参考
https://qiita.com/tommy_g/items/771ac45b89b02e8a5d64

## uvのインストール
pyenvとuvでpython環境を作ることにした。

uvはpipでもインストールできるがpythonのバージョンに依存させたくなかったので、直接インストールした。

```
curl -LsSf https://astral.sh/uv/install.sh | sh
```

パスを追加。ホームに.bashrcと.zshrcがあるが、今回インストールしたubuntu serverではbashを使っているっぽいので、.bashrcに追加する。

現在のシェルの確認。

```
echo $SHELL
```

```
/bin/bash
```

.bashrcに追加しようと思ったが、すでに末尾に`. "$HOME/.cargo/env"`追加済みだった。
念の為、再ログインしてuvコマンドが使えるか試したところ使えそうだったので、.bashrcの編集は不要と判断した。

## pyenv
以下を参考にpyenvをインストールした。
https://zenn.dev/tsaeki/articles/bc868a8d8fd6ae

```
sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```

```
curl https://pyenv.run | bash
```

参考記事のパスの追加先を.zshrcから.bashrcに変更した。

```
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

source .bashrc
```

## python
pyenvを使って、とりあえずpython 3.12をインストール。

```
pyenv install 3.12
```

3.12.5がインストールされたので、それをグローバルで使うように設定した。

```
pyenv global 3.12.5
```

## flaskサーバの実行
詳細は省略するが、flaskサーバを自作してgitにアップロードし、ラズパイからclone。
仮想環境を作成して、flaskサーバを実行。
そこに同一ネットワークの別PCからアクセスできることを確認。

## systemdサーバ自動起動の登録
前小節で作成したflaskサーバをsystemdで自動起動する。

`/etc/systemd/system`に拡張子`.system`のファイルを作成。
記述内容の例

```
[Unit]
Description=description
After=network.target

[Service]
Type=simple
WorkingDirectory=/path/to/app-dot-py-dir
ExecStart=/path/to/app-dot-py-dir/.venv/bin/python /path/to/app-dot-py-dir/app.py

[Install]
WantedBy=multi-user.target
```

以下、動作確認

有効化
```
sudo systemctl daemon-reload
```

起動
```
sudo systemctl start yourapp
```

停止

```
sudo systemctl stop yourapp
```

動作確認終了。
続いて、OS起動時に自動実行されるようにする。

```
sudo systemctl enable yourapp
```

もし無効化したい場合は以下。

```
sudo systemctl disable yourapp
```

参考
https://qiita.com/__deracio__/items/4f50a5c2585fc742a10b

## ネットワーク設定
何度か再起動をしていたらいつの間にかipv4アドレスを無線で取得できなくなっていた。
sshやブラウザからwebサーバへのアクセスにホスト名を用いていたが、ホスト名の名前解決がsshではできるのに、ブラウザからはできなくなったので気付いた。またwebサーバにlocalhostからもアクセスはできていた。

`ip addr show`でwlan0の項目を見ると、link-localがipv6は取得できているのに、ipv4は取得できていなかった。link-localはローカルネットワーク用のipアドレスらしい。また`ping google.com`がうまく実行できないことからインターネットアクセスもできていなさそうだった。

何らかの理由で自宅のwifiルータへの接続に失敗し、リカバリとして、ipv6のlink-localだけは取得できていた、という状況らしい。

ルータの設定は、DHCPの割当数には余裕があり問題なさそうだった。また、/etc/hostnameや/etc/hostsなども見たが特に問題なさそうだった。

ChatGPTのアドバイスに従って、`/etc/netplan/50-cloud-init.yaml`を編集した。wlan0のlink-localの行だけ追記した。

```/etc/netplan/50-cloud-init.yaml
network:
    version: 2
    renderer: networkd
    wifis:
        wlan0:
            dhcp4: true
            link-local: [ipv4]
            access-points:
                "my-ssid-name":
                    password: "..."
            optional: true
```

```
sudo netplan apply
```

上記コマンドを実行するとネット接続が切れた。
再度別ターミナルからsshして、`ip addr show`をするとipv4のアドレスが取得できていた。
また`ping google.com`やブラウザからの名前解決も成功するようになった。


# おわりに
raspberrypi imagerのおかげで昔より楽にできた印象があります。