はじめに
自宅ラボ環境に KVM + Cockpit 構成での簡易 IaaS 環境を構築したので構築メモを記載する
もともとは ESXi で自宅ラボサーバ (NUC) を構築していたが、2024 年に無償版 ESXi の提供が終了となったため、切り替えを進めるために試している
インストール先は NUC (Intel 版と ASUS 版) と呼ばれるミニ PC
ホスト OS は Rocky9 と Ubuntu24.04 LTS の両方で試した結果を記載している
OS インストールから実施しており、OS インストール後の設定方法は Ansible コードにしている
※ 導入後の画面。GUI でノードの仮想マシン・ネットワーク・ストレージなどを管理できる
Cockpit とは
Cockpit の開発元は RedHat 社がスポンサーとなっているフリーソフトウェアプロジェクトで、 LGPL v2.1+ で開発されている
様々な機能を提供している (公式サイトより抜粋)
- ネットワーク設定の検査と変更
- ファイアウォールを設定する
- ストレージの管理(RAIDおよびLUKSパーティションを含む)
- 仮想マシンの作成と管理
- コンテナをダウンロードして実行する
- システムログの閲覧と検索
- システムのハードウェアを検査する
- ソフトウェアのアップグレード
- パフォーマンスを監視する
- ユーザーアカウントを管理する
- systemdベースのサービスを検査し、操作する
- ローカルウェブブラウザでリモートサーバー上のターミナルを使用する
- 複数のコックピットサーバーを切り替える
- 増え続けるアプリやアドオンをインストールして、コックピットの機能を拡張します
サポート OS
サポート OS は以下の通り
- 利用可能 & テスト済み
- Fedora, RHEL (RedHat Enterprise Linux), Fedora CoreOS, CentOS, Debian, archlinux, Ubuntu
- 利用可能
- clearlinux, Tumbleweed, SUSE Linux Enterpise Micro
実行環境
サーバ
本環境では、2つの OS 種別のインストール先として、下記 2サーバを用意して実行する
構築時のポートと複数ネットワーク収容 (VLAN Trunk) 用のポートを分けるために、USB NIC を追加で入れている
項目 | サーバ1 | サーバ2 |
---|---|---|
サーバ | NUC8i5BEH | NUC14RVHI7 |
CPU | Intel Core i5-8259U 4Core/8Thread |
Intel Core Ultra 7 155H 16Core(P6/E8/LPE2)/22Thread |
Memory | 64GiB (DDR4-3200 32BiB x2) | 96GiB (DDR5-5600 48GiB x2) |
Disk | 500GB PCIe Gen3 | 1TB PCIe Gen4 |
拡張 NIC | USB NIC 1G x1 (LUA4-U3-AGTE-NBK) |
USB NIC 1G x1 (LUA5-U3-AGTE-NBK) |
ホスト名 | nuc02 | nuc04 |
Install OS | Rocky9.5 | Ubuntu24.04 LTS |
構成
概要図は下記の通り、詳細は書かないが Gateway となる Router とサーバを収容する Switch を分けて構築している
機器は他の記事でも使用している、EdgeRouter ER-X と GS108T を使用する
操作PC
OS インストール用の USB メモリ作成で使用する
MacBook Air 15インチ, M3, 2024, MacOS Sequoia 15.3(24D60)
構築
下記の順番で、準備・インストール・設定を実施する
- インストール USB 作成
- OS インストール
- KVM + Cockpit 設定 (ansible)
1. インストール USB 作成
1.1. ISO ファイルダウンロード
Ubuntu24.04
Ubuntu Server 24.04 LTS
を ubuntu.com からダウンロードする
※ 本記事では 24.04.1 LTS で記載しているが、書いている途中で 24.04.2 LTS がリリースされた
Rocky9
Rocky Linux 9
の Minimal ISO
を rockylinux.org からダウンロードする
※ 本記事では 2025.02.22 時点で最新の v9.5
を使用する
1.2. USB メモリをフォーマット
下記の流れで実施する
- USBメモリをMacに挿入
-
ディスクユーティリティ
開く(Command + Space → 「ディスクユーティリティ」と入力) - 左のリストからUSBメモリを選択
-
消去
をクリックし、MS-DOS (FAT32)
でフォーマット -
消去
をクリックしてフォーマット
1.3. USB メモリに書き込み
USBデバイス名を下記コマンドで確認
diskutil list
% diskutil list
...
/dev/disk4 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *31.0 GB disk4
1: DOS_FAT_32 NO NAME 31.0 GB disk4s1
USB メモリをアンマウントする
diskutil unmountDisk [USBメモリデバイス名]
% diskutil unmountDisk /dev/disk4
Unmount of all volumes on disk4 was successful
USB メモリへ ISO ファイルを書き込みを実施する
sudo dd if=[ダウンロードパス]/ubuntu-24.04.1-live-server-amd64.iso of=/dev/disk4 bs=1m status=progress
sudo dd if=[ダウンロードパス]/Rocky-9.5-x86_64-minimal.iso of=/dev/disk4 bs=1m status=progress
% sudo dd if=/Users/suzuyu/Downloads/ubuntu-24.04.1-live-server-amd64.iso of=/dev/disk4 bs=1m status=progress
2762997760 bytes (2763 MB, 2635 MiB) transferred 201.560s, 14 MB/s
2645+1 records in
2645+1 records out
2773874688 bytes transferred in 201.772883 secs (13747510 bytes/sec)
USB メモリを取り出す
diskutil eject [USBメモリデバイス名]
% diskutil eject /dev/disk4
Disk /dev/disk4 ejected
2. OS インストール
必要に応じて Boot 順番を BIOS で USB メモリを優先するように設定して起動する。起動後は下記のページ対応で設定をしていく (特別なことはしてない)
2.1. Ubuntu24.04 インストール
ページ | 選択・設定例 |
---|---|
Welcom page | English |
Installer update available | Continue without updating |
Keyboard configuration | Layout: [Japanese ], Variant: [Japanese ], [ Done ]
|
Choose the type of installation |
(X) Ubuntu Server , [ Done ]
|
Network configuration | 環境に応じた IP アドレス設定をする (本環境はルータ側の DHCP で実施しているので何もせずに進める), [ Done ]
|
Proxy configuration | [ Done ] |
Ubuntu archive mirror configuration | [ Done ] |
Guided storage configuration | (X) Use an entire disk |
Storage configuration |
[ Done ] -> Confirm destructive action -> [ Continue ]
|
Profile configuration | Your name: 自分のアカウント名 , Your servers name: サーバー名, Pick a username: 自分のアカウント名 , Choose a password: パスワード , Confirm your password: パスワード , [ Done ]
|
Upgrade to Ubuntu Pro |
(X) Skip for now , [ Continue ]
|
Installing system | Installation complete! が出るまで待って、[ Reboot Now ]
|
Please remove th installation medium, then press ENTER: | USB メモリを抜いて、Enter を押す |
起動後は次の ansible での設定のみとなる
2.2. Rocky9 インストール
ページ or 項目 | 選択・設定例 |
---|---|
WELCOM TO ROCKY LINUX 9.5 |
Japanese -> 続行(C)
|
インストール先(D) | OSインストールするローカルドライブを指定する , ストレージの設定 カスタム(C) , 完了(D) 手動パーティション設定 不要な既存領域をクリックして - で削除する -> ここをクリックすると自動作成します(C) -> /home を - をクリック (homeに大きく割り当てがデフォルトされるため) -> / をクリックして要求される容量: に最大値を割り当てる -> 完了(D) 変更を許可する(A) をクリック |
ソフトウェアの選択 |
最小限のインストール , 完了(D)
|
ネットワークとホスト名(N) | メインで利用するインターフェースを左上のボックで オン 変える, ホスト名(H): にホスト名を入力して 適用(A) をクリック, 完了(D) |
時刻と日付(T) | 地域(R): アジア, 都市(C): 東京, 完了(D) |
root パスワード(R): | root パスワード(R) : パスワード入力, 確認(C): 再度入力, 完了(D) |
ユーザーの作成(U) | (F): ユーザ入力, ユーザー名(U): アカウント名入力 , [x] このユーザーを管理者にする(M), [x] このアカウントを使用する場合にパスワードを必要とする(R), パスワード(P) パスワード入力, パスワードの確認(C) 再度入力, 完了(D) |
インストールの開始(B) | クリック |
システムの再起動(R) | クリック |
起動後は次の ansible での設定のみとなる
3. KVM + Cockpit 設定 (ansible)
OS インストール後から初期設定として下記をまとめた ansible playbook を下記に共有する。ansible 実行以外は何も設定しなくていいようにしている
- LVM 拡張
- Ubuntu は初期設定が 100GB になっているので、残りのサイズでディスクサイズを拡張しておく
- upgrade & update
- 最新化をする。必要に応じてリブートする
- KVM と Cockpit の導入
- 必要な package のインストール
- libvirtd, cockpit, NetworkManager の start と有効化(再起動対応)
- 既存 Interface を Cockpit で管理できるように NetworkManager 管理に書き換えて適用
- NetworkManager にすると systemd-networkd-wait-online.service がうまく動作しないので止める (Ubuntu)
- libvirt, kvm グループに ansible_user もしくは ansible 実行ユーザを登録
---
- name: Extend LVM and Resize Filesystem (Ubuntu Only)
hosts: cockpithost
become: yes
tasks:
- name: Check current LVM size
command: lvs --noheadings -o lv_size --units G --nosuffix /dev/ubuntu-vg/ubuntu-lv
register: current_lvm_size
changed_when: false
when:
- ansible_distribution == 'Ubuntu'
- name: Get available free space in volume group
command: vgs --noheadings -o vg_free --units G --nosuffix ubuntu-vg
register: vg_free_space
changed_when: false
when:
- ansible_distribution == 'Ubuntu'
- name: Extend LVM logical volume if there is free space
command: lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
register: lvextend_result
changed_when: "'successfully resized' in lvextend_result.stdout"
when:
- ansible_distribution == 'Ubuntu'
- vg_free_space.stdout | float > 0
- name: Resize filesystem
command: resize2fs /dev/ubuntu-vg/ubuntu-lv
when:
- ansible_distribution == 'Ubuntu'
- lvextend_result.changed
- name: Update
hosts: cockpithost
become: yes
tasks:
- name: Update and upgrade all packages (Ubuntu)
apt:
update_cache: yes
upgrade: dist
when:
- ansible_distribution == 'Ubuntu'
- name: Check if reboot is required (Ubuntu)
stat:
path: /var/run/reboot-required
register: reboot_flag
when:
- ansible_distribution == 'Ubuntu'
- name: Reboot if required (Ubuntu)
reboot:
when:
- ansible_distribution == 'Ubuntu'
- reboot_flag.stat.exists
- name: Install dnf-utils (for needs-restarting) (Rocky)
dnf:
name: dnf-utils
state: present
when:
- ansible_distribution == 'Rocky'
- name: Update and upgrade all packages (Rocky)
dnf:
name: '*'
state: latest
update_cache: yes
when:
- ansible_distribution == 'Rocky'
- name: Check if reboot is required (Rocky)
command: needs-restarting -r
register: reboot_flag
failed_when: reboot_flag.rc not in [0,1]
changed_when: reboot_flag.rc == 1
when:
- ansible_distribution == 'Rocky'
- name: Reboot if required (Rocky)
reboot:
when:
- ansible_distribution == 'Rocky'
- reboot_flag.rc == 1
- name: Enable KVM and Install Cockpit
hosts: cockpithost
become: yes
tasks:
- name: Install KVM, Cockpit (Ubuntu)
apt:
name:
- qemu-kvm
- libvirt-daemon
- libvirt-clients
- bridge-utils
- cockpit
- cockpit-machines
- cockpit-networkmanager
- nfs-common
state: present
update_cache: yes
when:
- ansible_distribution == 'Ubuntu'
- name: Install EPEL repository (Rocky)
dnf:
name: epel-release
state: present
when:
- ansible_distribution == 'Rocky'
- name: Install KVM, Cockpit (Rocky)
dnf:
name:
- qemu-kvm
- libvirt-daemon
- libvirt-client
- bridge-utils
- cockpit
- cockpit-machines
- cockpit-networkmanager
- nfs-utils
state: present
update_cache: yes
when:
- ansible_distribution == 'Rocky'
- name: Check if CPU supports KVM
command: kvm-ok
register: kvm_support
ignore_errors: yes
changed_when: false
when:
- ansible_distribution == 'Ubuntu'
- name: Enable and start libvirtd service
systemd:
name: libvirtd
enabled: yes
state: started
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Rocky'
- name: Enable and start Cockpit service
systemd:
name: cockpit
enabled: yes
state: started
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Rocky'
- name: Enable and start NetworkManager service
systemd:
name: NetworkManager
enabled: yes
state: started
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Rocky'
- name: Add current user to libvirt and kvm groups
user:
name: "{{ ansible_user | default(lookup('env', 'USER')) }}"
groups: libvirt,kvm
append: yes
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Rocky'
- name: Backup the current netplan configuration
copy:
src: /etc/netplan/50-cloud-init.yaml
dest: /etc/netplan/50-cloud-init.yaml.bak
remote_src: yes
register: backup_result
when:
- ansible_distribution == 'Ubuntu'
- name: Set renderer to NetworkManager in Netplan configuration if not set (Ubuntu)
lineinfile:
path: /etc/netplan/50-cloud-init.yaml
regexp: '^renderer:'
line: ' renderer: NetworkManager'
register: netplan_change
when:
- ansible_distribution == 'Ubuntu'
- name: Check if renderer is already NetworkManager (Ubuntu)
debug:
msg: "Netplan renderer is already set to NetworkManager"
when:
- ansible_distribution == 'Ubuntu'
- netplan_change is not changed
- name: Apply Netplan configuration if changed (Ubuntu)
command: netplan apply
become: yes
when:
- ansible_distribution == 'Ubuntu'
- netplan_change.changed
下記はインベントリ例。KVM側のサーバユーザが ansibleユーザと違う場合は、ansible_user
で設定しておく
[all]
nuc02 ansible_host=192.168.129.2
nuc04 ansible_host=192.168.129.4
[cockpithost]
nuc02
nuc04
実行コマンド例は下記の通り
ansible-playbook -i inventry.ini playbook_kvm_cockpit_servers.yml -Kk
設定後にブラウザで https://[サーバアドレス]:9090
にアクセスすると管理画面にアクセス可能
以上で構築完了
動作確認
管理画面にアクセスして下記操作を実施する
- 管理画面操作にログイン
- ネットワークでの
Bridge
作成 - 仮想マシン作成
管理画面操作にログイン
ホストIP + ポート 9090 に https でアクセスするとログイン画面が出るので、OS インストール時に設定したユーザ名・パスワードでログインする
ログイン後の画面は下記の通り
Rocky9 の場合は下記の通り
以降は操作方法がインターフェース名以外は同じになるので、Rocky9 の画面の例のみ記載する
ネットワークでの Bridge
作成
ネットワーキング
画面で Bridge
の作成を試す
Bridge0 (NIC1番目) の追加
ブリッジの追加
をクリックすると、下記の画面が出るので、
上位ポート eno1
を選択して 追加
をクリックする
追加されると、bridge0
が作成される
Ubuntu の場合の注意点
Ubuntu の場合は、Bridge の MAC アドレスが NIC の MAC アドレスを踏襲しないので、DHCP 環境だと別のアドレスがアサインされるため、Bridge の MAC アドレスで再度 DHCP サーバ側の払い出し設定が必要になる
外部アクセス環境で設定する場合は、別 NIC 側の設定後 (別 IP からもアクセスを可能にした後) に設定する方がよい
VLAN 識別ポート、Bridge1 (NIC2番目(USB-NIC箇所)) の追加
VLAN の追加
をクリックすると、下記画面が出るので、
VLAN Trunk を収容しているポート (ここでは enpOs2OfOu3
) を親
にして、
VLAN ID
を収容したい VLAN ID (ここでは 300
) に設定して、
名前をつけて(ここではデフォルト命名される名前) にして 追加
をクリックする
追加するとインターフェースが追加される
追加したインターフェースをもとにブリッジ追加をするために、ブリッジの追加
をクリックする
ポートを追加したインターフェースを選択して 追加
をクリックする
追加されると下記の画面となる
Ubuntu の場合の注意点
Ubuntu では USB-NIC のインターフェース名が長くなるので、名前の長さが VLAN ID つけると違反する場合があるので、その場合は適切な名前を付与する必要がある
仮想マシン作成
各サブネット向けに VM 作成を試して外部疎通が可能なことまで確認する
仮想マシン
タブにアクセスする
仮想マシンの作成
をクリックすると下記画面が出てくるので、
OS をダウンロードします
にすると事前用意なくダウンロードして作成が可能で (Air Gap 環境でなければ)、
オペレーティングシステム
で作成したい VM を選択するして作成できる
作成して編集する
を選ぶと起動前に他の設定も可能なので、一度そちらをクリックする
作成して編集する
をクリック後は下記のような画面になる
ネットワークインターフェースで接続するブリッジの選択や、仮想 NIC の MAC アドレスが表示されるので環境内の DHCP 側に登録して Static に払い出す設定を事前にすることも可能
ここではそのまま インストール
をクリックする
しばらくするとインストーラが起動してコンソール
箇所に仮想マシンのコンソールが表示され操作可能になる (コンソール
ブロックの展開[ ]
をクリックするとコンソールブロックのみの表示に拡大できる)
設定諸々してインストール完了するとログイン画面が表示されるので、アドレス確認して外部から SSH でログイン可能なことを確認できる
2つ目の VM として別の IP サブネットで作成する。ネットワーク設定以外は上記と同じなので作成して編集
まで進める
NIC の所属 Bridge を変更するために ネットワークインターフェース
の対象 NIC の 編集
で変更する (2NIC目にする場合は ネットワークインターフェースの追加
で追加も可能)
ソース
で対象の Bridge を設定して 保存
する
インストール後にアクセスすると別のサブネットで作成・疎通ができるところまで確認できた
おわりに
Cockpit を使用することで、簡易的に仮想マシン環境を構築できることが確認できた
管理機能は他にもいろいろありそうなので、詳細は Cockpit 公式ページなどを見て試すのが良さそう
参考
Tips
Wake-on-LAN を有効化する方法 (Ubuntu で NIC が enp86s0
の場合)
sudo ethtool -s enp86s0 wol g
- name: Enable Wake-on-LAN
hosts: cockpithost
become: yes
tasks:
- name: Ensure netplan configuration supports WoL
lineinfile:
path: /etc/netplan/50-cloud-init.yaml
insertafter: '^ dhcp4: true'
line: ' wakeonlan: true'
register: netplan_change
when:
- ansible_distribution == 'Ubuntu'
- name: Apply Netplan configuration if changed (Ubuntu)
command: netplan apply
become: yes
when:
- ansible_distribution == 'Ubuntu'
- netplan_change.changed