Raspberry PiでDockerを動かしたい。環境構築方法を教えて欲しい。
また、活用事例とともに具体的なサーバ構築方法を教えて欲しい。
こんなお悩みを解決します。
今回から、Raspberry Piを用いて、下記のアプリケーションを構築し、LAN内で小型サーバとして運用していきます。
- Webサーバ
- 赤外線制御サーバ
- NAS
まだ、Raspberry Piを購入していない方は、以下の記事を参考にしてください。
【紹介】Raspberry Piの活用事例
続きを見る
全体構成
最初にDocker環境で構築するシステムの全体像を定義しておきます。ただ、使いやすさの関係を考慮して今後変更する可能性もあります。
同じ色の線は、同じネットワークを表し、黒色の線はホスト側のデバイスとつながることを意味します。
また、それぞれの枠はコンテナを用いて実現します。
今回の場合、以下の5つのコンテナが出来上がることになります。
- NAS(Samba)
- Web Server(Node.js)
- DataBase(MariaDB)
- Web Server(NodeRed)
- Infrared Contoroller
Infrared Contorollerは、Alpineベースで環境を構築し、pythonのプログラムを常時実行する予定です。
Docker環境の導入
まずは、Docker環境を導入していきます。
以前の投稿を参考にしながら、Raspberry PiにSSHします。
【解説】Raspberry Piの初期設定(SSH接続・OSアップデート)
続きを見る
Dockerのインストール
SSH後に、以下のコマンドを実行します。
# =====
# 準備
# =====
sudo apt update
# python3のインストール
sudo apt -y install python3-dev python3-pip
# dbus-user-sessionのインストール
sudo apt-get install -y dbus-user-session
# fuse-overlayfsのインストール
sudo apt-get install -y fuse-overlayfs
# slirp4netnsのインストール
sudo apt-get install -y slirp4netns
# uidmapとiptablesのインストール
sudo apt-get install -y uidmap iptables
# =====================
# Dockerのインストール
# =====================
curl -fsSL https://get.docker.com/rootless | sh
Dockerをインストールすると以下のようなメッセージが表示されます。
curl -fsSL https://get.docker.com/rootless | sh
# Installing stable version 20.10.14
# Executing docker rootless install script, commit: 0221ade
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 55.1M 100 55.1M 0 0 9349k 0 0:00:06 0:00:06 --:--:-- 10.0M
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 19.7M 100 19.7M 0 0 9.9M 0 0:00:01 0:00:01 --:--:-- 9.9M
+ PATH=/home/user/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games /home/user/bin/dockerd-rootless-setuptool.sh install
[INFO] Creating /home/user/.config/systemd/user/docker.service
[INFO] starting systemd service docker.service
+ systemctl --user start docker.service
+ sleep 3
+ systemctl --user --no-pager --full status docker.service
● docker.service - Docker Application Container Engine (Rootless)
Loaded: loaded (/home/user/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
Active: active (running) since Fri 2022-04-29 01:25:49 JST; 3s ago
Docs: https://docs.docker.com/go/rootless/
Main PID: 2018 (rootlesskit)
Tasks: 36
CPU: 1.125s
CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/docker.service
tq2018 rootlesskit --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/user/bin/dockerd-rootless.sh
tq2028 /proc/self/exe --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/user/bin/dockerd-rootless.sh
tq2048 slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 2028 tap0
tq2057 dockerd
mq2084 containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.447355395+09:00" level=info msg="loading plugin \"io.containerd.content.v1.content\"..." type=io.containerd.content.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.449342408+09:00" level=info msg="loading plugin \"io.containerd.snapshotter.v1.aufs\"..." type=io.containerd.snapshotter.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.460375375+09:00" level=info msg="skip loading plugin \"io.containerd.snapshotter.v1.aufs\"..." error="aufs is not supported (modprobe aufs failed: exit status 1 \"modprobe: FATAL: Module aufs not found in directory /lib/modules/5.15.32-v8+\\n\"): skip plugin" type=io.containerd.snapshotter.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.460670504+09:00" level=info msg="loading plugin \"io.containerd.snapshotter.v1.btrfs\"..." type=io.containerd.snapshotter.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.462004648+09:00" level=info msg="skip loading plugin \"io.containerd.snapshotter.v1.btrfs\"..." error="path /home/user/.local/share/docker/containerd/daemon/io.containerd.snapshotter.v1.btrfs (ext4) must be a btrfs filesystem to be used with the btrfs snapshotter: skip plugin" type=io.containerd.snapshotter.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.462288888+09:00" level=info msg="loading plugin \"io.containerd.snapshotter.v1.devmapper\"..." type=io.containerd.snapshotter.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.462503369+09:00" level=warning msg="failed to load plugin io.containerd.snapshotter.v1.devmapper" error="devmapper not configured"
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.462610554+09:00" level=info msg="loading plugin \"io.containerd.snapshotter.v1.native\"..." type=io.containerd.snapshotter.v1
4月 29 01:25:50 raspberrypi dockerd-rootless.sh[2084]: time="2022-04-29T01:25:50.463378311+09:00" level=info msg="loading plugin \"io.containerd.snapshotter.v1.overlayfs\"..." type=io.containerd.snapshotter.v1
4月 29 01:25:51 raspberrypi dockerd-rootless.sh[2057]: time="2022-04-29T01:25:51.174232304+09:00" level=warning msg="grpc: addrConn.createTransport failed to connect to {unix:///run/user/1000/docker/containerd/containerd.sock 0 }. Err :connection error: desc = \"transport: error while dialing: dial unix:///run/user/1000/docker/containerd/containerd.sock: timeout\". Reconnecting..." module=grpc
4月 29 01:25:53 raspberrypi dockerd-rootless.sh[2057]: time="2022-04-29T01:25:53.632843052+09:00" level=warning msg="grpc: addrConn.createTransport failed to connect to {unix:///run/user/1000/docker/containerd/containerd.sock 0 }. Err :connection error: desc = \"transport: error while dialing: dial unix:///run/user/1000/docker/containerd/containerd.sock: timeout\". Reconnecting..." module=grpc
+ DOCKER_HOST=unix:///run/user/1000/docker.sock /home/user/bin/docker version
Client:
Version: 20.10.14
API version: 1.41
Go version: go1.16.15
Git commit: a224086
Built: Thu Mar 24 01:44:53 2022
OS/Arch: linux/arm64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.14
API version: 1.41 (minimum version 1.12)
Go version: go1.16.15
Git commit: 87a90dc
Built: Thu Mar 24 01:48:38 2022
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: v1.5.11
GitCommit: 3df54a852345ae127d1fa3092b95168e4a88e2f8
runc:
Version: 1.0.3
GitCommit: v1.0.3-0-gf46b6ba2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
+ systemctl --user enable docker.service
Created symlink /home/user/.config/systemd/user/default.target.wants/docker.service → /home/user/.config/systemd/user/docker.service.
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger user`
[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):
export PATH=/home/user/bin:$PATH
export DOCKER_HOST=unix:///run/user/1000/docker.sock
最後に、INFO
として以下の事が取り上げられているので、対応します。
- To run docker.service on system startup, run: `sudo loginctl enable-linger user`
→sudo loginctl enable-linger user
を実行 ~/.bashrc
に以下の環境変数を追加export PATH=/home/user/bin:${PATH}
export DOCKER_HOST=unix:///run/user/1000/docker.sock
ここで、/home/user
や/run/user/1000
の「user」や「1000」は実行する環境によって変化します。ご自身の環境に合わせて設定してください。
私の環境の場合、~/.bashrc
は以下のようになります。変更箇所は、11行目~13行目になります。
最後に、再起動します。再起動後、以下のコマンドを実行します。
# dockerサービスの状態を確認
systemctl --user status docker
コマンドを実行すると、以下のようなメッセージが表示されます。
systemctl --user status docker
● docker.service - Docker Application Container Engine (Rootless)
Loaded: loaded (/home/user/.config/systemd/user/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-04-29 01:49:28 JST; 2min 30s ago
Docs: https://docs.docker.com/go/rootless/
Main PID: 558 (rootlesskit)
Tasks: 39
CPU: 2.566s
CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/docker.service
tq558 rootlesskit --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/r>
tq568 /proc/self/exe --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up>
tq587 slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 568 tap0
tq595 dockerd
mq758 containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info
4月 29 01:49:32 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:32.884200679+09:00" level=warning msg="Unable to find io controller"
4月 29 01:49:32 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:32.884252882+09:00" level=warning msg="Unable to find cpuset controller"
4月 29 01:49:32 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:32.888897401+09:00" level=info msg="Loading containers: start."
4月 29 01:49:32 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:32.906821882+09:00" level=warning msg="Running modprobe bridge br_netfilter failed with message: modprobe: ERR>
4月 29 01:49:33 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:33.861375549+09:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Dae>
4月 29 01:49:34 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:34.137345715+09:00" level=info msg="Loading containers: done."
4月 29 01:49:34 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:34.526908011+09:00" level=warning msg="Not using native diff for overlay2, this may cause degraded performance>
4月 29 01:49:34 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:34.529413307+09:00" level=info msg="Docker daemon" commit=87a90dc graphdriver(s)=overlay2 version=20.10.14
4月 29 01:49:34 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:34.531295419+09:00" level=info msg="Daemon has completed initialization"
4月 29 01:49:34 raspberrypi dockerd-rootless.sh[595]: time="2022-04-29T01:49:34.662640493+09:00" level=info msg="API listen on /run/user/1000/docker.sock"
これで、Dockerの導入は完了です。
動作確認
Dockerの導入が完了したので、動作確認をします。
以下のコマンドを実行してください。
# nginxのコンテナを作成(しばらくかかります)
docker run --rm -d -p 8080:80 nginx
# nginxのコンテナにアクセス
curl localhost:8080
curlコマンドを実行すると、以下のような結果が返ってくると思います。
完全に一致していなくとも、「Welcom to nginx!」が表示されていれば意図通りの動作となります。
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
使用したコンテナとイメージは不要なので削除しておきます。
# コンテナの削除
docker rm -f $(docker ps -aq)
# コンテナイメージの削除
docker rmi nginx
docker-composeのインストール
今後、コンテナを一元管理していきたいため、docker-composeというものをインストールします。
これは、pipコマンドでインストールできます。
sudo pip3 install docker-compose
インストール完了後、以下のコマンドを実行し、パスが通っていることを確認します。
which docker-compose
/usr/local/bin/docker-compose
お疲れ様でした。これで、Docker環境の導入は完了です。
【追記】well-knownポートに対する対応
今回、rootlessのDockerをインストールしました。
ただ、well-knownポート(1024未満のポート)を使用する場合、rootlessのDockerではエラーが発生します。
回避方法としては、以下の2つの方法があります。
- 代替ポートを指定する
http(ポート:80)の場合、8080:80とし、クライアント側で8080を指定してアクセスする - CAP_NET_BIND_SERVICEの設定を行う
1番目は、Dockerやdocker-composeで、以下のように代替ポートを指定すればOKです。
# Dockerの場合
docker run [中略] -p 8080:80 [省略] # 8080番を80番にバインド
# docker-composeの場合
services:
service1:
[中略]
ports:
- "8080:80" # 8080番を80番にバインド
2番目は、クライアント側で変更できない場合の対応です。
例えば、NASサーバで利用する445/tcp
などが挙げられます。
この場合、Raspberry Piで以下のコマンドを実行します。
# well-knownポートも解放できるように設定
sudo setcap CAP_NET_BIND_SERVICE=ep $HOME/bin/rootlesskit
# Dockerサービスの再起動
systemctl --user restart docker
さいごに
今回はDocker環境を導入しました。
今後は、このDockerを用いて開発を行っていきます。
サーバの勉強にはRaspberry Piが便利だと考えています。
この機会に購入してみてはいかがでしょうか。
【紹介】Raspberry Piの活用事例
続きを見る