使用 Pulumi 自動建立 Proxmox LXC 環境
使用 Pulumi 自動建立 Proxmox LXC 環境
簡介
最近在嘗試使用 Pulumi + ProxmoxVE 搭建 HomeLab 的開發環境
摸了一段時間後終於搞清楚怎麼用了,因此這邊簡單做個紀錄
我們這次使用的是 https://github.com/muhlba91/pulumi-proxmoxve 這個第三方的元件,他是透過 tf-bridge 再去使用 https://github.com/bpg/terraform-provider-proxmox 這個 terraform 的元件
安裝步驟
建立 Pulumi 專案
首先,我們先建立一個空資料夾作為專案的資料夾
並在資料夾中執行 pulumi new python
來建立一個新專案
我們會看到,資料夾的結構變成這樣
Pulumi.yaml
裡面出現的會是我們剛剛填入的資料,其中 options
可以指定 python 環境要不要由 Pulumi 控制,預設會在專案內建立 venv
這個資料夾,並使用該環境來執行 pulumi
如果想要由自己來管理環境的話,可以把這個選項拿掉,他就會用目前 shell 環境下的 python 去執行
name: homelab
runtime:
name: python
options:
virtualenv: venv
description: a homelab iac
安裝套件
接下來就是安裝我們需要的元件,我們根據 說明,安裝對應語言的函式庫
這邊以 python 為例子,指令如下 pip install pulumi-proxmoxve
設定 provider
安裝完成後,就可以開始來設定我們的 provider 了
provider 需要的參數有以下這些
resource_name - Pulumi 的辨識名稱,跟 Proxmox 無關,填一個好記的字串即可
insecure - 是否跳過 TLS 檢查,這邊我選是
endpoint - Proxmox 的位置,填入 IP Port 就好了
api_token - 呼叫API時,用來驗證使用者身分的工具,可以在 datacenter 底下建立,建立完成後他會給你一個 UUID,再把 User 、 TokenID、剛剛拿到的 UUID 填入下面的程式即可
import pulumi
import pulumi_proxmoxve as pve
provider = pve.Provider(
resource_name="{Name}",
insecure=True,
endpoint="https://{IP}:{Port}/",
api_token="{User}!{TokenID}={UUID}",
)
給 APIToken 權限
接下來我們需要給 APIToken 相對應的權限,這邊我是給 PVEAdmin
給 LXC 名稱 + ID,以及登入用的 ssh key
接下來看看 LXC 的每個步驟分別需要那些基本參數
import pulumi
import pulumi_proxmoxve as pve
keys = ["{ssh public key}"] # 我是使用 ssh 登入,所以把 ssh publisc key 放這邊
pulumiTestCT = pve.ct.Container(
resource_name="{Name}",
opts=pulumi.ResourceOptions(provider=provider), # 跟程式說使用我們之前設定的 provider 來執行操作
vm_id={ID}, # CT ID
unprivileged=True, # 對應到 unprivileged container
started=True, # 設定完成後自動啟動
start_on_boot=True, # 開機後自動啟動
node_name="{NodeName}", # 對應到 node 那個欄位
initialization=pve.ct.ContainerInitializationArgs(
hostname="{Name}", # 對應到 Hostname 那個欄位
user_account=pve.ct.ContainerInitializationUserAccountArgs(keys=keys), # 我是使用 ssh 登入,所以把 ssh publisc key 放這邊
),
features=pve.ct.ContainerFeaturesArgs(nesting=True) # 對應到 Nesting
)
找到需要的 CT Template
可以使用 pveam list local
這個指令找出 CT template 的位置
pulumiTestCT = pve.ct.Container(
resource_name="{Name}",
opts=pulumi.ResourceOptions(provider=provider),
vm_id={ID},
unprivileged=True,
started=True,
start_on_boot=True,
node_name="{NodeName}",
features=pve.ct.ContainerFeaturesArgs(nesting=True),
operating_system=pve.ct.ContainerOperatingSystemArgs( # 設定我們要的 OS
template_file_id="local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst", # 可以使用 pveam list local 這個指令找出 CT template 的位置
type="debian", # 不同作業系統
),
initialization=pve.ct.ContainerInitializationArgs(
hostname="{Name}",
user_account=pve.ct.ContainerInitializationUserAccountArgs(keys=keys),
),
)
設定開機硬碟
pulumiTestCT = pve.ct.Container(
resource_name="{Name}",
opts=pulumi.ResourceOptions(provider=provider),
vm_id={ID},
unprivileged=True,
started=True,
start_on_boot=True,
node_name="{NodeName}",
features=pve.ct.ContainerFeaturesArgs(nesting=True),
operating_system=pve.ct.ContainerOperatingSystemArgs(
template_file_id="local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst",
type="debian",
),
initialization=pve.ct.ContainerInitializationArgs(
hostname="{Name}",
user_account=pve.ct.ContainerInitializationUserAccountArgs(keys=keys),
),
disk=pve.ct.ContainerDiskArgs(datastore_id="localHDD"), # 指定要使用哪個儲存空間
)
設定 CPU/記憶體
因為這次只是測試,所以 CPU Memory 都不用填,都使用預設值就好
設定網路
pulumiTestCT = pve.ct.Container(
resource_name="{Name}",
opts=pulumi.ResourceOptions(provider=provider),
vm_id={ID},
unprivileged=True,
started=True,
start_on_boot=True,
node_name="{NodeName}",
features=pve.ct.ContainerFeaturesArgs(nesting=True),
operating_system=pve.ct.ContainerOperatingSystemArgs(
template_file_id="local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst",
type="debian",
),
disk=pve.ct.ContainerDiskArgs(datastore_id="localHDD"),
initialization=pve.ct.ContainerInitializationArgs(
hostname="{Name}",
user_account=pve.ct.ContainerInitializationUserAccountArgs(keys=keys),
ip_configs=[
pve.ct.ContainerInitializationIpConfigArgs(
ipv4=pve.ct.ContainerInitializationIpConfigIpv4Args(
address="{IP/CIDR}", gateway="{Gateway}" # 設定 IP/CIDR + gateway
)
)
],
),
network_interfaces=[
pve.ct.ContainerNetworkInterfaceArgs(name="eth0", firewall=True) # 使用 eth0,並打開防火牆(也可以不開)
]
)
組合上述步驟 + 部屬
最後我們把所有步驟組合起來,會變成下面這樣,就大功告成了
現在我們可以使用 pulumi up
來部屬了
import pulumi
import pulumi_proxmoxve as pve
keys = ["{ssh public key}"]
provider = pve.Provider(
resource_name="{Name}",
insecure=True,
endpoint="https://{IP}:{Port}/",
api_token="{User}!{TokenID}={UUID}",
)
pulumiTestCT = pve.ct.Container(
resource_name="{Name}",
opts=pulumi.ResourceOptions(provider=provider),
vm_id={ID},
unprivileged=True,
started=True,
start_on_boot=True,
node_name="{NodeName}",
features=pve.ct.ContainerFeaturesArgs(nesting=True),
operating_system=pve.ct.ContainerOperatingSystemArgs(
template_file_id="local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst", # pveam list local
type="debian",
),
disk=pve.ct.ContainerDiskArgs(datastore_id="localHDD"),
initialization=pve.ct.ContainerInitializationArgs(
hostname="{Name}",
user_account=pve.ct.ContainerInitializationUserAccountArgs(keys=keys),
ip_configs=[
pve.ct.ContainerInitializationIpConfigArgs(
ipv4=pve.ct.ContainerInitializationIpConfigIpv4Args(
address="192.168.51.5/24", gateway="192.168.51.1"
)
)
],
),
network_interfaces=[
pve.ct.ContainerNetworkInterfaceArgs(name="eth0", firewall=True)
]
)