Proxmox VE GitOps
Proxmox VE Cluster GitOps Terraform Ansible CI/CD KVM LXC High Availability Ceph Storage Backup PBS Infrastructure as Code Production
| Component | Tool | Purpose | GitOps Role |
|---|---|---|---|
| VM Provisioning | Terraform | สร้าง VM LXC จาก Code | Declarative state |
| Configuration | Ansible | ติดตั้ง Software ตั้งค่า | Idempotent config |
| CI/CD | GitHub Actions | Plan Apply อัตโนมัติ | Automated workflow |
| State | Terraform State | เก็บ State ปัจจุบัน | Source of truth |
| Version Control | Git | Track ทุกการเปลี่ยนแปลง | Audit trail |
| Backup | PBS | Backup VM LXC | DR strategy |
Terraform Proxmox
# === Terraform Proxmox Provider ===
# terraform {
# required_providers {
# proxmox = {
# source = "telmate/proxmox"
# version = "3.0.1-rc1"
# }
# }
# backend "s3" {
# bucket = "terraform-state"
# key = "proxmox/terraform.tfstate"
# region = "ap-southeast-1"
# }
# }
#
# provider "proxmox" {
# pm_api_url = "https://pve1.local:8006/api2/json"
# pm_user = "terraform@pam"
# pm_password = var.proxmox_password
# pm_tls_insecure = true
# }
#
# resource "proxmox_vm_qemu" "web_server" {
# count = 3
# name = "web-"
# target_node = "pve"
# clone = "ubuntu-22.04-template"
#
# cores = 4
# memory = 8192
# balloon = 4096
# scsihw = "virtio-scsi-single"
#
# disk {
# storage = "ceph-pool"
# size = "50G"
# type = "scsi"
# ssd = 1
# }
#
# network {
# model = "virtio"
# bridge = "vmbr0"
# tag = 100
# }
#
# ipconfig0 = "ip=10.0.1./24, gw=10.0.1.1"
# sshkeys = file("~/.ssh/id_rsa.pub")
#
# lifecycle {
# ignore_changes = [network]
# }
# }
#
# resource "proxmox_lxc" "db_server" {
# hostname = "db-1"
# target_node = "pve1"
# ostemplate = "local:vztmpl/ubuntu-22.04-standard.tar.zst"
# cores = 4
# memory = 4096
# swap = 1024
# unprivileged = true
#
# rootfs {
# storage = "ceph-pool"
# size = "30G"
# }
#
# network {
# name = "eth0"
# bridge = "vmbr0"
# ip = "10.0.1.50/24"
# gw = "10.0.1.1"
# }
# }
from dataclasses import dataclass
@dataclass
class VMSpec:
name: str
role: str
cores: int
ram_gb: int
disk_gb: int
node: str
ha: bool
vms = [
VMSpec("web-1", "Web Server", 4, 8, 50, "pve1", True),
VMSpec("web-2", "Web Server", 4, 8, 50, "pve2", True),
VMSpec("web-3", "Web Server", 4, 8, 50, "pve3", True),
VMSpec("db-1", "PostgreSQL Primary", 8, 32, 200, "pve1", True),
VMSpec("db-2", "PostgreSQL Replica", 8, 32, 200, "pve2", True),
VMSpec("monitor-1", "Prometheus + Grafana", 4, 8, 100, "pve3", False),
VMSpec("backup-1", "PBS Server", 4, 16, 500, "pve3", False),
]
print("=== Infrastructure VMs ===")
for v in vms:
print(f" [{v.name}] Role: {v.role} | Node: {v.node}")
print(f" CPU: {v.cores} cores | RAM: {v.ram_gb}GB | Disk: {v.disk_gb}GB | HA: {v.ha}")
Ansible Configuration
# === Ansible Playbooks ===
# inventory/hosts.yml
# all:
# children:
# web_servers:
# hosts:
# web-1: { ansible_host: 10.0.1.10 }
# web-2: { ansible_host: 10.0.1.11 }
# web-3: { ansible_host: 10.0.1.12 }
# db_servers:
# hosts:
# db-1: { ansible_host: 10.0.1.50 }
# db-2: { ansible_host: 10.0.1.51 }
# playbooks/web-server.yml
# - hosts: web_servers
# become: yes
# roles:
# - common
# - nginx
# - node-exporter
# tasks:
# - name: Install packages
# apt:
# name: [nginx, certbot, python3-certbot-nginx]
# state: present
# update_cache: yes
#
# - name: Deploy nginx config
# template:
# src: nginx.conf.j2
# dest: /etc/nginx/sites-available/default
# notify: restart nginx
#
# - name: Enable firewall rules
# ufw:
# rule: allow
# port: "{{ item }}"
# loop: ["80", "443", "9100"]
# Proxmox Cluster Commands
# pvecm create my-cluster # Create cluster
# pvecm add 10.0.1.2 # Add node
# pvecm status # Check cluster status
# pvecm expected 1 # Set expected votes (emergency)
# ha-manager set vm:100 --state started # Enable HA for VM
# ha-manager groupadd ha-group --nodes pve1, pve2, pve3
@dataclass
class ClusterCommand:
command: str
purpose: str
when: str
commands = [
ClusterCommand("pvecm create cluster-name", "สร้าง Cluster ใหม่", "ครั้งแรก Node แรก"),
ClusterCommand("pvecm add 10.0.1.1", "เพิ่ม Node เข้า Cluster", "Node ใหม่ทุกตัว"),
ClusterCommand("pvecm status", "ดู Cluster Status", "ตรวจสอบปกติ"),
ClusterCommand("pvecm nodes", "ดู Nodes ทั้งหมด", "ตรวจสอบ"),
ClusterCommand("ha-manager set vm:100 --state started", "เปิด HA สำหรับ VM", "VM สำคัญ"),
ClusterCommand("ceph status", "ดู Ceph Storage Status", "ตรวจสอบ Storage"),
ClusterCommand("qm migrate 100 pve2", "ย้าย VM ไป Node อื่น", "Maintenance"),
ClusterCommand("vzdump 100 --storage pbs", "Backup VM ไป PBS", "Backup"),
]
print("\n=== Proxmox Commands ===")
for c in commands:
print(f" [{c.command}]")
print(f" Purpose: {c.purpose} | When: {c.when}")
CI/CD Pipeline
# === GitHub Actions GitOps Pipeline ===
# .github/workflows/proxmox-gitops.yml
# name: Proxmox GitOps
# on:
# pull_request:
# paths: ['terraform/**', 'ansible/**']
# push:
# branches: [main]
# paths: ['terraform/**', 'ansible/**']
#
# jobs:
# terraform-plan:
# if: github.event_name == 'pull_request'
# runs-on: self-hosted
# steps:
# - uses: actions/checkout@v4
# - uses: hashicorp/setup-terraform@v3
# - run: terraform init
# working-directory: terraform/
# - run: terraform plan -out=plan.tfplan
# working-directory: terraform/
# - uses: actions/github-script@v7
# with:
# script: |
# const plan = require('fs').readFileSync('terraform/plan.txt', 'utf8');
# github.rest.issues.createComment({
# owner: context.repo.owner,
# repo: context.repo.repo,
# issue_number: context.issue.number,
# body: '```\n' + plan + '\n```'
# });
#
# terraform-apply:
# if: github.ref == 'refs/heads/main' && github.event_name == 'push'
# runs-on: self-hosted
# steps:
# - uses: actions/checkout@v4
# - run: terraform init && terraform apply -auto-approve
# working-directory: terraform/
#
# ansible-configure:
# needs: terraform-apply
# runs-on: self-hosted
# steps:
# - uses: actions/checkout@v4
# - run: ansible-playbook -i inventory/hosts.yml playbooks/site.yml
@dataclass
class GitOpsStep:
step: str
trigger: str
action: str
safety: str
steps = [
GitOpsStep("1. Developer creates PR", "Code push", "terraform plan runs automatically",
"Plan output posted as PR comment"),
GitOpsStep("2. Team reviews PR", "PR created", "Review Terraform plan + Ansible changes",
"Approval required from 2 reviewers"),
GitOpsStep("3. Merge to main", "PR approved", "terraform apply runs automatically",
"State locked during apply"),
GitOpsStep("4. Ansible configure", "After Terraform", "ansible-playbook runs on new VMs",
"Idempotent — safe to re-run"),
GitOpsStep("5. Health check", "After Ansible", "Verify VMs running + services healthy",
"Auto-rollback if health check fails"),
]
print("GitOps Workflow:")
for s in steps:
print(f" [{s.step}]")
print(f" Trigger: {s.trigger} | Action: {s.action}")
print(f" Safety: {s.safety}")
เคล็ดลับ
- Template: สร้าง VM Template สำหรับ Clone เร็วกว่าติดตั้งใหม่
- Ceph: ใช้ Ceph Storage สำหรับ Shared Storage HA ย้าย VM ได้
- State: เก็บ Terraform State ใน Remote Backend เช่น S3
- PR Review: ทุกการเปลี่ยนแปลงต้องผ่าน PR Review ก่อน Apply
- Backup: ทดสอบ Restore Backup ทุกเดือน ตรวจว่าใช้ได้จริง
Proxmox VE คืออะไร
Open Source Virtualization KVM LXC Web UI Cluster 32 Nodes HA Ceph Storage Backup ZFS REST API ฟรี Enterprise Subscription
GitOps สำหรับ Proxmox ทำอย่างไร
Git Repository Terraform Proxmox Provider VM LXC Code Ansible Configuration CI/CD GitHub Actions PR Review Apply State Rollback
ตั้ง Cluster อย่างไร
3 Nodes Quorum pvecm create add Corosync Ceph Shared Storage HA Group Failover VM ย้ายอัตโนมัติ ทดสอบ
Backup Strategy ทำอย่างไร
PBS Proxmox Backup Server อัตโนมัติทุกวัน Incremental Deduplication GFS 7 วัน 4 สัปดาห์ 3 เดือน Restore ทดสอบทุกเดือน Offsite Sync
สรุป
Proxmox VE Cluster GitOps Terraform Ansible CI/CD KVM LXC HA Ceph Storage PBS Backup Infrastructure as Code Production Operations
