【Raspberry Pi】Kubernetes 環境の構築
はじめに
Raspberry Pi OS の 64bit 版に Lite バージョンが出ていたことに気づいたので、32bit 版で構成していた Raspberry Pi 4 Model B での Kubernetes 環境を新たに64bit 版で再構築してみました。
ちなみに、インストール手順については以下のページを参考にさせていただいています。
- https://kubernetes.io/docs/setup/production-environment/
- https://qiita.com/yyojiro/items/0cd7ec7e2a39610be53f
準備
SDカード書き込み
Raspberry Pi 公式の Raspberry Pi Imager を使用して Raspberry Pi OS (64bit 版) Lite をSDカードに書き込みます。Pi 4 が 4台あるので SD カードの書き込みも 4 回実施。
SSH有効化
Pi 4 にモニターやキーボードを接続していないため、予め SSH を有効にする必要があります。SD カードに OS イメージを書き込んだ後、SD 上の boot パーティションに「ssh」という名前の空ファイルを置くことで自動的に ssh でのログインが有効になります。
DHCP 割り当て設定
ネットワークへの接続には有線 LAN を使い、IP アドレスの割り当ては DHCP で行います。各ボードの MAC アドレスは既に DHCP サーバに登録してあるので、固定 IP を割り当てることができるようにしています。
ちなみに IP アドレスとホスト名の対応は以下のような感じです。
192.168.0.21 pi4b01 192.168.0.22 pi4b02 192.168.0.23 pi4b03 192.168.0.24 pi4b04
Raspberry Pi を設定する
初期設定
各ボードで raspi-config を使って、このへんの初期設定を行います。
- パスワード変更
- ホストネーム変更
- ロケール変更
- TimeZone 設定
/etc /hosts ファイルも編集しておきます。
- 127.0.1.1 の行を削除
- 各ボードに割り当てた IP アドレスの設定を追加する
192.168.0.21 pi4b01 192.168.0.22 pi4b02 192.168.0.23 pi4b03 192.168.0.24 pi4b04
Docker をインストールする
sudo apt-get update sudo apt-get -y upgrade sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common gnupg2
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add - echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \ $(lsb_release -cs) stable" | \ sudo tee /etc/apt/sources.list.d/docker.list sudo apt-get update sudo apt-get install docker-ce
sudo無しでdockerを利用できるようにするには「 sudo usermod -aG docker $USER」で自分を docker グループに追加します。 こうすることで次回のログインから docker コマンドが su なしで利用可能になります。
Kubernetes をインストールする
iptables の設定
Kubernetes 用の 設定が必要そうなので以下の作業をしておきます。
cat << EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sudo sysctl --system
Cgroup の memory グループを有効にする
cat /proc/cgroups をすると memory グループが無効になっているので、 /boot/cmdline.txt の行の末尾に 以下の設定を追加します。追加する際は改行を入れずに一行にする必要があります。
cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
この設定が有効になるように、ここで reboot します。
kubeadm, kubelete, kubectl をインストールする
sudo apt-get update && sudo apt-get install -y apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl
swap を停止する
swap があると kubernetes の設定ができないので swap は無効にしておきます。
sudo dphys-swapfile swapoff sudo dphys-swapfile uninstall sudo update-rc.d dphys-swapfile remove sudo systemctl stop dphys-swapfile sudo systemctl disable dphys-swapfile
ここまでは全ボード共通で行う作業です。
Master ノードの設定
ここでは pi4b01 を Master ノードとして設定します。Pod ネットワークには Flannel を使う例が多いようなので、ここでも Flannel を使いました。また、ロードバランサーは MetalLB を使用します。
- 初期化する
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
pi@pi4b01:~ $ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 W1003 20:59:40.066256 7995 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io] [init] Using Kubernetes version: v1.19.2 [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/ [WARNING SystemVerification]: missing optional cgroups: hugetlb [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local pi4b01] and IPs [10.96.0.1 192.168.0.21] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [localhost pi4b01] and IPs [192.168.0.21 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [localhost pi4b01] and IPs [192.168.0.21 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Starting the kubelet [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 37.511892 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.19" in namespace kube-system with the configuration for the kubelets in the cluster [upload-certs] Skipping phase. Please see --upload-certs [mark-control-plane] Marking the node pi4b01 as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node pi4b01 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: dznswr.altmxn5ip8qwbpgf [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.0.21:6443 --token dznswr.altmxn5ip8qwbpgf \ --discovery-token-ca-cert-hash sha256:c12a398a8acb4d2069b367980a0db018b2a4454a4a3a7e5d0544ac9d13eb269e
メッセージに従って以下のコマンドを入力します。
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
- Flannel を導入する。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
- MetalLB を導入する
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.4/manifests/namespace.yaml kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.4/manifests/metallb.yaml # On first install only kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
適当なディレクトリに以下の内容で config.yaml というファイルを作成します。 address の部分は DHCP と被らない範囲をテキトーに設定しています。
apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: - 192.168.0.60-192.168.0.69
kubectl apply -f config.yaml
Worker ノードの設定
Master ノードを初期化した際のログに書かれているコマンドを各 Worker ノードで実行します。
sudo kubeadm join 192.168.0.21:6443 --token dznswr.altmxn5ip8qwbpgf --discovery-token-ca-cert-hash sha256:c12a398a8acb4d2069b367980a0db018b2a4454a4a3a7e5d0544ac9d13eb269e
このコマンドを実行後、Master ノードで各ノードの状態を見ることができます。
kubectl get nodes
おわりに
今回はOSからの再インストールということで Rasberry Pi OS Lite の 64 bit 版を使ってみましたが、32 bit 版の時と何ら変わることなくOSインストールや Kubernetes の設定ができました。このまま 64bit 版の環境で使ってみようと思います。
【Raspberry Pi】タッチパネル付きの 3.5 インチLCDパネルを接続してみた
はじめに
Raspberry Pi Zero WH に接続できそうな GPIO 接続のタッチパネル付き 3.5 inch LCDを購入しました。
商品説明では Pi Zero に関する記載はなかったのですが、GPIO のピン配列は他の Pi シリーズと同等のため問題ないだろうと考えて購入。実際に使用してみたところソフト的な問題で少しハマってしまいました。
製品の概要
購入した製品は Elecrow というブランドの Raspberry Pi 用タッチパネル付き 3.5 インチモバイルモニターです。Raspberry Pi の拡張端子に接続して使用するタイプの製品になっています。
パネルの機能はこんな感じです。
Pi Zero WH のとサイズ比較。
付属マニュアルが違う !?
使用方法を確認するために同梱のマニュアルを見ます。マニュアルには接続方法やドライバーのインストール手順が書かれているので、マニュアルをしっかり読むことは大事です。
表紙にはナゼか HDMI という文字が書かれているのですが…
内容を見てみると何か違うモノの説明が書かれています。
これ、別製品のマニュアルじゃないですか!?
GPIO 接続製品を買ったのにマニュアルは HDMI 接続品のものが入っていました。最初からこれでは、この先が心配になってきましたよ。
接続とドライバのインストール
添付マニュアルが別製品用でインストールには役に立たないものでしたが、幸い Amazon の製品ページにインストールに必要な情報が記載されていました。
(Amazon 商品ページ)より引用
ドライバーをインストールステップ:
Tips:Basic for Raspbian Jessie with PIXEL (2017-04-10-raspbian-jessie.img)
Step 1: Raspbian IMGファイルをダウンロード。
https://www.raspberrypi.org/downloads/raspbian/
Step 2: IMGファイルをSDカードに書き込み、次のリンクでの文章をご参照くださいませ。
https://www.raspberrypi.org/documentation/installation/installing-images/README.md
Step 3: Terminalウィンドウを開いてRPIにドライバーをダウンロード。
Run: git clone https://github.com/Elecrow-keen/Elecrow-LCD35.git
Step 4: ドライバーをインストール。
Run:
cd Elecrow-LCD35
sudo ./Elecrow-LCD35
また、製品の詳細も商品ページに記載されているURLにありました。
情報も分かったところで接続します。
ピンの位置がずれないことだけに注意して接続するだけなので簡単です。
次にソフトウェアのインストールを行います。インストール手順書には Raspbian Jessie with PIXEL (2017-04-10-raspbian-jessie.img) が指定されていますが、さすがに古い環境なので Raspberry Pi OS (2020-08-20-raspios-buster-armhf) を使用します。
git clone https://github.com/Elecrow-keen/Elecrow-LCD35.git
cd Elecrow-LCD35
sudo ./Elecrow-LCD35
表示されませんよ
インストール自体に問題は無いはずですが、液晶画面には何も表示されませんでした。
画面表示はされませんが、ssh 接続をして「xev -display :0.0」コマンドでタッチパネルのイベントを拾ってみるとパネルに触れたりパネル状をスライドしたときの情報は取れているため、接続ミスでは無いようです。
カーネルのバージョンに依存しているらしい
商品ページやインストールガイドの記載では Raspbian Jessie を使用しているので、自分のシステム環境もJessie に変更して、再インストール。
はい、問題なく LCD に表示されました。
2020-08-20 版の Raspberry Pi OS のカーネルバージョンは 5.4 なので、カーネルのバージョンが 4.19 だった 2020-05-27 版の Raspberry Pi OS で再度挑戦してみます。
すると、LCDに表示することができました。ただし、2020-05-27 版のシステムでも apt upgrade を実行してしまうとカーネルバージョンが 5.4 に上がってしまうため LCD に何も表示されない問題が再発します。
DeviceTree の内容を調べてみる
Linuxカーネルの差分を調査するのは嫌だなーと思い、ネットで何かヒントがないか調べるためのキーワードを探る用に git clone で取得した「ドライバー」を解析してみます。
入手したファイルはドライバーといっても、内容物は設定用のコマンドと Device Tree Overlay のバイナリファイル、後はタッチパネルのキャリブレーション用ソフトの 3 点のみです。
表示ドライバ自体はRaspbian や Raspberry Pi OS のシステムに含まれていて、Device Tree Overlay で LCD 出力に必要な設定変更をしているようですね。
というわけで、Device Tree Overlay のファイルをソースに変換してみます。
dtc -I dtb -O dts -o elecrow35a-overlay.dts elecrow35a-overlay.dtb
ソースに変換したものがこれ ↓ です。
/dts-v1/;
/ {
compatible = "brcm,bcm2835\0brcm,bcm2708\0brcm,bcm2709";
fragment@0 {
target = < 0xdeadbeef >;
__overlay__ {
status = "okay";
spidev@0 {
status = "disabled";
};
spidev@1 {
status = "disabled";
};
};
};
fragment@1 {
target = < 0xdeadbeef >;
__overlay__ {
waveshare35a_pins {
brcm,pins = < 0x11 0x19 0x18 >;
brcm,function = < 0x00 0x00 0x00 >;
linux,phandle = < 0x01 >;
phandle = < 0x01 >;
};
};
};
fragment@2 {
target = < 0xdeadbeef >;
__overlay__ {
#address-cells = < 0x01 >;
#size-cells = < 0x00 >;
waveshare35a@0 {
compatible = "ilitek,ili9486";
reg = < 0x00 >;
pinctrl-names = "default";
pinctrl-0 = < 0x01 >;
spi-max-frequency = < 0xe4e1c0 >;
txbuflen = < 0x8000 >;
rotate = < 0x5a >;
bgr = < 0x00 >;
fps = < 0x1e >;
buswidth = < 0x08 >;
regwidth = < 0x10 >;
reset-gpios = < 0xdeadbeef 0x19 0x00 >;
dc-gpios = < 0xdeadbeef 0x18 0x00 >;
debug = < 0x00 >;
init = < 0x10000b0 0x00 0x1000011 0x20000ff 0x100003a 0x55 0x1000036 0x28 0x10000c2 0x44 0x10000c5 0x00 0x00 0x00 0x00 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 0x1000036 0x28 0x1000011 0x1000029 >;
linux,phandle = < 0x02 >;
phandle = < 0x02 >;
};
waveshare35a-ts@1 {
compatible = "ti,ads7846";
reg = < 0x01 >;
spi-max-frequency = < 0x1e8480 >;
interrupts = < 0x11 0x02 >;
interrupt-parent = < 0xdeadbeef >;
pendown-gpio = < 0xdeadbeef 0x11 0x00 >;
ti,x-plate-ohms = [ 00 3c ];
ti,pressure-max = [ 00 ff ];
linux,phandle = < 0x03 >;
phandle = < 0x03 >;
};
};
};
__overrides__ {
speed = < 0x02 0x7370692d 0x6d61782d 0x66726571 0x75656e63 0x793a3000 >;
txbuflen = [ 00 00 00 02 74 78 62 75 66 6c 65 6e 3a 30 00 ];
rotate = [ 00 00 00 02 72 6f 74 61 74 65 3a 30 00 ];
fps = [ 00 00 00 02 66 70 73 3a 30 00 ];
bgr = [ 00 00 00 02 62 67 72 3a 30 00 ];
debug = < 0x02 0x64656275 0x673a3000 >;
swapxy = < 0x03 0x74692c73 0x7761702d 0x78793f00 >;
};
__symbols__ {
waveshare35a_pins = "/fragment@1/__overlay__/waveshare35a_pins";
waveshare35a = "/fragment@2/__overlay__/waveshare35a@0";
waveshare35a_ts = "/fragment@2/__overlay__/waveshare35a-ts@1";
};
__fixups__ {
spi0 = "/fragment@0:target:0\0/fragment@2:target:0";
gpio = "/fragment@1:target:0\0/fragment@2/__overlay__/waveshare35a@0:reset-gpios:0\0/fragment@2/__overlay__/waveshare35a@0:dc-gpios:0\0/fragment@2/__overlay__/waveshare35a-ts@1:interrupt-parent:0\0/fragment@2/__overlay__/waveshare35a-ts@1:pendown-gpio:0";
};
__local_fixups__ {
fixup = "/fragment@2/__overlay__/waveshare35a@0:pinctrl-0:0\0/__overrides__:speed:0\0/__overrides__:txbuflen:0\0/__overrides__:rotate:0\0/__overrides__:fps:0\0/__overrides__:bgr:0\0/__overrides__:debug:0\0/__overrides__:swapxy:0";
};
};
Device Tree 内にある waveshare35a というキーワードからすると、恐らくは waveshare.com のこの製品がオリジナルだと考えられます。また、さらに waveshare35a でネット検索すると GitHub に dts ファイルが存在することを見つけました。
このコードの kernel 5.1 以降に対応するパッチを見ると、 gpio の極性(?)設定を変更する必要がありそうです。
そこで、waveshare35a.dtsの変更内容を参考にelecrow35a-overlay.dtbを修正してみます。
# dtb をソースに変換する
dtc -I dtb -O dts -o elecrow35a-overlay.dts elecrow35a-overlay.dtb
# 変更点 1
reset-gpios = < 0xdeadbeef 0x19 0x01 >; # 0x00 を 0x01 に書き換える
# 変更点 2
pendown-gpio = < 0xdeadbeef 0x11 0x01 >; # 0x00 を 0x01 に書き換える
# ソースを dtb に変換する
dtc -I dts -O dtb -o elecrow35a-overlay.dtb elecrow35a-overlay.dts
# 修正した dtb ファイルをインストールする
sudo ./Elecrow-LCD35
この作業を行うことで カーネルバージョン 5.4 の Raspberry Pi OS でも LCD 表示を行うことが可能になりました。
おわりに
少しハマってしまいましたが何とか Raspberry Pi Zero WH + 3.5 インチ LCD + タッチパネルという環境が動作するようになりました。次は Raspberry Pi High Quality Camera を接続して遊んでみたいと考えています。
【Raspberry Pi】Raspberry Pi Zero WHを導入してみました
はじめに
2020年の新型コロナウィルスによる自粛期間中に何となくRaspberry Pi Zero WHを購入してみました。Raspberry Pi のインストール記事は世の中にたくさん存在しますが、ここではメモとして自分のやったことを記録しておこうと思います。
用意したもの(ハードウェア)
インストールするにあたって用意したハードはこちらです。
- Raspberry Pi Zero WH
- microSD カード
- USB micro B ホストケーブル
- mini HDMI 変換ケーブル
- 無線マウス(+USB ドングル)
- BlueTooth キーボード
- フォトパネル改造モニター
- USB電源
新規に購入したものは本体(Raspberry Pi Zero WH)のみで、それ以外の物はすでに所有しているものを流用しました。本体が Bluetooth 対応なので動作確認も兼ねてBuletooth キーボードを使用してみます。モニターはインストール画面の確認ができれば OK ということで過去に作成したフォトパネル改造モニターで済ませています。
用意したもの(ソフトウェア)
microSDカードに OS イメージを書き込むツールとして、Raspberry Pi 公式の Raspberry Pi Imager for Ubuntu を利用しました。Ubuntu Linux の動作する PC 上で作業を行うため、書き込みツールには for Ubuntu を選択しています。そして、SDカードに書き込むイメージは Raspberry Pi OS (32-bit) with desktop (buster 2020-05-27) です。
インストールしてみた
インストール作業そのものは Raspberry Pi 公式サイトの手順(https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up)を参考に実行します。
SDカードの準備
Raspberry Pi Imager を起動し、[CHOOSE OS] をクリックします。
OS選択メニューが開くので、一番上の Rspberry Pi OS (32-bit) をクリックします。
次に [CHOOSE SD CARD] メニューをクリックし、書き込み先のSDカードを選択します。
OS、SDカードの選択が終了すると [WRITE] メニューがクリック可能になるのでクリックします。
確認画面が出るので、YES をクリック。
書き込みが始まりました。
書き込みが終了すると、検証が始まります。
検証が完了すると SDカードを取り出すことができます。
Raspberry Pi OSの初期設定
Raspberry Pi 公式サイトの手順通りに実施すれば良いので、ここでは Bluetooth キーボードを設定した部分だけ記載します。
OS イメージを書き込んだ SD カードを Raspberry Pi Zero WH に挿入し、本体の電源を入れると最初の画面が表示されます。
設定を開始する前に右上の Buletooth のマークをクリック。
プルダウンメニューが出るので [Add New Device] を選択します。
ここで Buletooth キーボードをペアリングモードして待つと、Raspberry Pi Zero WH にキーボードが検出されます。
ペアリングするキーボードをクリックすると、
認証用のコードが表示されるので、キーボード側からコードを入力します。
ペアリングに成功するとキーボードとの接続が行われ、
Bluetooth キーボードが使えるようになりました。
キーボードが使えるようになった後はインストールを再開します。インストール中の文字入力は Bluetooth キーボードで問題なく行うことができました。
おわりに
これで Raspberry Pi Zero WH が使えるようになりました。今回は Raspberry Pi OS のデスクトップ版をインストールしましたが、Pi Zero WHの処理能力を考えると Lite 版の Raspberry Pi OS を導入したほうが良いような気がします。