UbuntuCoreイメージを作成してみる

#UbuntuCoreとは
IoT用途向けに開発されたUbuntuで、Kernelスナップ、gadgetスナップ、Coreスナップ、Snapdスナップ、アプリケーションスナップのsnapパッケージで構成されています。アプリケーションだけでなく、Kernelもスナップで構築されているのでSnapStore（BrandStore）を介して
カーネルスナップのアップデート（FOTA)を簡単に行うことができます。

#SNAPパッケージとは
アプリケーション・ソフトウェアとその依存パッケージをバンドルしたパッケージになります。SNAPパッケージは[SnapStore](https://snapcraft.io/store)を通して公開されており、様々な既存アプリケーションのスナップパッケージが登録されています。

#環境
Ubuntu 18.04がインストールされたラップトップでテストをしています。
(追記)Ubuntu Core20はUbuntu 20.04がインストールされたラップトップでテストをしています。

#UbuntuCoreイメージの作成の流れ
今回はCanonicalが提供しているX86用のKernelスナップとgadgetスナップを使用してUbuntuCore18イメージを作成しようと思います。手順としては以下のようになります。
(追記)UbuntuCore20イメージの場合も同様の手順ですが、モデルファイルのフォーマットが変更されています。

1）下準備
2）モデルファイルの記述とモデルアサーションの作成
3）Ubuntu-imageスナップを利用して、イメージを作成する
4）ラズベリーパイ３B+で作成されたイメージをテストする

#下準備
####必要なソフトウェアのインストール
UbuntuCoreのイメージを作成するのに必要なUbuntu-imageスナップをインストールします。
<details><summary>必要なソフトウェアのインストール</summary><div>

```
$ sudo snap install --classic snapcraft
$ sudo snap install --classic ubuntu-image
$ sudo apt install qemu-kvm
```

</div></details>

####アカウントとSSH鍵の作成と登録
まだ作成されていない場合は[UbuntuOneのアカウント](https://login.ubuntu.com/)を作成します。ここで設定したユーザー名は後々必要になるのでメモをしておくと良いと思います。
![UbuntuOne account.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692438/36073d19-d6a0-2ce2-8ae6-3ce7b3cabcf9.png)

アカウントを作成したら、ターミナルで鍵を作成します。パスフレーズは必須ではありませんが、
設定した場合は忘れないようにしてください。
注意：鍵は~/.sshフォルダの中に作成してください。それ以外の場所で作成した場合は~/.sshにコピーしてください。

<details><summary>SSH鍵の作成</summary><div>

```
$ cd ~/.ssh
$ ssh-keygen -t rsa -C "your_email@example.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/your_user_here/.ssh/id_rsa): hiro
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 

```

</div></details>

公開鍵と秘密鍵のペアが作成されているので、公開鍵の内容（私の場合はhiro.pub）をUbuntuOneアカウントに登録します。(エディタで開いてコピー&ペーストして緑色のImportSSHKeyボタンをクリック）これはUbuntuCoreデバイスにSSH接続するための鍵になります。

![key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692438/95061f33-463b-ef33-bc24-5b97f09862c1.png)

####snapアカウントIDの確認
[dashboard.snapcraft.io](https://dashboard.snapcraft.io/)にアクセスして
アカウントの詳細ページにあるSnapアカウントIDをメモします。


![Snapcraftio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692438/705088a4-e48a-e3dc-82d9-ce23bc01cb9d.png)

####snapストアに鍵を登録する
下記のコマンドを実行すると、Snapcraft.ioにログインしていない場合は、
ユーザアカウントとパスワードを入力を求められるので、それぞれ入力します。
今回はパスフレーズを入力する必要があるので、パスフレーズを設定します。
この鍵はモデルファイルに署名をする際の鍵になります。

<details><summary>鍵の作成と登録</summary><div>

```
$ snapcraft create-key labkey
You are required to login before continuing.
Enter your Ubuntu One e-mail address and password.
If you do not have an Ubuntu One account, you can create one at https://snapcraft.io/account
Email:
Password: 
 
We strongly recommend enabling multi-factor authentication: https://help.ubuntu.com/community/SSO/FAQs/2FA
Passphrase:
Confirm passphrase:

$ snapcraft register-key labkey
Enter your Ubuntu One e-mail address and password.
If you do not have an Ubuntu One account, you can create one at https://snapcraft.io/account
Email: your_email@example.com
Password: 
 
We strongly recommend enabling multi-factor authentication: https://help.ubuntu.com/community/SSO/FAQs/2FA
Registering key ...
Done. The key "labkey" (...) may be used to sign your assertions.


```

</div></details>

#モデルファイルの記述
モデルファイルはデバイスのプロパティなどを指定したJSONフォーマットのファイルになります。
必要な内容は下記のとおりになります。Kernel,及びgadgetでそれぞれ使用するSnapパッケージを
指定します。authority-id、brand-idにはSnapアカウントIDを指定します。timestampは”date -Iseconds --utc”で取得し指定します。

<details><summary>model-test.json(UC18)</summary><div>

```
  1 {
  2     "type": "model",
  3     "authority-id": "PcQpbi62D9Fvr3TBxaS5lf3M9650ceGr",
  4     "brand-id": "PcQpbi62D9Fvr3TBxaS5lf3M9650ceGr",
  5     "series": "16",
  6     "model": "RPI",
  7     "architecture": "armhf",
  8     "base": "core18",
  9     "gadget": "pi=18-pi3",
 10     "required-snaps": [ "modem-manager" ],
 11     "kernel": "pi-kernel=18-pi3",
 12     "timestamp": "2020-10-19T07:16:03+00:00"
 13 }                                                  

```
</div></details>

<details><summary>model-test.json(UC20)</summary><div>

```
{
    "type": "model",
    "series": "16",
    "authority-id": "PcQpbi62D9Fvr3TBxaS5lf3M9650ceGr",
    "brand-id": "PcQpbi62D9Fvr3TBxaS5lf3M9650ceGr",
    "model": "ubuntu-core-20-armhf",
    "architecture": "armhf",
    "timestamp": "2019-11-14T07:13:24.0Z",
    "base": "core20",
    "grade": "dangerous",
    "snaps": [
        {
            "name": "pi",
            "type": "gadget",
            "default-channel": "20/stable",
            "id": "YbGa9O3dAXl88YLI6Y1bGG74pwBxZyKg"
        },
        {
            "name": "pi-kernel",
            "type": "kernel",
            "default-channel": "20/stable",
            "id": "jeIuP6tfFrvAdic8DMWqHmoaoukAPNbJ"
        },
        {
            "name": "core20",
            "type": "base",
            "default-channel": "latest/stable",
            "id": "DLqre5XGLbDqg9jPtiAhRRjDuPVa5X1q"
        },
        {
            "name": "snapd",
            "type": "snapd",
            "default-channel": "latest/stable",
            "id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4"
        }
    ]
}                                                

```


(追記)UbuntuCore20の新しいフィールド"grade"
UbuntuCore20ではモデルファイルに新しく"grade"が追加されました。ここではとりあえずdangerousグレードを使用します。dangerousグレードはいくつかの制約を緩和し（たとえば、必須のスナップID）、アサートされていないスナップ、devmodeスナップの存在を許可します。dangerousは開発目的のみを対象としています。またSnapIDは"snap info"コマンドで調べられます。

</div></details>


モデルファイルに署名をしてモデルアサーションを作成します。
```
 $ snap sign -k labkey model-test.jason > model-test.assert
```

#UbuntuCoreイメージの作成
UbuntuCoreのイメージはUbuntu-imageスナップを利用して簡単に作成できます。
今回はSnapの更新やあたらしいSnapアプリケーションの追加を考えて２Gバイトのイメージを
作成しました。

```
$ubuntu-image snap -i 2G model-test.assert　
```

コマンド完了後、pi.imgというファイルが生成されているので、これをDDコマンドを使ってSDカードに書き込みます。私の環境ではSDカードは/dev/sddにマウントされていましたが、lsblkなどを利用してお使いの環境でどこにマウントされたかを確認し適宜書き換えてください。

```
$sudo dd bs=32MB if=pi.img of=/dev/sdd 　　　　
$sync
```

#UbuntuCoreの起動
ラズベリーパイにモニタ（HDMI)、USBキーボードを接続し、SDカードをセットして電源を入れます。しばらくすると画面に”Press Enter to configure”と表示されるのでエンターキーを押します。画面上の指示に従ってネットワークの設定画面、UbuntuOneに登録したメールアドレスの入力をすると下のような表示がされるます。![ubntu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692438/02c880e4-f625-811c-c17a-87bc80cda8b1.png)
この状態でターミナルからラズベリーパイにSSHで接続することができます

```
$    ssh masahiro20200511@172.22.2.28
The authenticity of host '172.22.2.28 (172.22.2.28)' can't be established.
ECDSA key fingerprint is SHA256:v0eyxHYfogqq75MVRbimehtU3lBKgk7dnUSSvDktlUA.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.22.2.28' (ECDSA) to the list of known hosts.
Welcome to Ubuntu Core 18 (GNU/Linux 4.15.0-122-generic armv7l)

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

 * Ubuntu Core:     https://www.ubuntu.com/core
 * Community:       https://forum.snapcraft.io
 * Snaps:           https://snapcraft.io

This Ubuntu Core 18 machine is a tiny, transactional edition of Ubuntu,
designed for appliances, firmware and fixed-function VMs.

If all the software you care about is available as snaps, you are in
the right place. If not, you will be more comfortable with classic
deb-based Ubuntu Server or Desktop, where you can mix snaps with
traditional debs. It's a brave new world here in Ubuntu Core!

Please see 'snap --help' for app installation and updates.
masahiro20200511@localhost:~$ 
```


中川　雅裕　Canonical Japan (Iot Field Engineer)
Ubuntu Blog: https://jp.ubuntu.com/blog
Canonical Japan: https://jp.ubuntu.com/
Email: masahiro.nakagawa@canonical.com
Email:info-jp@canonical.com
Phone: 03-6205-3075