Proxmoxで公式qcow2イメージからVMを作成する（Ubuntu,Rocky,Alma,RHEL）

# はじめに
以前にProxmox上にLinuxVMを新規インストールする手法としてKickstartを利用したエントリを書きました。

https://qiita.com/bashaway/items/c389ff50d4c2f61e3865

が、公式が以下のようなクラウドイメージを提供しているので、これを利用してもっと手軽に実施できました。

* **[Ubuntu](https://cloud-images.ubuntu.com/)**
    * [jammy-server-cloudimg-amd64.img](https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img)
* **[RockyLinux](https://dl.rockylinux.org/pub/rocky/)**
    * [Rocky-9-GenericCloud.latest.x86_64.qcow2](https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2)
* **[AlmaLinux](https://repo.almalinux.org/almalinux/)**
    * [AlmaLinux-9-GenericCloud-latest.x86_64.qcow2](https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2)


RHEL9 はファイルの直接リンクができないのでログイン後に **[ダウンロード > Red Hat Enterprise Linux 製品のソフトウェア](https://access.redhat.com/downloads/content/479/ver=/rhel---9/9.2/x86_64/product-software)** から探してください。


# qcow2形式のイメージをダウンロードする
ファイルをダウンロードして `/var/lib/vz/images/` に配置する。`qm`コマンドでVMを作成する際にフルパスで指定するので、どこでもよいが、WebUIからダウンロードする場合とあわせてここに配置する。

```
wget -P /var/lib/vz/images/ https://dl.rockylinux.org/pub/rocky/9.2/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2
```

例えばRocky9のqcow2ファイルは1GBちょっとのファイルだが、以下のように10Gとして構成されている。これを仮想マシンとして展開すると10Gのディスクを搭載したVMが作成できることになる。

```
# qemu-img info ./Rocky-9-GenericCloud.latest.x86_64.qcow2
image: ./Rocky-9-GenericCloud.latest.x86_64.qcow2
file format: qcow2
virtual size: 10 GiB (10737418240 bytes)
disk size: 943 MiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false
Child node '/file':
    filename: ./Rocky-9-GenericCloud.latest.x86_64.qcow2
    protocol type: file
    file length: 943 MiB (989265920 bytes)
    disk size: 943 MiB
```

# ユーザ情報を含んだCloud-Initファイルを作成する
qcow2ファイルを仮想マシンに展開しただけでは初期設定を手動でやらなければならなくなってしまうので、Cloud-Initを利用する。

前回は `qm` コマンドのオプションでユーザ情報とネットワーク情報を渡したが、今回はユーザ情報として、以下のような初期設定を実施するスニペットを配置する。（SSH鍵の指定や、そのほかパラメータは適宜変更のこと）
* ホスト名、ロケール、タイムゾーン設定
* 初期アカウント `ci-user` を作成し、SSH鍵を配置、SSH経由はパスワード禁止
* SELinuxの無効化
* 追加パッケージの導入
* 再起動

スニペットファイルを `/var/lib/vz/snippets/` に作成する。`qm`コマンドでVMを作成する際にフルパスで指定するので、どこでもよいが、WebUIで管理されるパスにあわせてここに配置する。
```:/var/lib/vz/snippets/ci-user.yaml
#cloud-config

# SYSTEM
hostname: ci-linux
fqdn: ci-linux.example.com
manage_etc_hosts: true
locale: ja_JP.UTF-8
timezone: Asia/Tokyo

# USER
user: ci-user
password: changeme
chpasswd: {expire: False}
ssh_pwauth: False
ssh_authorized_keys:
  - ssh-rsa AAAAB3N～～～

# COMMAND on boot
bootcmd:
 - grubby --update-kernel ALL --args selinux=0

# PACKAGE
package_upgrade: False
packages:
 - qemu-guest-agent
 - lsof

# REBOOT
power_state:
  mode: reboot
```



# Proxmox上にVMを作成
`qm`でqcow2ファイルを`import-from`で展開した場合、ディスクサイズがもとのqcow2ファイルで定義されているサイズとなってしまうため `qm create` 後にすぐ起動せず `qm resize` で指定するディスクサイズに拡張してから起動している。


```:VMのパラメータ設定
# 既存のホスト上で重複しなければOK
VM_ID=999
VM_NAME=ci-linux

# 作成するVMのスペックを指定
# ディスクサイズはqcow2イメージの展開後より大きな値ならOK
VM_CORES=4
VM_MEM=4096
VM_DISKSIZE=16G

# デフォルトのままだとRHELなどでKernelPanicするのでhostや特定のものを指定する
VM_CPUTYPE=x86-64-v3
VM_CPUTYPE=host

# IPアドレスはDHCPも固定も指定可能
VM_IPCONF='ip=dhcp'
VM_IPCONF='ip=10.254.10.99/24,gw=10.254.10.254'

# qcow2イメージはインストールしたいものにあわせて指定する
VM_DISKIMAGE=/var/lib/vz/images/jammy-server-cloudimg-amd64.img
VM_DISKIMAGE=/var/lib/vz/images/Rocky-9-GenericCloud.latest.x86_64.qcow2
VM_DISKIMAGE=/var/lib/vz/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2
VM_DISKIMAGE=/var/lib/vz/images/rhel-9.2-x86_64-kvm.qcow2
```

ユーザ情報のCloud-Init設定を利用してVMを作成する。
なお、スニペットを利用すると `--ciuser` や `--cipassword` など `qm` コマンドのオプションとしてユーザ情報を引き渡す設定はすべて無視される。

```
qm create ${VM_ID} \
 --name ${VM_NAME} \
 --bios ovmf \
 --machine q35 \
 --efidisk0 local-lvm:0 \
 --cpu ${VM_CPUTYPE} \
 --sockets 1 \
 --cores ${VM_CORES} \
 --memory ${VM_MEM} \
 --scsihw virtio-scsi-pci \
 --boot order=scsi0 \
 --agent enabled=1 \
 --scsi0 local-lvm:0,import-from=${VM_DISKIMAGE},format=qcow2,cache=writeback,discard=on \
 --sata0 local-lvm:cloudinit \
 --cicustom "user=local:snippets/ci-user.yaml" \
 --serial0 socket \
 --net0 virtio,bridge=vmbr0,tag=10 \
 --ipconfig0 ${VM_IPCONF} \
&& qm resize ${VM_ID} scsi0 ${VM_DISKSIZE} \
&& qm start ${VM_ID}
```


VM作成時に `--serial0 socket` でシリアルポートを追加しているので以下でシリアルコンソールに接続できる
```
# シリアルターミナルから抜ける場合は Ctrl-o
qm terminal ${VM_ID}
```

VMを削除するにはVMを停止してから削除する。
```
qm stop ${VM_ID} && qm destroy ${VM_ID} --purge
```


# 参考

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/html/configuring_and_managing_cloud-init_for_rhel_9/index

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/html/configuring_and_managing_cloud-init_for_rhel_9/red-hat-supports-these-cloud-init-modules_red-hat-support-for-cloud-init