Skip to main content

EdgeX Foundry ハンズオンラボガイド公開

EdgeX Foundry の初修者向けハンズオンガイド(日本語)を作成して公開しました。

いわゆる セルフペースドラボ形式 です。Docker がインストールされた Ubuntu があれば、実際に EdgeX Foundry を動作させながら、基本的な アーキテクチャや利用方法を学習できる ように構成しています。

📖 EdgeX Foundry ハンズオンラボガイド

併せて、先日の EdgeX Foundry Tokyo Meetup #2 でこのガイドを ハンズオンセッションとして解説しながら実践(75 分)したときの録画が公開されています。

🎥 EdgeX Foundry Tokyo Meetup #2 録画(1.94 GB)

コンテンツ

説明など

これまで、EdgeX Foundry 関連のエントリを趣味で好き放題にいくつか書いてきていました が、それをきっかけに、ハンズオンセッションへのお声かけをいただきました。

ブログの内容がすでにハンズオンっぽくなっていたものの、やさしくない表現や最新の状況と整合していない部分も多々あったため、ブログを基に再編しガイドとしてまとめたのが本ガイドです。コミュニティの承認やレビュは得ていないので、非公式ですが……。

ハンズオンセッションは、実際にこのガイドに従って、解説を加えながら実機を操作する様子を配信する形で行いました。

おかげさまで 40 名ほどのご参加をいただき、オンラインでのハンズオンセッションというなかなかない機会になり、個人的にもよい経験になりました。おもしろかったです。

今後のこと

ガイド執筆時点では Fuji が最新リリースでしたが、今月には Geneva、半年後には Hanoi、と今後も半年ごとに新しいリリースが予定されています。

趣味の範囲内ではあるものの、何らかの形で追従できたらいいなあとは考えています。まずは Geneva を触るところからですね。

EdgeX Foundry 関連エントリ


デジタル一眼レフカメラを 5,000 円で無理やり Web カメラ化する実験的方法(Windows)

HDMI のキャプチャのことをいろいろ調べていたら おもしろそうなブログ を見つけたので、実際に遊んでみました。これはその記録です。

免責

  • 安定性は不明 です、実験程度 に捉えてください
  • 当然ながら ハードウェア HDMI キャプチャのほうがよい です。もしくはプラグインを書くべきです
  • 映像は 実測で 0.5 秒ほど遅延 しますし、画質は落ちます し、CPU をとても食い ます
  • 音声は得られません
  • 何かが起きても ぼくは責任は取りません

TL; DR

手順

結論

  • 使えないことはないけれど、CPU をほんとうに食うし、0.5 秒くらい遅延するので、この方法が活用できるシーンは限られそうだ
  • 素直にハードウェア HDMI キャプチャを使うか、LKV373 を使うにしてもプラグインを書く方がよいだろう

概要

できることと注意

この方法によって、

  • PC やゲーム機の映像を、YouTube Live などの生配信で使う
  • デジタル一眼レフカメラの映像を Zoom や Teams や Meets で使う

などが、ハードウェアの HDMI キャプチャを用意するよりは比較的低コスト(約 5,000 円)でできるようになります。

ただし、端的に言って 品質を相当犠牲にする ことになり、

  • CPU をめっちゃ食う
  • 映像が 0.5 秒くらい遅延して配信される
  • 音声は別に工夫(分離器で音だけ取り出す、コードを追加する、など)が必要
  • 安定して動作するかどうか誰もわからない

な点には注意が必要です。

別解

単に デジタル一眼レフカメラの映像を Web カメラ化したいだけ であれば、macOS なら Camera Live と CamTwist、キヤノン製のカメラなら EOS Webcam Utility など、より低コストかつ理想的な別解があります。

また、LKV373 を使う場合でも、macOS であれば、別の方のブログで OBS Studio のプラグインを実装している偉大な例があります。

で、Windows でソニーの α7iii なぼくはこれが使えず、とはいえ、OBS Studio のプラグイン作りはいきなり手を出すにはしんどかったので、手間がかからない代わりに CPU にはめっちゃ優しくない 方法でがんばる、のが本エントリです。

必要なもの

  • Lenkeng の HDMI 延長器 LKV373(またはその OEM 品)の、送信機(TX、Sender)
    • 受信機は不要
    • Amazon だと これ とか。約 5,000 円
    • 後継の LKV373A だと使えないのでややこしい
    • 本体の裏に V2.0 があれば LKV373(使える)、V3.0 だと LKV373A(使えない)らしい?
  • PC の有線 LAN ポート
  • golkv373
  • VLC media player
  • OBS Studio

キモはいちばん上のこれです。

裏の V2.0 が大事みたいです。

手順

配線

HDMI ソースと LKV373(TX)をつなぎ、LKV373(TX)と PC を LAN ケーブルで直結します。

LKV373(TX)がデフォルトで 192.168.168.55/24 を持っているので、PC 側の NIC には同じセグメントの適当な IP アドレスを固定で割り当てます。LKV373(TX)の IP アドレスは Web の管理画面から変えられますが、その場合は、PC 側も併せて変えます。

golkv373 の準備

golkv373 のバイナリをダウンロード してきて、起動します。自分でビルドしてもよいです。署名がどうのこうので怒られたら、納得の上でとにかく実行します(ダブルクリックで起動せずにコマンドプロンプトや PowerShell から叩けば怒られませんが、どちらでもよいです)。

ファイアウォールの穴あけも必要です。LKV373(TX)と接続している NIC のプロファイルを Get-NetConnectionProfile かなにかで調べて、そのプロファイルで通信を許可します。

起動するとなんやかや出力されて、

2020/xx/xx xx:xx:xx Program started as:  [C:\...\golkv373-v0.5.2-win64.exe]
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

2020/xx/xx xx:xx:xx No active transmitters
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /src/:IP/frame.mjpg       --> main.main.func2 (4 handlers)
[GIN-debug] GET    /src/:IP/frame.jpeg       --> main.main.func3 (4 handlers)
[GIN-debug] GET    /src/:IP/                 --> main.main.func4 (4 handlers)
[GIN-debug] GET    /status                   --> main.main.func5 (3 handlers)
[GIN-debug] GET    /                         --> main.main.func6 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8080

続けて毎秒のログが出始めるはずです。状況に応じて出方が変わります。

ファイアウォールに阻まれているなど、LKV373(TX)と疎通できていない状態のときは、No active transmitters だけが繰り返し出力されます。この場合、設定を見直してどうにかします。

...
2020/xx/xx xx:xx:xx No active transmitters
2020/xx/xx xx:xx:xx No active transmitters
2020/xx/xx xx:xx:xx No active transmitters
...

疎通できているけれども映像が入力されていない場合は、keepalive sentNo active transmitters が両方出力されます。この場合は HDMI のソースに何の信号も来ていない可能性があります。

2020/xx/xx xx:xx:xx keepalive sent to 192.168.168.55:48689
2020/xx/xx xx:xx:xx No active transmitters
2020/xx/xx xx:xx:xx keepalive sent to 192.168.168.55:48689
2020/xx/xx xx:xx:xx No active transmitters
2020/xx/xx xx:xx:xx keepalive sent to 192.168.168.55:48689
2020/xx/xx xx:xx:xx No active transmitters

疎通できていて映像も送られてきているときは、フレームレートなどが表示されます。

2020/xx/xx xx:xx:xx keepalive sent to 192.168.168.55:48689
2020/xx/xx xx:xx:xx 192.168.168.55: MB/s=2.66 FPS=30.00 lost=0
2020/xx/xx xx:xx:xx keepalive sent to 192.168.168.55:48689
2020/xx/xx xx:xx:xx 192.168.168.55: MB/s=2.69 FPS=30.00 lost=0
2020/xx/xx xx:xx:xx keepalive sent to 192.168.168.55:48689
2020/xx/xx xx:xx:xx 192.168.168.55: MB/s=2.71 FPS=30.00 lost=0

ブラウザで http://localhost:8080/ にアクセスして、LKV373(TX)の IP アドレス(デフォルトなら 192.168.168.55)を選択すると、転送されてきている映像が表示されます。単に映像が観たいだけであれば、これで終わりです。

この段階で、192.168.168.55 からの映像は、

  • http://localhost:8080/src/192.168.168.55/frame.mjpg

で Motion JPEG としてストリーミングされています。ここから、OBS Studio でこの Motion JPEG を映像ソースとして取り込めるように設定していきます。

プレイリストファイル(XSPF)の作成

OBS Studio では、メディアソース で Motion JPEG の URL を直接指定しても映像は取り込めます。が、

  • バッファされるので遅延が増えるうえ、バッファの設定を変えられない
  • 遅延が蓄積していく(ように見える)

ので、URL だけでなくキャッシュ設定も含まれたプレイリストファイルを作って、それを OBS Studio から読ませる方法を取ります。

プレイリストの作成には、VLC media player を使います。VLC media player を起動して、

  • [メディア] > [ネットワークストリームを開く] を開き、
  • URL に http://localhost:8080/src/192.168.168.55/frame.mjpg を入力して、
  • [詳細オプション] で [キャッシュ] を [0 ms] にして
  • [再生]

します。この段階で遅延がひどかったりフレームレートが低かったりする場合は、余計なものを閉じてやり直すなどするとよさげです。

キャッシュを増やすとより安定しますが、増やしただけ遅延が純増します。ここでは強気に 0 ms です。

で、映像が極端な遅延なく見えていれば、[メディア] > [プレイリストファイルを保存] して、XSPF ファイルを保存します。この XSPF ファイルがプレイリストで、キャッシュの設定もここに含まれています。

保存したら、VLC media player はもう要らないので閉じます。

OBS Studio の設定

最後に、OBS Studio で、ソースとして VLC ビデオソース を追加し、その設定画面で先ほどの XSPF ファイルを追加すれば、完了です。

ここからさらに OBS-VirtualCam などを使って仮想デバイスに出力すれば、別のソフトウェア(Zoom など)でも映像を利用できることになります。

実測

次のパタンで遅延や CPU 使用率などを比較してみます。

  • Web カメラとして使うパタン
    • 本エントリの方法を使った場合
    • ハードウェア HDMI キャプチャを使った場合
    • 市販の Web カメラを使った場合
  • HDMI キャプチャとして使うパタン
    • 本エントリの方法を使った場合
    • ハードウェア HDMI キャプチャを使った場合

登場人物

  • PC
    • Intel NUC6i5SYH
    • Intel Core i5-6260U @ 1.80 GHz
    • 32 GB RAM
  • ハードウェア HDMI キャプチャ
    • Ezcap269
  • 市販の Web カメラ
    • Logicool C270

測定方法

ブラウザでストップウォッチを表示 させて、測定パタンに応じた経路で最終的に Zoom に表示します。

各画面に時間が表示されている状態で、充分に速いシャッタスピード(1/800 程度)で全体を撮影すると、撮影できた各画面の時間の差が遅延時間そのものを表すことになります。

Inter BEE などの展示会では、似た方法をよく低遅延伝送のデモンストレーションで見かけますね。表示させるソースをストップウォッチとフレーム数とで迷いましたが、遅延はミリ秒表記のほうが個人的に馴染みがあるのこうしています。

Web カメラとして使うパタン

本エントリの LKV373 を使った方法は、遅延も CPU 使用率も圧倒的に大きくなりました。

方法遅延CPU 使用率経路
本エントリ(LKV373)460 ms 程度80 ~ 100 %ソース → α7iii → LKV373 → OBS Studio → Zoom
ハードウェアキャプチャ150 ms 程度20 ~ 40 %ソース → α7iii → Ezcap269 → Zoom
市販 Web カメラ60 ms 程度20 ~ 40 %ソース → c270 → Zoom

そもそも、ある瞬間を α7iii が取り込んで HDMI で出力する(≒ カメラの液晶に表示される)までに 70 ms くらいの遅延があるみたいでした(カメラ側の設定で変わる部分かもですが未調査です)。460 ms の内訳は、

経路遅延
ソース → α7iii70 ms
α7iii → LKV373 → OBS Studio220 ms
OBS Studio → Zoom170 ms

な具合です。OBS Studio の仮想カメラでは、デフォルトで入る 3 フレームのバッファ設定をそのままにしているので、その分も含まれるでしょう。

HDMI キャプチャとして使うパタン

カメラを経由しない分遅延は改善されますが、それでも LKV373 を使った方法は、遅延も CPU 使用率も圧倒的に大きいままです。

方法遅延CPU 使用率経路
本エントリ(LKV373)370 ms 程度80 ~ 100 %ソース → LKV373 → OBS Studio → Zoom
ハードウェアキャプチャ80 ms 程度20 ~ 40 %ソース → Ezcap269 → Zoom

370 ms の内訳は、

経路遅延
ソース → LKV373 → OBS Studio200 ms
OBS Studio → Zoom170 ms

な具合でした。

画質

LKV373 を通すと、JPEG らしさのある圧縮ノイズが視認できるレベルで乗ってきます。

自分のブログを映した別 PC の画面を LKV373 経由で OBS Studio に取り込んで等倍キャプチャしたものがこれです。

ハードウェア HDMI キャプチャだとこういう劣化はなく、ここにさらに配信プラットフォーム側の圧縮が乗ってくることになるので、画質面もこの方式のデメリットです。

まとめ

強引に多段変換してどうにかする手法では、遅延も CPU 使用率も大きくなるというごく当たり前のことが確認できました。

同じ LKV373 を使う手法でも、先の macOS 用の OBS Studio のプラグイン を使うのであれば、原理的にはオーバヘッドは相当減らせると推測できるため、プラグインの開発に至ったモチベーションも合理的なものと言えそうです。

CPU 使用率の高騰が許容できるなら、例えば録画や生配信の用途であれば、音声に意図的に遅延を入れて同期を取れば使えないこともないかもしれません。一方、オンライン会議などでは、音声を遅延させるわけにもいかず、そうすると声と映像が 0.5 秒ズレることになってしまうので、なかなか使いづらそうです。そしてどちらの場合でも、この方式の安定性はだれにも保証できません。

いずれにせよ、最近は安いハードウェアキャプチャは 10,000 円強で手に入りますし、予算が許せばそうする方が、あらゆる面で合理的だと思いました。


デジタル顕微鏡で遊ぶ

ちょっと前に 4,000 円の怪しいデジタル顕微鏡 を買ったのだけれど、思っていたより遊べてしまい、おもしろかったです。という話です。

例えば、Raspberry Pi 4 って、

基盤のチップに文字が書いてあると、読めたり読めなかったりです。

例えばこれ。何かもじゃもじゃ書いてあるような気がするのだけれど、肉眼では全然読めない。

そこにこの怪しい顕微鏡を当ててみると、こう。

もっとがんばるとこう。

なるほど、QSAK KDD ね、みたいな。意味は知らんけど。

おもちゃみたいなスタンドも付いているので、がんばって調整すると、撮影もがんばれます。LED 照明が組み込みなのが助かる。

あとはスマートフォンの画面も、

ドット感がこう。ところどころ汚いのは画面ではなくカメラの問題です、エアダスタでも飛ばせないゴミが常に映る。仕方ない。

もっと寄るとこう。なるほど、RGB だなあ、光の三原色だなあ、と思える。左側が白、右側が青の部分です。

お札の小さい文字も読めます。これは諭吉さんの右上です。

この顕微鏡は UVC 準拠なので、つなげば適当なソフトウェアで取り込めます。スマートフォンにも Wi-Fi でつなげられるみたいです、試していませんが。

商品説明では 1,000 倍を謳ってはいるものの、これが実際何倍なのかはよくわかりません。

画面に常にゴミが映るし、画質は悪いし、ピントも合わせにくいし、解像度は 1280×720 だし、と、欠点は挙げようと思えば挙げられるけれど、それでもお値段を考えるととても優秀でした。たのしい。

いろいろ分解して遊ぶときに、キラキラしたかっこいい部品を観察しておもしろがるのに役立っています。


x64 な Windows で ARM アーキテクチャのコンテナイメージをビルドする

Docker は マルチ CPU アーキテクチャ をサポートしているので、docker image pull すると、イメージ側が対応していれば、同じイメージの同じタグを指定しても、環境(OS や CPU アーキテクチャ)に応じて適切なイメージが勝手に取得されます。

で、今回、マルチ CPU アーキテクチャに対応したイメージを、実際に x64 な Windows 環境だけで意外とサクッとビルドできたので、そのお話。

マルチ CPU アーキテクチャ

例えば alpine:latestpull して inspect すると、手元の Windows 環境(x64)では次のように amd64 が降ってくるのに対して、

> docker pull alpine:latest
> docker inspect alpine:latest
[
    {
        "Id": "sha256:f70734b6a266dcb5f44c383274821207885b549b75c8e119404917a61335981a",
        "RepoTags": [
            "alpine:latest"
        ],
        "RepoDigests": [
            "alpine@sha256:9a839e63dad54c3a6d1834e29692c8492d93f90c59c978c1ed79109ea4fb9a54"
        ],
        ...
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 5612304,
        "VirtualSize": 5612304,
        ...
    }
]

同じことを Raspberry Pi にインストールした Ubuntu(arm64)で実行すると、CPU が ARM アーキテクチャなので正しく arm64 が降ってきます。

$ docker pull alpine:latest
$ docker inspect alpine:latest
[
    {
        "Id": "sha256:c20d2a9ab6869161e3ea6d8cb52d00be9adac2cc733d3fbc3955b9268bfd7fc5",
        "RepoTags": [
            "alpine:latest"
        ],
        "RepoDigests": [
            "alpine@sha256:9a839e63dad54c3a6d1834e29692c8492d93f90c59c978c1ed79109ea4fb9a54"
        ],
        ...
        "Architecture": "arm64",
        "Os": "linux",
        "Size": 5357453,
        "VirtualSize": 5357453,
        ...
    }
]

Docker Hub で見ると、ひとつのタグに対してアーキテクチャごとに別々のイメージが紐づけられている様子がわかります。

今回は、つまり、これを自分で作りたいね、ということです。

困ったこと

Docker Hub にあるイメージのうち、公式に展開されているものは、もともとこのような仕組みで(または別のタグ、別のイメージとして)複数の CPU アーキテクチャに対応してくれているものが多いのですが、野良イメージだとそうでない場合があります。

で、今回、実際に amd64 環境で便利に使っていたコンテナを arm64 で動かそうとしたら動かせなかった…… という事があり、そんなわけで自前でビルドすることにしました。

そのイメージの Dockerfile は公開されていたので、Raspberry Pi 上で docker build . すれば使えはするのですが、ビルドのためだけにいちいちそのアーキテクチャのプラットフォームを用意するのも長期的にみると相当イケてないでしょうということで、21 世紀だしエミュレートしてどうにかできるでしょ、みたいな。

方法

さっきのリンク先Buildx というのが書いてあり、それでできるみたいです。現時点では Experimental な機能 なので、覚悟して使いましょう。

Docker Desktop for Windows を使う場合、設定画面の Command Line から、Enable experimental features を有効にする必要があります。

これで docker buildx コマンドが使えるようになるので、あとは さっきのリンク先 の手順通りです。

最初はデフォルトのビルダ default が指定されていますが、これだとマルチ CPU の機能は対応しておらず、multiple platforms feature is currently not supported for docker driver と怒られます。

> docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
default * docker
  default default         running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

> docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t kurokobo/demo:latest .
multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")

ので、BuildKit ベースの新しいビルダを作って、それを使うように設定します。ls したときの * がアクティブなやつです。

> docker buildx create --name multipfbuilder --use
multipfbuilder

> docker buildx ls
NAME/NODE         DRIVER/ENDPOINT                STATUS   PLATFORMS
multipfbuilder *  docker-container
  multipfbuilder0 npipe:////./pipe/docker_engine inactive
default           docker
  default         default                        running  linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

あとは Dockerfile のあるディレクトリを指定してビルドするだけです。--push を指定して、できたイメージは直接リポジトリにつっこみます。初回実行時は BuildKit のコンテナイメージの取得が最初に入ります。

> docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t kurokobo/demo:latest --push .
[+] Building 59.5s (13/13) FINISHED
 => [internal] booting buildkit                                                                                   16.1s
 => => pulling image moby/buildkit:buildx-stable-1                                                                14.5s
 => => creating container buildx_buildkit_multipfbuilder0                                                          1.6s
...
 => [linux/amd64 internal] load metadata for docker.io/library/alpine:3.9                                         13.1s
 => [linux/arm/v7 internal] load metadata for docker.io/library/alpine:3.9                                        10.2s
 => [linux/arm64 internal] load metadata for docker.io/library/alpine:3.9                                         13.1s
 => [linux/amd64 1/2] FROM docker.io/library/alpine:3.9@sha256:414e0518bb9228d35e4cd5165567fb91d26c6a214e9c95899e  9.8s
...
 => [linux/arm64 1/2] FROM docker.io/library/alpine:3.9@sha256:414e0518bb9228d35e4cd5165567fb91d26c6a214e9c95899  11.8s
...
 => [linux/arm/v7 1/2] FROM docker.io/library/alpine:3.9@sha256:414e0518bb9228d35e4cd5165567fb91d26c6a214e9c95899  9.5s
...
 => exporting to image                                                                                            14.4s
 => => exporting layers                                                                                            0.4s
 => => exporting manifest sha256:2ce6c278a94742c9510b15369b72bf62681741e52074c0b11c4c1da8706b1417                  0.0s
 => => exporting config sha256:9913143b883435a3a206777147d7c9aaac67a50e4538b79283eb1dca6a3ef633                    0.0s
 => => exporting manifest sha256:5935a9dde92945f9e4f601cc548918de5076856f7bc06b2137bf0767c5d19978                  0.0s
 => => exporting config sha256:93d0264837f8f039cd002e842511276aaf9ff3355dea4f7171ce6a97b4c0264f                    0.0s
 => => exporting manifest sha256:e023fb745782f5d2eeda3a8dd80fc93ca0f7051a78ecd03a062d8595473ed7b1                  0.0s
 => => exporting config sha256:f5f2bad0db136c6f06bf2d4244814660cf229e66bf9dd18eeb47e958c6033cd6                    0.0s
 => => exporting manifest list sha256:9a058a80760a142ff335305a438dfbb0eb640d910a01e9ee8a319ec1faa00a85             0.0s
 => => pushing layers                                                                                              6.8s
 => => pushing manifest for docker.io/kurokobo/demo:latest                                                         7.0s

--push を指定しないと、docker images にも表示されませんでした。BuildKit 内に キャッシュができるだけのようです。

ビルドしてそのまま使えるようにするには --load を指定すればよさそう…… なのですが、現状、--platform に複数の引数を指定している場合は --load はコケる みたいです。実際、コケました。

BuildKit 自体の機能を正しく使ってキャッシュをどうのこうのとかきちんと何かすればもうすこしいろいろできるのかもですが、まだよくわからんです。

というわけでできました。

Windows と Raspberry Pi で実際に pull すると、別のイメージが降ってくるようになりました。かんぺきです。

なお、できたあとも、手元の Docker ホストには、BuildKit のコンテナ(とそれ用のイメージ)が起動したままで残るようです。使わなくなったら殺そう。

> docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
moby/buildkit       buildx-stable-1     f2a88cb62c92        2 weeks ago         82.8MB

> docker ps -a
CONTAINER ID        IMAGE                           COMMAND             CREATED             STATUS              PORTS               NAMES
9b06292f089c        moby/buildkit:buildx-stable-1   "buildkitd"         2 minutes ago       Up 2 minutes                            buildx_buildkit_multipfbuilder0

応用

GitHub Actions などと組み合わせれば、Dockerfile をコミットしたらこれでビルドして Docker Hub へ…… などもできますね。


Raspberry Pi 4 と Raspberry Pi Imager

今まで Raspberry Pi 3 Model B+ を使っていましたが、ようやく Raspberry Pi 4 Model B (4 GB RAM) を買いました。

電源が USB Type-C コネクタだったり、HDMI 出力が Type-D(HDMI Micro)だったり、ちまちまと 3 系と違うんですね。ケーブルの使いまわしができない……。

ちょうど数日前に 2 年ぶりの LTS である Ubuntu 20.04 がリリースされたニュースもありましたし、入れて遊ぼう…… と思ったものの、まだ Docker が 20.04 をサポートしていない みたいです。19.10 が出たときも Docker が追従するまでにちょっとラグがあったので、仕方ないですね。

Ubuntu 20.04 に 19.10 用の Docker を入れて動かす例もインタネットにはありますが、ちょっとお行儀よく使いたい要件があったので、20.04 自体をあきらめて 18.04 を入れました。

公式のダウンロードページが全部 20.04 に置き換わってしまったので、Raspberry Pi 向けの古いバージョンのバイナリは、cdimage.ubuntu.com から持ってきます。

Raspberry Pi Imager

全然知りませんでしたが、Raspberry Pi Imager というめっちゃ便利なのがリリースされていました。最初の SD カードづくりがこれだけで簡単にできるみたいです。

後者のブログで書かれている通り、最新の Server の LTS と最新の Core しか選べないので、今日時点だと Ubuntu Server はすでに 18.04 は選択肢になく、20.04 しか出てきません。

If you select this option, you will be able to choose from the latest LTS (Long Term Support) Ubuntu server images, or the latest Ubuntu Core images for either armhf or arm64 architectures. Canonical updates these images with every new LTS.

How to install Ubuntu with the new Raspberry Pi Imager
古いバージョンは出てこない

よって、古いバージョンの OS を導入したいときは、結局個別にイメージのダウンロードが必要になってしまうわけですが、とはいえ、これ以外にも機能はあり、

  • SD カードの FAT32 でのフォーマット
    • 64 GB 以上の SD カードでも問題なく使える
  • 任意のイメージの書き込み
    • 古いバージョンの OS を書き込みたいときに使える
  • Raspberry Pi の EEPROM のリカバリ
    • Raspberry Pi がお亡くなりになったとき用

が地味にうれしい実装です。64 GB 以上の SD カードだと、Windows では FAT32 でフォーマットするために地味に面倒な手間が発生していたので、助かります。

便利機能群

Ubuntu 18.04 の導入

イメージを書き込んで起動すれば普通に起動してくるので、あとはノリでどうにかなりますが、公式のチュートリアルもとても親切ですね、すごい。

で、適当に気合で構成したら、/etc/netplan/99-override.yaml あたりにファイルを作って設定を放り込んで、IP アドレスを固定します。家の Wi-Fi の SSID がステルスなので、StackExchange で投稿されている謎ハック を追加で突っ込んでいます。汚い。

network:
    version: 2
    ethernets:
        eth0:
            dhcp4: false
            addresses:
            - 10.96.1.239/24
    wifis:
        wlan0:
            access-points:
                "MY_STEALTH_SSID\"\n  scan_ssid=1\n  #":
                    password: MY_PASSWORD
            dhcp4: false
            addresses:
            - 192.168.0.239/24
            gateway4: 192.168.0.1
            nameservers:
                addresses:
                - 192.168.0.1

Docker と Docker Compose の導入

Docker を入れるには、淡々とガイドに従います。途中、リポジトリを追加するときの CPU アーキテクチャは arm64 です。

Docker Compose を入れるのも、淡々とガイドに従います。arm64 用のバイナリはないので、Alternative Install Options を参考に pip で入れました。入れる前にパッケージがいくつか足りないので足さないとダメでした。

$ sudo apt install -y python3 python3-pip
$ sudo apt install -y libffi-dev libssl-dev
$ sudo pip3 install docker-compose

というわけで、あとは遊ぶだけです。