はじめに
自宅の玄関に手動でも回せるオートロックを取り付けたいと考え、3Dプリンターとラズパイを駆使し実現できたのですが、機能を増やしたところ、複雑になってしまったためDockerを使って機能ごとにコンテナ化してみました。
オートロックを作成した記事は以下です。
DockerfileやDocker Composeを活用しているので、Dockerを使用する具体例としても見てもらえるといいと思います。
githubにdocker compose用のファイルをまとめているので、詳細はこちらを参照してください。
オートロックの概要
- オートロックはラズパイからサーボモーターを制御して実現する
- 解錠や施錠の操作はLINEから行うため、内部ではLINEからWebhookが送信されたら、必要な情報を抜き出し、JSON形式でメインプログラムに渡す。
- メインプログラムは受け取った情報を見て、ユーザー等をDBに問い合わせる。
- 内部の情報のやり取りの通信プロトコルはMQTTを使用する。
- 詳細な設定等をWebアプリで設定できるようにしている。
システム構成
docker-compose.yaml全文
version: "3"
services:
#--------------- 1. Autolockメインコンテナ---------------
autolock: # サービスの名前
container_name: autolock_main
build:
context: autolock_main # autolock_mainディレクトリをビルドコンテキストとする
dockerfile: Dockerfile # ビルドコンテキスト内のDockerfileからイメージを作成する
image: autolock_main_img #イメージ名をautolock_main_imgとする
privileged: true # 特権モードを有効にする
volumes:
- autolock_setting_volume:/home/pi/autolock/gear_version/etc
networks:
- autolock_net #autolock_netブリッジネットワークに所属する
restart: always #dockerの起動時にコンテナを自動起動する
#--------------- 2. MQTT Brokerコンテナ---------------
mqtt_broker:
container_name: autolock_mqtt_broker
build:
context: mqtt_broker
dockerfile: Dockerfile
image: autolock_mqtt_broker_img
ports:
- "1883:1883" #mqtt
networks:
- autolock_net
restart: always
#--------------- 3. 認証DBコンテナ---------------
auth_db:
container_name: autolock_auth_db
image: mariadb:latest
environment: #.envファイルから呼び出す
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
MARIADB_DATABASE: ${MARIADB_DATABASE}
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
volumes:
- auth_db_volume:/var/lib/mysql
- ./auth_db:/docker-entrypoint-initdb.d
networks:
- autolock_net
restart: always
#--------------- 4. Node.Js+Express(設定用webアプリ配信)コンテナ ---------------
setting_webapp:
container_name: autolock_setting_webapp
build:
context: setting_webapp
dockerfile: Dockerfile
image: autolock_webapp_img
environment: #.envファイルから呼び出す
MARIADB_DATABASE: ${MARIADB_DATABASE}
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
BASE_URL: ${BASE_URL}
ports:
- "8080:3000"
networks:
- autolock_net
restart: always
#--------------- 5. Node.Js+Express(webhook処理)コンテナ---------------
webhook:
container_name: autolock_webhook
build:
context: webhook
dockerfile: Dockerfile
image: autolock_webhook
ports:
- "3000:3000"
networks:
- autolock_net
restart: always
#A.ブリッジネットワークの作成
networks:
autolock_net:
#B.ボリュームの作成
volumes:
auth_db_volume:
autolock_setting_volume:
※コンテナ間で連携するため、コンテナは全て共通のブリッジネットワークに属する
- docker-compose.yamlのA.ブリッジネットワークの作成の部分でautolock_netというネットワークの作成を行なっている。
- B.ボリュームの作成で
auth_db_volume
とautolock_setting_volume
というボリュームの作成を行なっている。
各コンテナの説明
1.Autolockコンテナ
- オートロックのメイン処理を担当している
- 設定を保存するため永続化ボリュームを作成する
- GPIO制御のため、特権モードで起動する
- pigpioやautolockのプロセスなど、複数プロセスを動作させている
2.MQTT Brokerコンテナ
- 内部のAPIはMQTTで実装しているため、NginxとAutolockのデータ送受信、ローカルでのMQTT送受信の中継をしている
- 1883番ポートはホストの1883番ポートにマッピングしている
- mosquittoというライブラリでサーバーを立ち上げている
3.認証DBコンテナ
4.Node.Js+Express(設定用webアプリ配信)コンテナ
- オートロックの設定を行うwebアプリの配信を担当する
- Expressでサーバーを起動し、3000番ポートで待ち受けている
- 3000番ポートはホストの8080番ポートにマッピングしている
- 重要なアプリのため、ローカルのみの配信としている
5.Node.Js+Express(webhook処理)コンテナ
- オートロックの操作をLINEやSlack等のアプリで行うためwebhookを受信する部分を担当する
- 以下の図のような画面(LINE)でボタンを押すと、webhookが送信される
- Expressでサーバーを起動し、3000番ポートで待ち受けている
- 3000番ポートはホストの3000番ポートにマッピングしている

envファイル
以下のような内容のファイルを、docker-compose.yamlと同じディレクトリに.env
という名前で配置しておけばyamlファイルから${}
の中にキーを入れれば値が呼び出せる。
筆者の環境ではenv_templateというファイルを用意しておき、環境によって値を書き換えて名前を.env
にするというスクリプトを初期セットアップで走らせている。
MARIADB_ROOT_PASSWORD=root
MARIADB_DATABASE=autolock_user
MARIADB_USER=pi
MARIADB_PASSWORD=raspberry
BASE_URL=http://your_domain.com
autolockコンテナのDockerfile
他のコンテナでもDockerfileを書いているが、参考としてメインのコンテナのDockerfileについて紹介する。このイメージは複数プロセスを同時に実行する。GPIOを制御するpigpioのプロセスとautolockのメインプロセスである。
また、複数プロセスを管理する際Linux
ではsystemd
が使用されるが、コンテナ上でsystemd
を動作させるのは非常に重たい上に、セキュリティ上の危険があるため。そのため、軽量でコンテナ内で完結する複数プロセス管理パッケージとしてsupervisor
を利用する。
# ベースイメージを指定
FROM takuteh/raspberrypi-os:2023-05-03_bullseye
#これ以降の操作を/home/piで行う
WORKDIR /home/pi
# 非対話モードでの設定
ENV DEBIAN_FRONTEND=noninteractive
# rootを追加
USER root
# pi(一般ユーザー)を作成し、必要な設定を行う
# パスワードをraspberryにして、sudoersにpiを追加する
RUN echo "pi:raspberry" | chpasswd && \
echo "pi ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
#/home/piディレクトリの権限をpi:piにする
RUN chown -R pi:pi /home/pi
# パッケージの更新と必要な依存関係のインストール
RUN apt update && \
apt upgrade -y && \
apt install -y \
supervisor \
git \
g++\
cmake \
pigpio \
mosquitto-clients \
libmosquitto-dev \
libcurl4-openssl-dev\
libmysqlcppconn-dev
#各種設定ファイルとコンテナ起動時のスクリプトをイメージ内に配置
COPY ./supervisor/supervisor.conf /etc/supervisor/supervisord.conf
COPY ./supervisor/conf.d/* /etc/supervisor/conf.d/
COPY ./src/entry.sh /entry.sh
#起動スクリプトに実行権限を付与
RUN chmod +x /entry.sh
# コンテナ起動時にentry.shを実行する
# 複数プロセスを管理するプロセス(supervisor)をフォアグラウンドで実行するスクリプト
ENTRYPOINT ["/entry.sh"]
#これ以降の操作をpiユーザーで実行
USER pi
#autolockのプログラムをgit clone
RUN git clone https://github.com/takuteh/autolock.git &&\
cd autolock
#プログラムをビルドする
RUN cd autolock/gear_version && \
mkdir build && \
cd build && \
cmake .. && \
make
さいごに
筆者の作成したオートロックシステムを具体例として、docker-compose.yamlやDockerfileで実際にどのような場面でどのような設定を使うのか、Dockerfileを書くのはどんなときなのかみたいな、コンテナ技術の嬉しさがどこなのかわからずモヤモヤしていた人の参考になれば良いと思っています。
疑問点やわかりにくいところがあればぜひコメントください!