👻

Raspberry Pi OS でクラウドイメージの利用

2024/11/15に公開

はじめに

OSインストールは通常だと、インストールメディアを挿入してインストールを進める形になります。
仮想環境でも同様にインストールCDメディアからインストールするというのが普通でしたが、最近ではOSインストール済みの仮想ディスクイメージが配布されています。
こういった仮想ディスクイメージは、クラウドイメージと呼ばれています。こちらを利用するとインストールの手間を省いて手っ取り早く仮想環境を用意することができます。
クラウドイメージは(必要な設定がされており)、cloud-init という仕組みで初期設定することができるようになっています。

ここでは、クラウドイメージで cloud-init を動かしてみます。

参考

https://gihyo.jp/admin/serial/01/ubuntu-recipe/0565
https://cloudinit.readthedocs.io/en/latest/index.html
https://blog.programster.org/create-debian-12-kvm-guest-from-cloud-image

環境

https://zenn.dev/mnod/articles/ed212df5a8786f の環境を利用します。

インストール

クラウドイメージで cloud-init を利用する場合、初期設定したい内容を含んだ所定の形式の iso イメージを cdrom としてマウントします。
この iso イメージを簡単に作るために、必要なパッケージをインストールします。

$ sudo apt install --no-install-recommends cloud-utils

クラウドイメージの入手

例としてDebian。
Debianの公式 https://cloud.debian.org/images/cloud/ からCloudイメージを取得します。

$ sudo curl -L https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2 -o debian-12-genericcloud-arm64.qcow2

$ ls -l /media/work/libvirt/images/debian-12-genericcloud-arm64.qcow2
-rw-r--r-- 1 root root 333499392 Nov  4 19:50 /media/work/libvirt/images/debian-12-genericcloud-arm64.qcow2

$ qemu-img info /media/work/libvirt/images/debian-12-genericcloud-arm64.qcow2
image: /media/work/libvirt/images/debian-12-genericcloud-arm64.qcow2
file format: qcow2
virtual size: 2 GiB (2147483648 bytes)
disk size: 318 MiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false

簡単に初期状態へ戻せるようにしておきます。

$ mv debian-12-genericcloud-arm64.qcow2 debian-12-genericcloud-arm64.qcow2.base
$ qemu-img create -f qcow2 -b debian-12-genericcloud-arm64.qcow2.base -F qcow2 debian-12-genericcloud-arm64.qcow2 2G
Formatting 'debian-12-genericcloud-arm64.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2147483648 backing_file=debian-12-genericcloud-arm64.qcow2.base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16

cloudinit.iso の作成

  • パスワード認証を使用
  • クラウドイメージのデフォルトユーザ(debian)と、rootユーザのパスワードを設定する
  • ログイン時にパス変更を求められないようにする
$ cloud-localds cloudinit.iso <(cat <<EOF
#cloud-config
ssh_pwauth: True
chpasswd:
  expire: false
  users: 
  - name: root
    password: password
    type: text
  - name: debian
    password: password
    type: text
EOF
);

作成したファイルを確認

$ ls -l cloudinit.iso
-rw-r--r-- 1 pi pi 374784 Nov  6 07:41 cloudinit.iso

$ file cloudinit.iso
cloudinit.iso: ISO 9660 CD-ROM filesystem data 'cidata'

$ sudo mount cloudinit.iso /media/tmp/
mount: /media/tmp: WARNING: source write-protected, mounted read-only.

$ cat /media/tmp/meta-data
{
"instance-id": "iid-local01"
}

$ cat /media/tmp/user-data
#cloud-config
ssh_pwauth: True
chpasswd:
  expire: false
  users:
  - name: root
    password: password
    type: text
  - name: debian
    password: password
    type: text

KVMで起動する場合

クラウドイメージ内からコピーしたカーネルと初期化RAMディスクを指定。また 作成した cloudinit.iso を cdrom として利用。

$ sudo qemu-system-aarch64 \
 -machine virt \
 -cpu host \
 -m 1024 \
 -enable-kvm \
 -kernel debian-12-genericcloud-arm64.vmlinuz \
 -initrd debian-12-genericcloud-arm64.initrd.img \
 -append root=/dev/vdb1 \
 -cdrom cloudinit.iso \
 -drive file=debian-12-genericcloud-arm64.qcow2 \
 -net nic,macaddr=52:54:00:12:34:0 -net tap,ifname=tap1 \
 -vnc 0.0.0.0:0 \
 -daemonize

virt-install で作成する場合

$ sudo virt-install --virt-type kvm \
--features acpi=off \
--connect qemu:///system \
--name debian-12-genericcloud-arm64 \
--os-variant debian11 \
--memory 1024 \
--cdrom /media/work/libvirt/images/cloudinit.iso \
--boot kernel=/media/work/libvirt/images/debian-12-genericcloud-arm64.vmlinuz,initrd=/media/work/libvirt/images/debian-12-genericcloud-arm64.initrd.img,kernel_args='root=/dev/vda1' \
--disk /media/work/libvirt/images/debian-12-genericcloud-arm64.qcow2 \
--network network=host-bridge \
--graphics none --serial pty --console pty \
--import

仮想マシンのコンソールが標準出力に接続されるが Ctrl + ] でデタッチする

Domain is still running. Installation may be in progress.
You can reconnect to the console to complete the installation process.

デタッチしたコンソールは virsh console で接続できる

$ sudo virsh list --all
 Id   Name                           State
-----------------------------------------------
 1    debian-12-genericcloud-arm64   running
 -    debian-12.7.0-arm64            shut off

$ sudo virsh console debian-12-genericcloud-arm64
Connected to domain 'debian-12-genericcloud-arm64'
Escape character is ^] (Ctrl + ])

cloud-init の内容の作成(1)

duckduckgo https://duckduckgo.com/ の chat 機能を利用して gpt-4o mini にお伺いする

お伺い内容

cloud-localds を利用してcloudinit.iso を作成したい。
以下の内容のユーザデータ、メタデータ、ネットワークコンフィグを生成したい。
YAMLの内容とcloud-localds のコマンドラインを教えて。
- タイムゾーンJST
- ホスト名は myhost01
- IPアドレス 192.168.11.101/24 デフォルトGW 192.168.11.254、DNS 192.168.11.254, 192.168.11.253
- 10.0.0.1/16 へのネクストホップは192.168.11.1

下されたご宣託

cloud-localds を使用して cloudinit.iso を作成するためには、ユーザーデータ、メタデータ、ネットワーク設定を含むYAMLファイルを作成する必要があります。以下に、必要なYAMLの内容と cloud-localds コマンドラインを示します。

1. YAMLファイルの作成

以下の内容で user-datameta-datanetwork-config の3つのファイルを作成します。

user-data

#cloud-config
timezone: Asia/Tokyo
hostname: myhost01

meta-data

instance-id: iid-local01
local-hostname: myhost01

network-config

version: 2
ethernets:
  eth0:
    dhcp4: no
    addresses:
      - 192.168.11.101/24
    gateway4: 192.168.11.254
    nameservers:
      addresses:
        - 192.168.11.254
        - 192.168.11.253
    routes:
      - to: 10.0.0.0/16
        via: 192.168.11.1

2. cloud-localds コマンドライン

次に、上記のファイルを使用して cloudinit.iso を作成するための cloud-localds コマンドを実行します。以下のコマンドを使用します。

cloud-localds -v cloudinit.iso user-data meta-data network-config

3. ファイルの配置

上記のコマンドを実行する前に、user-datameta-datanetwork-config の各ファイルを同じディレクトリに保存してください。

これで、指定された内容の cloudinit.iso が作成されます。

試してみる

変更したこと

  • ユーザデータには前述のパスワード設定を追記
  • 利用するインタフェース名は enp1s0 とする
$ cloud-localds -v cloudinit.iso user-data meta-data network-config
Usage: cloud-localds [ options ] output user-data [meta-data]

confused by additional args

エラーとなった。現時点でははまだ AI を100%信頼できるわけではない。

慌てず騒がず、以下で再実行

$ cloud-localds -v cloudinit.iso user-data meta-data -N network-config
wrote cloudinit.iso with filesystem=iso9660 and diskformat=raw

作成された内容を確認

$ file cloudinit.iso
cloudinit.iso: ISO 9660 CD-ROM filesystem data 'cidata'

$ sudo mount cloudinit.iso /media/tmp
mount: /media/tmp: WARNING: source write-protected, mounted read-only.

$ cat /media/tmp/meta-data
instance-id: iid-local01
local-hostname: myhost01

$ cat /media/tmp/user-data
#cloud-config
timezone: Asia/Tokyo
hostname: myhost01
ssh_pwauth: True
chpasswd:
  expire: false
  users:
  - name: root
    password: password
    type: text
  - name: debian
    password: password
    type: text

$ cat /media/tmp/network-config
version: 2
ethernets:
  enp1s0:
    dhcp4: no
    addresses:
      - 192.168.11.101/24
    gateway4: 192.168.11.254
    nameservers:
      addresses:
        - 192.168.11.254
        - 192.168.11.253
    routes:
      - to: 10.0.0.0/16
        via: 192.168.11.1

$ sudo umount /media/tmp

前述のオプションで virt-install を実行して、結果を確認する。

  • 所定のパスワードで debian ユーザでログインできる
  • ホスト名が所定のものに変わっている
  • タイムゾーンがJSTになっている
  • ip アドレスが所定のものになっている
  • 指定したとおりルーティングが設定されている
  • 指定したとおり名前解決が設定されている
  • 所定のパスワードで root ユーザでログインできる
$ id
uid=1000(debian) gid=1000(debian) groups=1000(debian),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev)

$ hostname
myhost01

$ date
Sun Nov 10 07:58:12 JST 2024


$ ip a show enp1s0
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:44:23:67 brd ff:ff:ff:ff:ff:ff
    inet 192.168.11.101/24 brd 192.168.11.255 scope global enp1s0
       valid_lft forever preferred_lft forever
    inet6 2405:6580:d400:2900:5054:ff:fe44:2367/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 86388sec preferred_lft 14388sec
    inet6 fe80::5054:ff:fe44:2367/64 scope link
       valid_lft forever preferred_lft forever

$ ip route
default via 192.168.11.254 dev enp1s0 proto static
10.0.0.0/16 via 192.168.11.1 dev enp1s0 proto static
192.168.11.0/24 dev enp1s0 proto kernel scope link src 192.168.11.101

$ cat /etc/resolv.conf
:
:
nameserver 192.168.11.254
nameserver 192.168.11.253
search .

$ host www.yahoo.co.jp
www.yahoo.co.jp is an alias for edge12.g.yimg.jp.
edge12.g.yimg.jp has address 183.79.249.252

$ su -
Password:
# id
uid=0(root) gid=0(root) groups=0(root)

なお、ネットワーク設定は netplan が利用されている。

$ ls -l /etc/netplan/50-cloud-init.yaml
-rw-r--r-- 1 root root 688 Nov 10 07:57 /etc/netplan/50-cloud-init.yaml

$ cat /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        enp1s0:
            addresses:
            - 192.168.11.101/24
            dhcp4: false
            gateway4: 192.168.11.254
            nameservers:
                addresses:
                - 192.168.11.254
                - 192.168.11.253
            routes:
            -   to: 10.0.0.0/16
                via: 192.168.11.1
    version: 2

cloud-init 関連のログは下記。

$ ls -l /var/log/cloud-init*
-rw-r----- 1 root adm  5452 Nov 10 07:57 /var/log/cloud-init-output.log
-rw-r--r-- 1 root adm 90888 Nov 10 07:57 /var/log/cloud-init.log

cloud-init の内容の作成(2)

CA証明書を利用したsshd設定

仮想マシン作成

以下の内容で cloudinit.iso を作成して、virt-install で仮想マシン作成

/media/tmp/meta-data
instance-id: iid-local01
local-hostname: myhost01
/media/tmp/user-data
#cloud-config
timezone: Asia/Tokyo
hostname: ${local-hostname}

write_files:
  - path: /etc/ssh/ca_key
    content: |
      -----BEGIN OPENSSH PRIVATE KEY-----
      (省略)
      -----END OPENSSH PRIVATE KEY-----
    owner: root:root
    permissions: '0600'

  - path: /etc/ssh/ca_cert.pub
    content: |
      (省略)
    owner: root:root
    permissions: '0644'

runcmd:
  - |
    CA_KEY="/etc/ssh/ca_key"
    ssh-keygen -s ${CA_KEY} -I $(hostname) -h /etc/ssh/ssh_host_ed25519_key.pub
    echo "TrustedUserCAKeys /etc/ssh/ca_cert.pub" >> /etc/ssh/sshd_config
    echo "HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub" >> /etc/ssh/sshd_config
    sed -i -e '/#PasswordAuthentication/ s/.*/PasswordAuthentication no/' /etc/ssh/sshd_config
    systemctl restart sshd
/media/tmp/network-config
version: 2
ethernets:
  enp1s0:
    dhcp4: no
    addresses:
      - 192.168.11.101/24
    gateway4: 192.168.11.254
    nameservers:
      addresses:
        - 192.168.11.254
        - 192.168.11.253
    routes:
      - to: 10.0.0.0/16
        via: 192.168.11.1

ssh クライアント側の設定

以下でCA秘密鍵でsshキーに署名。署名したユーザ証明書とsshキーをssh クライアントのカレントディレクトリに配置

$ ssh-keygen -s ca.key -I certificate-test -n debian -z $(date +%Y%m%d%H%M) -V +365d id_ed25519

CA公開鍵の情報で カレントディレクトリに known_hosts ファイルを作成

$ echo "@cert-authority 192.168.11.* $(cat ca.key.pub)" >> known_hosts

ssh config を作成

Host myalias
    HostName 192.168.11.101
    User debian
    IdentityFile ./id_ed25519
    UserKnownHostsFile ./known_hosts

接続テスト

$ ssh -v -F config myalias

:
debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:Yx/G3La3/ckdOIprHoUyQIBoRM2rwGrWJMqfq+Kxwmw, serial 0 ID "myhost01" CA ssh-ed25519 SHA256:p12hRLK8xDAv+ArfcrZS1loLBUXkTC3JRtlRyYZvpwQ valid forever
:
debug1: Host '192.168.11.101' is known and matches the ED25519-CERT host certificate.
debug1: Found CA key in ./known_hosts:1
:
debug1: Offering public key: ./id_ed25519 ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os explicit
debug1: Server accepts key: ./id_ed25519 ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os explicit
:

サーバ上でログ確認

$ journalctl -u ssh:
:
Nov 10 17:21:52 myhost01 sshd[588]: Accepted publickey for debian from 192.168.11.250 port 45000 ssh2: ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os ID certificate-test (serial 202411100738) CA ED25519 SHA256:p12hRLK8x>
:
GitHubで編集を提案

Discussion