cloud-initのNoCloudを使ってお試し環境を簡単に構築する

以前cloud-initについて紹介をした。

blog.ty-tbs.com

cloud-initの仕組みはVMを決まったユーザや鍵を使ってセットアップしたり、指定スクリプトを実行したりとクラウドプロバイダ経由でなくても利用したい機能である。

自宅にOpenStackを構築していれば、DatastoreとしてOpenStackが有力な候補となるかもしれないが、「そんなもの自宅にはない」もしくは「もう少しライトにVMを使ってる」という人がほとんどだろう。

そこでNoCloudというDatastoreを使ってqemu/kvmで構築したVMに対してcloud-initを活用してセットアップする。

DatastoreとしてのNocloud

NoCloudはcloud-initのDatastoreとしては少し特殊で、ネットワークを経由せずに起動VMに対してデータを与える役割を担っている。

ではどうやってデータを渡すかというとVFATのローカルディスク経由もしくは、iso9660で外部から与える事ができる。

VM起動確認

まずcloud-initを確認するためのベースイメージを用意する。各ディストリビューションでAWSなどのクラウドプロバイダ上での動作を想定したcloud imageが配布されているが、これを利用すればcloud-initが最初からインストールされているため簡単に利用することができる。

今回はFedoraのcloud imageを利用することにした。 - https://alt.fedoraproject.org/cloud/

NoCloudを利用するためにはuser-datameta-dataをディスクイメージに含める必要がある。

まずmeta-dataを作成する。 ここで指定されている、intance-idについては初回起動かどうかを識別するためのものとドキュメントに記載がある。

Note: that the instance-id provided (iid-local01 above) is what is used to determine if this is “first boot”. So if you are making updates to user-data you will also have to change that, or start the disk fresh.

local-hostanmeはその名の初期ホスト名として利用される。

$ cat << 'EOF' >  meta-data
instance-id: test-vm
local-hostname: test-vm

次にuser-dataを作成する。

ここにはログイン情報などを記載するがせっかくなので、パスワードに加えてsshの公開鍵認証でログインできるように設定する。

今回は最小限のログイン情報を設定したが、様々な設定が可能なのでこちらのドキュメントを参照してほしい。

cat << 'EOF' > user-data
#cloud-config
users:
  - name: test
    groups: users, wheel
    lock_passwd: False
    plain_text_passwd: test
    ssh_pwauth: True
    ssh_authorized_keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqg4+5ISX6LuYfF+197BhGLaPGhtpsuIdl0YM26g7b/rt80l6KdccVqmDbv27dD6gfGx2l5DFFIGb1rPLIUnJ8NCsV3zQWivSRac/8thidRzHWLb/fLvmyOA2LqYeKv2SUubbtQVnm972w+gHAukALitmWp251WvCwzj7K2woMWNj63qFtplDnm8LLVZkhbC2iAvr23sNAz8LX+wsaX79A18mo6f7whTXn

この2つのファイルをイメージファイルに固めてvm起動時にcdromとして認識するようにする。 イメージの作成にはgenisoimageコマンドを利用したが、同じように作成すれば何を使っても問題ない。このときボリュームラベルにcidataもしくはCIDATAを設定しなれければいけないことに注意する。

genisoimage -output cloud-init-conf.iso -volid cidata -joliet -rock user-data meta-data

起動する前にダウンロードしてきたFedoraのcloud imageをそのまま使ってもよいが、毎回新しいイメージを用意するのは面倒なので、バッキングファイルとして残しておくことにする。

sudo qemu-img create -b Fedora-Cloud-Base-32-1.6.x86_64.qcow2 -f qcow2 test-vm.qcow2 20G

この状態でcdromに先程生成したisoデータを設定して、virt-installする。

virt-install --name test-vm --ram 16384 --vcpus 4 --arch x86_64 --os-type linux --hvm --virt-type kvm --file ./test-vm.qcow2 --cdrom ./cloud-init-conf.iso --boot hd --graphics bash --serial pty --console pty --autostart

これで設定に間違えがなければ、インストール後に設定したパスワードやssh鍵でログインすることができる。

cdromからは先程設定したデータが確認できた。

$ sudo mkdir /mnt/cdrom
$ sudo mount /dev/cdrom /mnt/cdrom/
mount: /mnt/cdrom: WARNING: source write-protected, mounted read-only.
$ ls /mnt/cdrom/
meta-data  user-data

入力したしたデータやスクリプト、cloud-initの実行結果などはVM内の/var/lib/cloud/配下で確認することができる。

おまけ

cloud-initではどのdatastoreを利用するのかds-identifyで判定している。 https://github.com/canonical/cloud-init/blob/main/tools/ds-identify#L835-L859 コードを読んでみるとNoCloudの判定のため引数やファイル、ファイルシステムのラベルが最初に設定したcidataもしくはCIDATAなどかをチェックしていることがわかる。

dscheck_NoCloud() {
    local fslabel="cidata CIDATA" d=""
    case " ${DI_KERNEL_CMDLINE} " in
        *\ ds=nocloud*) return ${DS_FOUND};;
    esac
    case " ${DI_DMI_PRODUCT_SERIAL} " in
        *\ ds=nocloud*) return ${DS_FOUND};;
    esac


    for d in nocloud nocloud-net; do
        check_seed_dir "$d" meta-data user-data && return ${DS_FOUND}
        check_writable_seed_dir "$d" meta-data user-data && return ${DS_FOUND}
    done
    # shellcheck disable=2086
    if has_fs_with_label $fslabel; then
        return ${DS_FOUND}
    fi


    # This is a bit hacky, but a NoCloud false positive isn't the end of the world
    if check_config "NoCloud" && check_config "user-data" && check_config "meta-data"; then
        return ${DS_FOUND}
    fi


    return ${DS_NOT_FOUND}
}