
はじめに:Pi Zero Wでのコンテナ運用の現実
Raspberry Pi Zero Wは、そのサイズと価格の安さから2017年頃にちょっとしたブームになりました。実用上の制約は多いものの、今でも魅力あるマシンです。筆者も手元にPi Zero用のセンサーHATがあったため、これでセンサー値を可視化して再活用しようと考えました。
しかし、これをコンテナホストとして活用しようとすると意外な壁にぶつかります。それはDockerのARMv6サポート終了です。Docker公式は古いARMアーキテクチャのバイナリ提供を終了しており、2026年現在Pi Zero WでDockerを動かすのは茨の道です。
そこで採用したのが Podman です。これはRed Hat主導で開発されているコンテナエンジンで、デーモンレスで動作するため軽量です。何より、Debian / Raspberry Pi OSの標準パッケージとして提供されているため、apt install するだけで素直に動くのが最大の利点です。
本記事では、Dockerに見捨てられたPi Zero Wを、Podman Quadletを使って「モダンなコンテナ環境」として蘇らせる方法を紹介します。
前提条件:OSとカーネルの準備
Raspberry PiでPodmanを利用する場合、いくつか落とし穴があります。
最新のOSを利用する
Podmanの強力な機能であるQuadlet(後述)を利用するには、比較的新しいバージョンのPodmanが必要です。古いOSを使っている場合は、最新のRaspberry Pi OS(Trixie以降)をクリーンインストールしてください。
Podmanのインストール
必要な依存パッケージ(uidmap)を含めてインストールします。
sudo apt update sudo apt install podman uidmap
カーネルパラメータの変更
Raspberry Pi OSのデフォルト設定では、コンテナの実行に必要なメモリーコントローラー(cgroups)が無効化されています。これを有効にしないと、Podmanは起動してもコンテナ作成時にエラーを吐いて止まります。
/boot/firmware/cmdline.txt を開き、行末に以下のパラメータを追記して再起動します。
cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1
ランタイム:Podman Quadlet
Podmanを採用する上で、コンテナの自動起動管理をどうするかという課題があります。今回は Quadlet という機能を試してみました。
Quadletは、Systemdのユニット生成ツールです。Docker Composeに似た宣言的なファイルで構成を定義しておくと、Podmanがそれを読み取り、SystemdのServiceファイルを自動生成してくれます。
センサーからメトリクスを収集するPrometheus Exporterのような常駐プロセスの場合、OS起動と同時に確実に立ち上がってほしいものです。Quadletを使えば、コンテナを「OS標準のSystemdサービス」として扱えるため、再起動時の挙動や依存関係の定義が非常にシンプルになります。
実際の定義例(温湿度センサー監視用)を見てみましょう。
# /etc/containers/systemd/rpi-sensor-exporter.container [Container] ContainerName=rpi-sensor-exporter Image=ghcr.io/hnw/rpi-sensor-exporter:latest PublishPort=9101:9101 # センサーデバイス(I2C)のマッピング AddDevice=/dev/i2c-1:/dev/i2c-1 [Service] # コンテナが停止しても自動再起動する Restart=always [Install] WantedBy=multi-user.target
Docker Composeと記述量は大差ありませんが、[Service] や [Install] セクションからわかる通り、Systemd風のフォーマットになっています。このファイルを /etc/containers/systemd/ に配置し、デーモンをリロードするだけでサービス化完了です。
sudo systemctl daemon-reload sudo systemctl start rpi-sensor-exporter
これで systemctl status rpi-sensor-exporter でログやステータスを確認できるようになります。Podmanの理解度が高くなくても、使い慣れたSystemd管理のデーモンのつもりで使えるのは大きなメリットだと思います。
コンテナビルド:Go + ko + GitHub Actions
ランタイムが決まっても、ARMv6用のコンテナイメージをどうビルドするかという問題が残ります。
言語選定の重要性(Python vs Go)
余談ですが、今回コンテナ化したいアプリがGo製だったのはラッキーでした。
もしこれがPythonやNode.jsだった場合、ARMv6用のバイナリ(Wheel等)が提供されていないライブラリが多く、pip install のたびにC/Rustのコンパイル待ちが発生したり、クロスコンパイル環境の構築に苦戦したりしていたでしょう。
Go言語(特に CGO_ENABLED=0)の強力なクロスコンパイル機能と、後述するツールのおかげで、快適な開発環境が構築できました。
Docker build (QEMU) ではなく ko を使う
通常、x86マシン上でARMv6用イメージをビルドするにはQEMUエミュレーションを使います。しかし、わざわざエミュレーションのオーバーヘッドをかけてビルドするのは効率的ではありません。
そこで、Go製のイメージビルドに ko を採用しました。
コンテナイメージの実体は、実は単なるファイルのアーカイブ(tar)とメタデータです。ko はこの点に着目し、Goでクロスコンパイルしたバイナリを、Dockerデーモンを介さずに直接イメージ形式のアーカイブとして出力するというアプローチを取っています。
QEMU環境下で COPY や RUN を実行してファイルシステムを構築するのではなく、単にバイナリを生成してtarで固めるだけなので、CPU本来の速度でARMv6用イメージを生成できます。
ベースイメージをAlpineに固定する
ko のデフォルトベースイメージはARMv6をサポートしていません。そのため、.ko.yaml で明示的に Alpine Linux を指定し、かつ CGO_ENABLED=0 で静的リンクバイナリを作成するようにします。
# .ko.yaml defaultBaseImage: alpine defaultLdflags: - -s - -w
GitHub Actionsでの設定
この構成はCI/CDとも相性抜群です。GitHub Actions上で ko を走らせれば、シンプルな記述でマルチアーキテクチャビルドが完了します。
以下は実際に使用しているWorkflowの抜粋です。--platform に linux/arm/v6 を指定しているのがポイントです。
- name: Setup Go uses: actions/setup-go@v5 with: go-version: '1.25' - name: Install ko uses: ko-build/setup-ko@v0.6 - name: Build and Push run: | ko build . \ --bare \ --platform=linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 \ --tags=latest \ --image-label org.opencontainers.image.source=https://github.com/${{ github.repository }} env: KO_DOCKER_REPO: ghcr.io/${{ github.repository }} CGO_ENABLED: 0
これにより、GitHubにコードをPushしたら自動的にPi Zero Wで動くイメージが生成されるようになります。
おわりに
シングルコア・メモリ512MBのPi Zero Wにおいて、コンテナ運用は非現実的だと思われている方も多いのではないでしょうか。しかし、 Podman とGo製アプリのコンテナの組み合わせであれば、問題なく動作することが分かりました。
実際に運用中のメトリクスを見ても、リソース不足で落ちることもなく安定しています。皆さんも昔買ったPi Zero Wを引っ張り出してみてはいかがでしょうか。
