試行錯誤してProxmox VE上でvJunosEvolvedを動かしたりPyEZを動かしたり

この記事は BBSakura Networks Advent Calendar 2023 の 22日目の記事です。

adventar.org

はじめに

こんにちは、BBSakura Networksでバックエンド開発をしている秋山です。普段はOCXの開発をしており、OCXの機能追加やクラウド事業者とのAPI連携に尽力しています。最近はバックエンド開発の他にもネットワーク開発に興味を持っており、社内ラボ環境の整備を目的とした石狩プロジェクトなどにも顔を出したりしています。最近、石狩プロジェクトのメンバーのおかげでProxmox VEを通じて自由にVMを立てたり消したりできる環境ができたので、自分も便乗してたまに触ったりしています。今回は、その中で得た知見としてVMの立て方やconfig投入自動化の仕方などについて解説したいと思います。

blog.bbsakura.net

今回は

  • NW自動化の勉強がしたいと思い、NW機器上でPythonコードを走らせられるPyEZに興味があった
  • 今年公開された大手ベンダーの新しい仮想イメージを触って見たかった
  • アカウント登録が不要でハードルが低い

などの理由からvJunosEvolvedをProxmox VE上で動かしてみることにしました。

仮想イメージを取得

仮想イメージは Downloads から取得できます。DLした仮想イメージはノード内の任意ディレクトリに移動させます。 ノードの/home/akiyama配下にvJunosEvolved-23.2R1-S1.8-EVO.qcow2が存在している画像

仮想イメージをインポート

まずはvJunosEvolvedを動作させるための最小要件に合わせて空のVMを作成します。

ハードウェアおよびソフトウェアの最小要件 |vJunosEvolved |ジュニパーネットワークス

以下のコマンドを実行しましょう。(1行です)

# qm create 103 --cores 4 --memory 8192 --cpu host --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci --ostype l26

ノードのshellから以下のコマンドを実行し、仮想イメージを取り込みます。

# qm importdisk 103 <your_path>/vJunosEvolved-23.2R1-S1.8-EVO.qcow2 <your_storage_name>
# qm set 103 --virtio0 <your_storage_name>:vm-103-disk-0
# qm set 103 --boot order=virtio0
# qm set 103 --serial0 socket

起動にはSMBIOSの設定も必要になります。

KVMでのvJunosEvolvedの展開と管理 |vJunosEvolved |ジュニパーネットワークス

VMのOptionsからSMBIOS(type 1)の各欄に以下を入力します。

manufacturer: Bochs
product: Bochs
serial: chassis_no=0:slot=0:type=1:assembly_id=0x0D20:platform=251:master=0: channelized=yes

前述のパラメータがSMBIOS(type 1)の各欄に入力されている様子

その後、ノードのshellから/etc/pve/qemu-server/[vmid].confを編集し、argsを2行追加します。

# nano /etc/pve/qemu-server/103.conf
boot: order=scsi1;scsi0;ide2;net0
cores: 4
cpu: x86-64-v2-AES
ide2: none,media=cdrom
memory: 8192
meta: creation-qemu=8.1.2,ctime=1703206221
name: vJunosEvolved
net0: virtio=BC:24:11:90:EA:A2,bridge=vmbr0
numa: 0
ostype: l26
scsi0: local-lvm:vm-103-disk-0,iothread=1,size=32G
scsi1: local-lvm:vm-103-disk-1,iothread=1,size=40G
scsihw: virtio-scsi-single
smbios1: uuid=dca71814-b638-4735-8eae-9a62237a7e2c,manufacturer=Qm9jaHM=,product=Qm9jaHM=,serial=Y2hhc3N>
sockets: 1
vmgenid: bb9c4e40-e285-47f5-bb3c-0fffec77746b
args: -smbios type=0,vendor=Bochs,version=Bochs
args: -smbios type=3,manufacturer=Bochs

VMの起動

VMを起動して動作を確認します。

# qm start 103
# qm terminal 103

ログイン情報を求められた際は「root」と入力すれば入れるはずです。
ログインと同時にエラーログが流れたりして見にくいので、以下のコマンドを実行し、少し待つと止まります。

# cli
# configure
# delete chassis auto-image-upgrade
# set system root-authentication plain-text-password
# commit and-quit

以上でvJunosEvolvedの設定は終わりです。
環境構築は完了したので、これから自動化やアプリケーションの動作検証など頑張ってやっていきたいと思います。
実際にJuniperの機器が手元になくても、config投入を行うスクリプト等の動作検証ができるのは非常に便利だと感じました。
また、Proxmox VEもVMの設定が非常に楽で、慣れれば15~30分で好きな仮想イメージを積んだVMが立てれるようになりそうです。

PyEZでconfigを操作してみる

環境構築ができたということで、config投入の自動化に取り組んでみました。その第一歩としてインターフェースの有効化、無効化を行うconfigをPyEZを用いたPythonコードから投入できるようにします。
PyEZとはJunos OSに対するPythonライブラリであり、これを使用することで、Junos機器への設定や管理が可能になります。

以下のコード(interface_manip.py)をVM内の/var/db/scripts/op/配下にscpなりを使って置きます。

from jnpr.junos import Device
from jnpr.junos.utils.config import Config
from jnpr.junos.exception import *

def generate_interface_config(interface_name, disable=True):
    if disable:
        disable_tag = "<disable/>"
    else:
        disable_tag = "<disable operation=\"delete\"/>"
    return f"""
        <configuration>
            <interfaces>
                <interface>
                    <name>{interface_name}</name>
                    {disable_tag}
                </interface>
            </interfaces>
        </configuration>
    """


def apply_configuration_changes(config_utility, config_changes):
    try:
        config_utility.lock()
        config_utility.load(config_changes, format="xml", merge=True)
        config_utility.commit()
    except (LockError, ConfigLoadError, CommitError) as err:
        print(f"Error: {err}")
        return False
    finally:
        try:
            config_utility.unlock()
        except UnlockError:
            print("Error: Unable to unlock configuration")
            return False
    return True

def main():
    with Device() as dev:
        dev.bind(cu=Config)
        if apply_configuration_changes(dev.cu, generate_interface_config("et-0/0/1", True)):
            print("Configured successfully.")
        else:
            print("Configuration error")

if __name__ == "__main__":
    main()

自分は以下のコマンドでsshを有効化し、ユーザを作り、scpで送りました。
アドレスの設定なども適宜行なって下さい。

# configure
# set system services ssh
# set system login user akiyama authentication plain-text-password
# set system login user akiyama class super-user
# commit and-quit

Pythonをスクリプト言語として設定し、操作スクリプト(op script)の登録をするために、/var/db/scripts/op/interface_manip.pyがある状態で以下のコマンドを実行します。

# configure
# set system services netconf ssh
# set system scripts language python3
# set system scripts op file interface_manip.py
# commit and-quit

CLIモードで以下のコマンドを実行すると、Pythonコードが実行されます

# op interface_manip.py

interface_manip.pyの実行前後で特定のインターフェースが無効化されているのが分かります。 全てのインターフェース(et-0/0/0からet-0/0/3)がuplinkしている et-0/0/1だけがdownlinkしている

終わりに

今まで開発の中でちょくちょく仮想アプライアンスは出てきていたのですが、あまり理解しておらず、今回のProxmox VEの操作を通じて一気に理解が深まった気がします。ただ検証環境を整えたところで終わっては勿体無いので、ネットワーク×アプリケーションでどんなことができるかこれから色々試していきたいです。