IoTデバイスのアップデート管理 / Akeurn Advent Calendar 18日目

qiita.com

この記事はAkerun Advent Calendar 18日目の記事です。 Akerun Remote開発担当 @KoheiAKitaが担当します。

一度リリースしたら組み込みのソフトウェアは更新できないは過去の話、ユーザー自身でCD-ROMを用いてソフトウェアアップデートを行ったり、OS自体が自動でアップデートを行ったりなど、ソフトウェアの更新を行い、最新のプログラムを提供するのが当たり前になっています。

IoTデバイスもネットワーク機能を有している端末が多く、搭載しているソフトウェアを常に最新にアップデートを行いたいと思うことでしょう。もしくは、不具合を見つけてしまい、不具合修正版を配信したいという場面もあるでしょう。

弊社で採用している手法、パッケージ管理のtipsについて紹介したいと思います。

1. IoT アップデートシステム

弊社でのソフトウェアアップデートは、端末自身が行う自発的アップデート方式でなく、命令して初めて実行するアップデート方式です。 端末管理者がアップデート操作 → MQTTサーバー → Akerun Remote という流れでアップデート指示を出すことで、端末一つ一つにアップデートを行います。なぜ命令によるアップデート方式を採用したかについては、

  1. バイスの使用状況に応じ、きめ細かい対応が必要である。
    (自発的アップデートの場合は、状況ごとの処理わけをあらかじめ組み込んでおかなければならない)
  2. エラー発生時に人間の判断で様々な対応ができる
    (自発的アップデートの場合は、ありとあらゆるエラー時の処理を組み込んでおく必要がある)
  3. 端末でのアップデート処理をシンプルにできる
    (自発的アップデートは処理が膨大、テストが複雑に)

という大きな3つの理由からです。 そして、IoTデバイス側に、MQTTメッセージを用いてサーバーへ端末状況をPublish(発行)するようにしておけば、MQTTサーバー側でそのメッセージをSubscribe(購読)するようにし、細かい処理を組むというポリシーにすることで、柔軟な変更が可能になるメリットがあります。アップデート時の処理に変更がある場合でも、IoTデバイス側に影響なく変更が可能になる部分が多くなります。

2. パッケージ作成

次にアップデートするファイルは、Debianなら.debファイル、RedHat系なら.rpmとご使用のOSによって異なります。 ただ、IoTデバイスではDebian系のOSの割合は非常に高いのではないでしょうか。ここでは弊社でも採用している.debファイルを扱うことを前提としてお話していきます。

Debianでのアップデートファイル作成は、Debianが定めているディレクトリ構成、必要ファイルを用意します。どのようなファイルが必要か、どのようにディレクトリ構成すべきかは、公式サイトに詳しく説明されています。
参考:(Debian公式サイト)第4章 debian/ ディレクトリー以下に無くてはならないファイル

こちらでも非常に詳しく説明されています。
Debianパッケージの作り方と公開方法: groongaを例にして - ククログ(2010-01-18)

その後、自身のアプリケーションなどをビルドディレクトリ配下に置き、debuildコマンドを実行すると、パッケージのビルドの後自動的にLintianコマンドにより静的チェックを行い、エラーが発生しなければ晴れて.debファイルが作成されます。
参考:(Debian公式サイト)第6章 パッケージのビルド

このファイルが、apt-getから取得でき、インストール可能なファイルとなります。

3. パッケージ管理

さて、アップデートパッケージができたところで、このファイルの管理が必要です。 パッケージ管理は、弊社ではaptlyを使用して行っています。

aptlyはサーバーへのアップロードはもちろんのこと、コマンド実行だけでリポジトリの作成、ミラーの作成、スナップショット、マージ、リリース、バージョン管理を一元管理できるので便利です。 aptlyのできることを公式ページにて図解しています。
https://www.aptly.info/img/schema.png

一般的な手順としては以下のようになります。

  1. aptly repo create -distribution=[ディストリビューション名] -component=[コンポーネント名] [リポジトリ名]
    ローカル環境に、指定した名前でのリポジトリを作成します。

  2. aptly repo add [リポジトリ名] [.debファイル]
    1.で作成したローカルリポジトリに、作成したアップデートパッケージ.debファイルを指定し、登録します。

  3. aptly snapshot create [スナップショット名] from repo [リポジトリ名] 指定したリポジトリにある最後のデータのスナップショット(コピー)を作成します。

  4. aptly publish snapshot [スナップショット名] [サーバー名]
    3.で作成したスナップショットを、サーバーに初回アップロードし、リポジトリを作成します。 ここでいう"初回"とは、サーバーにリポジトリがまだない状態のことです。[サーバー名]でより詳しい指定をすることで、リポジトリ構成をしています。

例として、Amazon S3にアップロードし、debianのフォルダをトップディレクトリに作成、その配下にリポジトリを展開する場合は: s3:[URLアドレス]:debian となります。そうすると、以下のようなディレクトリ構成が自動で作成されます。

[URLアドレス] - debian - dists - [ディストリビューション名] - [コンポーネント名] - binary-XXX
                     ∟ pool - [コンポーネント名] - t - [ディストリビューション名]

"binary-XXX"はアーキテクチャ名によって変化します。Intel CPU環境であればi386amd CPU環境であればamd64など。

dists配下が最新のアップデートパッケージとして配信されるデータフォルダ、pool配下が最新バージョンを含む履歴データのフォルダです。 apt-get install [パッケージ名]=[バージョン]として指定した場合に取得できるデータですね。

2回目以降にアップロードする場合、"publish snapshot"ではなく、"publish switch"に変化しますのでご注意ください。

aptly tips

ここで、aptlyでのtips、、、というほどではないですが、google先生に伺い立てても公式ページ以外はあまりいい内容は出てこなかった、一度登録したデータの削除方法についてご紹介します。 登録データはaptlyシステム内で依存性があり

publish済み >> snapshot作成済み >> データベースに登録のみ

の順で実施するコマンドが増えます。

  1. aptly publish drop [ディストリビューション名] [サーバー名]
    publish済みはここから実行します。いろいろ試しましたが、サーバーのデータを削除するのには、一度リモートリポジトリを削除するしかないようです(もし、リモートのパッケージのみ削除する方法があれば是非お知らせください。)

  2. aptly snapshot drop [スナップショット名]
    snapshot作成ずみの場合はここから実行します。

  3. aptly repo remove [ディストリビューション名] [パッケージ名]
    データベース作成済みの場合はこちらからです。パッケージ名の指定が少し異なり、追加するときは「package_v1.2.0.deb」のように拡張子付きで指定しましたが、削除時は「package_v1.2.0」と、拡張子無しで指定しないといけないようです。この点が分からずにハマっていました。

  4. aptly repo drop [リポジトリ名]
    最後に、リポジトリの削除です。必要なくなった場合はこちらのコマンドでローカルリポジトリを削除できます。

まとめ

ざっくりとした説明でしたが、IoTデバイスでのアップデート管理は、
* アップデート実行方法
* パッケージ管理
の方法が重要で、特に、「アップデート方法」についてのシステムは、システム運用する方法、顧客の状況などを鑑みて設計する必要があり、一番肝となる部分です。 この点を注意し、常に最新のソフトウェアで動作し、安定した運用ができるアップデートシステムを構築していくことになるかと思います。

Akerunをつくっている株式会社フォトシンスでは、Railsエンジニアを募集しています! www.wantedly.com

Akerun Developersサイトもやってます。Akerun APIについては、こちらをご覧ください。 photosynth-inc.github.io