[メモ] Raspberry Pi ZeroをUSBケーブル一本でインターネット接続！(nfs使用、SDカード・キーボード・マウス・モニター必要なし)

## 概要
- Raspberry Pi ZeroをUSBケーブル一本でインターネット接続
- SDカード不要
- NFSでroot(`/`)をマウントするので、NFSサーバ側をVirtualBoxのUbuntu20.04にて設定する。
- たまに、NFSマウントが失敗するっぽい(タイミング?)ので、モニターを接続してみたほうがよいかも?


- 参考: [HOW TO RUN OR BOOT RASPBIAN ON A RASPBERRY PI ZERO WITHOUT AN SD-CARD](https://dev.webonomic.nl/how-to-run-or-boot-raspbian-on-a-raspberry-pi-zero-without-an-sd-card)<br>というかそのまま、Buster向けで確認したくらい




## 環境
- Windows 10 (1909) 64bit 
- Virtualbox 6.1.6 + ExtensionPack
- Vagrant 2.2.9
    - `ubuntu/focal64` (Ubuntu 20.04) | `IP: 10.42.0.1/24`
- RPi Zero (Wでもいけるはず?)
    - Raspbian: `2020-02-13-raspbian-buster-lite`
    - `IP: 10.42.0.14/24`

## 手順
### 仮想環境のインストール

1. PowerShellを管理者で起動　(Win+x, a, ALT+y)
2. Chocolatey インストール　( https://chocolatey.org/install)

    ```powershell:コピペ
    Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
    ```
3. Virtualbox + Extensionインストールして、ピン止め(勝手にバージョンアップさせない)

    ```powershell
    #choco pin remove --name virtualbox
    #choco uninstall  -y virtualbox -x
    cinst -y virtualbox --params "/ExtensionPack /NoQuickLaunch /NoRegister /NoPath"
    choco pin add    --name virtualbox
    ```

4. vagrant他 インストール

    ```powershell
    cinst -y vagrant vscode
    ```
    - (Hostキーの設定)右Ctrlがないキーボードの場合、一度、Virtualboxを起動して、メニュー > File > Preferences... > Input > [Virtual Machine] の Host Key Combination で、ほかのキー(例: 右Alt)にする。<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/a4b23a37-5f7a-915f-8f40-68127b63d464.png)


5. 一度、ホスト機(Windows10)再起動して、再度、PowerShellを管理者で起動
6. vagrantのプラグインインストール

    ```powershell
    vagrant plugin install vagrant-vbguest
    vagrant plugin install vagrant-disksize 
    ```
7. `exit`で終了

### 仮想機(VMゲスト)の準備
1. PowerShellを普通に起動　(Win+x, i)
2. 作業フォルダ: C:\Vagrant\u20 を作って(`> mkdir C:\Vagrant\u20`) 、移動('> cd C:\Vagrant\u20`)
3. VSCodeで、以下の`Vagrantfile`を作成(`> code C:\Vagrant\u20\Vagrantfile`).<br>ついでにプラグインを入れる<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/3817fecb-f4e0-65ee-d19d-4dce4078da26.png)

    ```rb:Vagrantfile
    # -*- mode: ruby -*-
    # vi: set ft=ruby :

    VB_NAME="u2004"
    VM_MEMORY=1024
    VM_CORES=2

    Vagrant.configure("2") do |config|
      config.vm.box = "ubuntu/focal64"
      config.vm.boot_timeout = 6000
      config.vm.network "public_network"
      
      config.vm.provider "virtualbox" do |vb|
        #vb.gui = true # Virtualboxのウインドウが開きます
        vb.name         = VB_NAME
        vb.memory       = VM_MEMORY
        vb.cpus         = VM_CORES
        vb.customize ['modifyvm', :id, '--usb', 'on']
        vb.customize ['modifyvm', :id, '--usbehci', 'on' ] # USB 2.0 controller
        vb.customize ["modifyvm", :id, "--usbxhci", 'off' ] # USB 3.0 controller
        vb.customize ["usbfilter", "add", "0", "--target", :id, '--name', "Broadcom BCM2708 Boot","--vendorid","0a5c","--productid","2763", "--remote", "no"] #
        vb.customize ["usbfilter", "add", "1", "--target", :id, '--name', "Broadcom BCM2710 Boot","--vendorid","0a5c","--productid","2764", "--remote", "no"] #
        vb.customize ["usbfilter", "add", "2", "--target", :id, '--name', "Linux with usb RNDIS/Ethernet Gadget","--vendorid","0525","--productid","a4a2", "--remote", "no"] #
      end

      config.vm.provision "shell", privileged: true, inline: <<-SHELL
        sed -i -e 's/ console=ttyS0//g' /etc/default/grub.d/50-cloudimg-settings.cfg
        update-grub
        apt-get update
        apt install -y linux-modules-$(uname -r) linux-modules-extra-$(uname -r)
        apt install -y build-essential libusb-1.0-0-dev git unzip nfs-kernel-server
      SHELL
    end
    ```

4. `vagrant up`で、仮想機起動
5. しばらく待つ。20～30分くらい?
    - `ubuntu/focal64`イメージのダウンロード
    - こいつの起動がすごく時間かかる。grubのパラメータを変更する(`console=ttyS0`を取り除く)と[よいらしい](https://bugs.launchpad.net/cloud-images/+bug/1829625)ので、vagrantのprovisionで行ってる。
    - ツールほかのダウンロードなど
    - USB Ethernetのドライバのため、`linux-modules-extra-`をインストールする

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/b98b419d-84a5-1e85-855e-33f5ffd14d9c.png)

6. `vagrant halt`で、一度、シャットダウン.
7. Vagrantfileの `vb.customize ["usbfilter", "add" ...` の`add`を`modify`に変更する.(３つともやる。下の画像は２つだけだが..３つ目を変更しようとしているとこ...)<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/c33e2e68-3a16-5f13-4567-b565bd87ead8.png)

8. `vagrant up`で起動、`vagrant ssh`で、ログイン

### RPiZeroを起動させるための準備
1. 仮想機にログイン
2. usbboot/rpiboot のビルド
 
    ```bash:コピペ
    cd ${HOME} && \
    git clone --depth=1 https://github.com/raspberrypi/usbboot && \
    cd usbboot && \
    make && \
    cd ${HOME}
    ```

3. Raspbian liteのダウンロードと解凍

    ```bash:コピペ
    cd ${HOME} && \
    wget http://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2020-02-14/2020-02-13-raspbian-buster-lite.zip && \
    unzip 2020-02-13-raspbian-buster-lite.zip
    ```

4. Raspbian lite イメージのマウント.

    ```bash:こぴぺ
    sudo losetup -P /dev/loop5 ${HOME}/2020-02-13-raspbian-buster-lite.img
    sudo mkdir -p /pi/{boot,root}
    sudo mount /dev/loop5p1 /pi/boot
    sudo mount /dev/loop5p2 /pi/root
    ```


5. 起動させるためのパッチ

    ```bash:コピペ
    # Edit /pi/boot/config.txt
    grep -e '^dtoverlay=dwc2$' /pi/boot/config.txt || echo -e "# enable OTG\ndtoverlay=dwc2\n# set initramfs\ninitramfs initrd.img followkernel" | sudo tee -a /pi/boot/config.txt

    #cmdline.txt
    #console=serial0,115200 console=tty1 root=PARTUUID=738a4d67-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh
    echo 'otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=10.42.0.1:/pi/root rw ip=10.42.0.14:10.42.0.1::255.255.255.0:pi:usb0:static elevator=deadline modules-load=dwc2,g_ether fsck.repair=yes rootwait g_ether.host_addr=5e:a1:4f:5d:cf:d2' | sudo tee /pi/boot/cmdline.txt

    cat <<'EOF' | sudo tee /pi/root/etc/fstab
    proc            /proc           proc    defaults          0       0
    10.42.0.1:/pi/root / nfs defaults 0 1
    #PARTUUID=738a4d67-01  /boot           vfat    defaults          0       2
    #PARTUUID=738a4d67-02  /   
    EOF

    # /pi/root/etc/dhcpcd.conf
    grep -e '^interface usb0 #mt08$' /pi/root/etc/dhcpcd.conf || echo -e 'interface usb0 #mt08\nstatic ip_address=10.42.0.14/24\nstatic routers=10.42.0.1\nstatic domain_name_servers=8.8.8.8' | sudo tee -a /pi/root/etc/dhcpcd.conf

    # sshを自動起動させる
    cd /pi/root/etc/systemd/system/multi-user.target.wants
    sudo ln -s /lib/systemd/system/ssh.service ssh.service
    cd ${HOME}

    # initrdを持ってくる。
    cd ${HOME} && \
    wget "https://github.com/mt08xx/files/raw/master/2020-0512-1_RPIZero_initrd.img-4.19.97%2B" && \
    sudo cp 2020-0512-1_RPIZero_initrd.img-4.19.97+ //pi/boot/initrd.img
    ```

6. Ubuntu側設定

    ```bash:コピペ
    # NFSの設定
    grep 10.42.0 /etc/exports || echo "/pi/root 10.42.0.14(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
    sudo systemctl restart nfs-server.service
    sudo exportfs -rav

    # USB接続のEthernetに固定IP割り当てる。
    # デバイス名が、usb0だったり、enx5ea14f5dcfd2だったりする..
    cat << 'EOF' | sudo tee /etc/netplan/50-cloud-init.yaml
    # This file is generated from information provided by the datasource.  Changes
    # to it will not persist across an instance reboot.  To disable cloud-init's
    # network configuration capabilities, write a file
    # /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
    # network: {config: disabled}
    network:
        ethernets:
            enp0s3:
                dhcp4: true
                match:
                    macaddress: 02:c2:ed:de:cc:93
                set-name: enp0s3
            usb0:
                dhcp4: no
                dhcp6: no
                addresses: [10.42.0.1/24]
            enx5ea14f5dcfd2:
                dhcp4: no
                dhcp6: no
                addresses: [10.42.0.1/24]
        version: 2
    EOF

    #適応
    sudo netplan generate
    sudo netplan apply

    # IP Forwading有効
    sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
    ```
7. `exit` で抜けて、`vagrant halt`で仮想機、いったん、シャットダウン

### RPiZeroを起動
1. RPiZeroは接続しない
2. PowerShellを普通に起動　(Win+x, i)
3. 以下実行

    ```powershell:
    # 作業フォルダに移動
    cd C:\Vagrant\u20
    # 仮想機起動
    vagrant up
    # 仮想機にログイン
    vagrant ssh
    ```
4. 以下実行

    ```bash
    # IP forwarding の設定(保存しない)
    sudo iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
    #
    # Raspbian lite イメージのマウント
    sudo losetup -P /dev/loop5 ${HOME}/2020-02-13-raspbian-buster-lite.img
    sudo mkdir -p /pi/{boot,root}
    sudo mount /dev/loop5p1 /pi/boot
    sudo mount /dev/loop5p2 /pi/root
    #
    # rpiboot実行
    cd ${HOME}
    sudo usbboot/rpiboot -d /pi/boot/
    ```
5. RPiZeroのUSBポート(電源PWRの方ではない)と、PCを接続。<br>RPiZeroをテレビに接続して様子を見た方がよいかも。
6. 祈る


## 実行例
- `10.42.0.1:/pi/root on / type nfs ...` となってます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/13a73f9b-1d32-c12e-748e-a5ceafe840f5.png)


## その他
- RPi4B に ubuntu 20.04 64bitをいれて、同様にして動きました(というか、RPi4Bで確認したほうが先..)
- swapはつかえない
- raspbianのimgファイルをマウントして使っているが、実使用時は、ファイルをコピーするんだと思う。
- デバイス名が、usb0だったり、enx5ea14f5dcfd2だったりするんだが..
- 複数のPiZeroが接続されたら? とか、その時のうまい設定とか、できたら、教えてください。
- SDを使う、前の記事、[[メモ] Raspberry Pi ZeroをUSBケーブル一本でインターネット接続！(キーボード・マウス・モニター必要なし)](https://qiita.com/mt08/items/ce5e3911d74d7fad4563)、は　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/dfae691b-7579-af5c-f13b-80b915efd397.png) . もうそんな経つのか


### initrd.imgの作り方
1. RaspbianをSDにやいて、起動。
2. RPi Zeroで起動
3. 以下実行

    ```bash
    ## Make initramfs on "RPi-Zero"
    sudo apt install -y initramfs-tools

    grep -e '^g_ether$' /etc/initramfs-tools/modules || echo -e 'g_ether\nlibcomposite\nu_ether\nudc-core\nusb_f_rndis\nusb_f_ecm' | sudo tee -a /etc/initramfs-tools/modules

    sudo update-initramfs -c -k `uname -r`
    ```
4. `/boot/initrd.img-4.19.97+`というファイルができるので、それをVMの`/pi/boot/initrd.img`へコピー。

<!--
5. 実行例<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/3bf2653a-f342-6e4f-558b-7800eed3104d.png) -->