572 lines
14 KiB
Markdown
572 lines
14 KiB
Markdown
# Cloud-Init.func Wiki
|
|
|
|
VM cloud-init configuration and first-boot setup module for Proxmox VEs, providing automatic system initialization, network configuration, user account setup, and SSH key management for virtual machines.
|
|
|
|
---
|
|
|
|
## 📋 Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Cloud-Init Fundamentals](#cloud-init-fundamentals)
|
|
- [Main Configuration Functions](#main-configuration-functions)
|
|
- [Interactive Configuration](#interactive-configuration)
|
|
- [Configuration Parameters](#configuration-parameters)
|
|
- [Data Formats](#data-formats)
|
|
- [Best Practices](#best-practices)
|
|
- [Troubleshooting](#troubleshooting)
|
|
- [Contributing](#contributing)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Cloud-init.func provides **VM first-boot automation** infrastructure:
|
|
|
|
- ✅ Cloud-init drive creation (IDE2 or SCSI fallback)
|
|
- ✅ User account and password configuration
|
|
- ✅ SSH public key injection
|
|
- ✅ Network configuration (DHCP or static IP)
|
|
- ✅ DNS and search domain setup
|
|
- ✅ Interactive whiptail-based configuration
|
|
- ✅ Credential file generation and display
|
|
- ✅ Support for Debian nocloud and Ubuntu cloud-init
|
|
- ✅ System package upgrade on first boot
|
|
|
|
### Integration Pattern
|
|
|
|
```bash
|
|
# In Proxmox VM creation scripts
|
|
source <(curl -fsSL .../cloud-init.func)
|
|
|
|
# Basic setup:
|
|
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes"
|
|
|
|
# Interactive setup:
|
|
configure_cloud_init_interactive "root"
|
|
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "$CLOUDINIT_ENABLE"
|
|
```
|
|
|
|
### First-Boot Sequence
|
|
|
|
```
|
|
VM Power On
|
|
↓
|
|
Cloud-init boot phase
|
|
↓
|
|
Read cloud-init config
|
|
↓
|
|
Create/modify user account
|
|
↓
|
|
Install SSH keys
|
|
↓
|
|
Configure network
|
|
↓
|
|
Set DNS/search domain
|
|
↓
|
|
Upgrade packages (if configured)
|
|
↓
|
|
Boot completion
|
|
```
|
|
|
|
---
|
|
|
|
## Cloud-Init Fundamentals
|
|
|
|
### What is Cloud-Init?
|
|
|
|
Cloud-init is a system that runs on the first boot of a VM/Instance to:
|
|
- Create user accounts
|
|
- Set passwords
|
|
- Configure networking
|
|
- Install SSH keys
|
|
- Run custom scripts
|
|
- Manage system configuration
|
|
|
|
### Proxmox Cloud-Init Integration
|
|
|
|
Proxmox VE supports cloud-init natively via:
|
|
- **Cloud-init drive**: IDE2 or SCSI disk with cloud-init data
|
|
- **QEMU parameters**: User, password, SSH keys, IP configuration
|
|
- **First-boot services**: systemd services that execute on first boot
|
|
|
|
### Nocloud Data Source
|
|
|
|
Proxmox uses the **nocloud** data source (no internet required):
|
|
- Configuration stored on local cloud-init drive
|
|
- No external network call needed
|
|
- Works in isolated networks
|
|
- Suitable for private infrastructure
|
|
|
|
---
|
|
|
|
## Main Configuration Functions
|
|
|
|
### `setup_cloud_init()`
|
|
|
|
**Purpose**: Configures Cloud-init for automatic VM first-boot setup.
|
|
|
|
**Signature**:
|
|
```bash
|
|
setup_cloud_init()
|
|
```
|
|
|
|
**Parameters**:
|
|
- `$1` - VMID (required, e.g., 100)
|
|
- `$2` - Storage name (required, e.g., local, local-lvm)
|
|
- `$3` - Hostname (optional, default: vm-${VMID})
|
|
- `$4` - Enable Cloud-Init (yes/no, default: no)
|
|
- `$5` - User (optional, default: root)
|
|
- `$6` - Network mode (dhcp/static, default: dhcp)
|
|
- `$7` - Static IP (optional, CIDR format: 192.168.1.100/24)
|
|
- `$8` - Gateway (optional)
|
|
- `$9` - Nameservers (optional, space-separated, default: 1.1.1.1 8.8.8.8)
|
|
|
|
**Returns**: 0 on success, 1 on failure; exits if not enabled
|
|
|
|
**Behavior**:
|
|
```bash
|
|
# If enable="no":
|
|
# Returns immediately (skips all configuration)
|
|
|
|
# If enable="yes":
|
|
# 1. Create cloud-init drive (IDE2, fallback to SCSI1)
|
|
# 2. Set user account
|
|
# 3. Generate random password
|
|
# 4. Configure network
|
|
# 5. Set DNS servers
|
|
# 6. Add SSH keys (if available)
|
|
# 7. Save credentials to file
|
|
# 8. Export variables for calling script
|
|
```
|
|
|
|
**Operations**:
|
|
|
|
| Operation | Command | Purpose |
|
|
|-----------|---------|---------|
|
|
| Create drive | `qm set $vmid --ide2 $storage:cloudinit` | Cloud-init data disk |
|
|
| Set user | `qm set $vmid --ciuser $ciuser` | Initial user |
|
|
| Set password | `qm set $vmid --cipassword $cipassword` | Auto-generated |
|
|
| SSH keys | `qm set $vmid --sshkeys $SSH_KEYS_FILE` | Pre-injected |
|
|
| DHCP network | `qm set $vmid --ipconfig0 ip=dhcp` | Dynamic IP |
|
|
| Static network | `qm set $vmid --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1` | Fixed IP |
|
|
| DNS | `qm set $vmid --nameserver $servers` | 1.1.1.1 8.8.8.8 |
|
|
| Search domain | `qm set $vmid --searchdomain local` | Local domain |
|
|
|
|
**Environment Variables Set**:
|
|
- `CLOUDINIT_USER` - Username configured
|
|
- `CLOUDINIT_PASSWORD` - Generated password (in memory only)
|
|
- `CLOUDINIT_CRED_FILE` - Path to credentials file
|
|
|
|
**Usage Examples**:
|
|
|
|
```bash
|
|
# Example 1: Basic DHCP setup
|
|
VMID=100
|
|
STORAGE="local-lvm"
|
|
setup_cloud_init "$VMID" "$STORAGE" "myvm" "yes"
|
|
# Result: VM configured with DHCP, random password, root user
|
|
|
|
# Example 2: Static IP configuration
|
|
setup_cloud_init "$VMID" "$STORAGE" "myvm" "yes" "root" \
|
|
"static" "192.168.1.100/24" "192.168.1.1" "1.1.1.1 8.8.8.8"
|
|
# Result: VM configured with static IP, specific DNS
|
|
|
|
# Example 3: Disabled (no cloud-init)
|
|
setup_cloud_init "$VMID" "$STORAGE" "myvm" "no"
|
|
# Result: Function returns immediately, no configuration
|
|
```
|
|
|
|
---
|
|
|
|
### `configure_cloud_init_interactive()`
|
|
|
|
**Purpose**: Interactive whiptail-based configuration prompts for user preferences.
|
|
|
|
**Signature**:
|
|
```bash
|
|
configure_cloud_init_interactive()
|
|
```
|
|
|
|
**Parameters**:
|
|
- `$1` - Default user (optional, default: root)
|
|
|
|
**Returns**: 0 on success, 1 if whiptail unavailable; exports configuration variables
|
|
|
|
**Environment Variables Exported**:
|
|
- `CLOUDINIT_ENABLE` - Enable (yes/no)
|
|
- `CLOUDINIT_USER` - Username
|
|
- `CLOUDINIT_NETWORK_MODE` - dhcp or static
|
|
- `CLOUDINIT_IP` - Static IP (if static mode)
|
|
- `CLOUDINIT_GW` - Gateway (if static mode)
|
|
- `CLOUDINIT_DNS` - DNS servers (space-separated)
|
|
|
|
**User Prompts** (5 questions):
|
|
1. **Enable Cloud-Init?** (yes/no)
|
|
2. **Username?** (default: root)
|
|
3. **Network Mode?** (DHCP or static)
|
|
4. **Static IP?** (if static, CIDR format)
|
|
5. **Gateway IP?** (if static)
|
|
6. **DNS Servers?** (default: 1.1.1.1 8.8.8.8)
|
|
|
|
**Fallback Behavior**:
|
|
- If whiptail unavailable: Shows warning and returns 1
|
|
- Auto-defaults to DHCP if error occurs
|
|
- Non-interactive: Can be skipped in scripts
|
|
|
|
**Implementation Pattern**:
|
|
```bash
|
|
configure_cloud_init_interactive() {
|
|
local default_user="${1:-root}"
|
|
|
|
# Check whiptail availability
|
|
if ! command -v whiptail >/dev/null 2>&1; then
|
|
echo "Warning: whiptail not available"
|
|
export CLOUDINIT_ENABLE="no"
|
|
return 1
|
|
fi
|
|
|
|
# Ask enable
|
|
if ! (whiptail --backtitle "Proxmox VE Helper Scripts" --title "CLOUD-INIT" \
|
|
--yesno "Enable Cloud-Init for VM configuration?" 16 68); then
|
|
export CLOUDINIT_ENABLE="no"
|
|
return 0
|
|
fi
|
|
|
|
export CLOUDINIT_ENABLE="yes"
|
|
|
|
# Username
|
|
CLOUDINIT_USER=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
|
"Cloud-Init Username" 8 58 "$default_user" --title "USERNAME" 3>&1 1>&2 2>&3)
|
|
export CLOUDINIT_USER="${CLOUDINIT_USER:-$default_user}"
|
|
|
|
# Network mode
|
|
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "NETWORK MODE" \
|
|
--yesno "Use DHCP for network configuration?" 10 58); then
|
|
export CLOUDINIT_NETWORK_MODE="dhcp"
|
|
else
|
|
export CLOUDINIT_NETWORK_MODE="static"
|
|
# ... prompt for static IP and gateway ...
|
|
fi
|
|
|
|
# DNS servers
|
|
CLOUDINIT_DNS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
|
"DNS Servers (space-separated)" 8 58 "1.1.1.1 8.8.8.8" --title "DNS" 3>&1 1>&2 2>&3)
|
|
export CLOUDINIT_DNS
|
|
}
|
|
```
|
|
|
|
**Usage Examples**:
|
|
|
|
```bash
|
|
# Example 1: Interactive configuration
|
|
configure_cloud_init_interactive "root"
|
|
# Prompts user for all settings interactively
|
|
# Exports variables for use in setup_cloud_init()
|
|
|
|
# Example 2: With custom default user
|
|
configure_cloud_init_interactive "debian"
|
|
# Suggests "debian" as default username
|
|
|
|
# Example 3: In script workflow
|
|
configure_cloud_init_interactive "$DEFAULT_USER"
|
|
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "$CLOUDINIT_ENABLE" "$CLOUDINIT_USER"
|
|
# User configures interactively, then script sets up VM
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration Parameters
|
|
|
|
### VMID (Virtual Machine ID)
|
|
|
|
- **Type**: Integer (100-2147483647)
|
|
- **Required**: Yes
|
|
- **Example**: `100`
|
|
- **Validation**: Must be unique, >= 100 on Proxmox
|
|
|
|
### Storage
|
|
|
|
- **Type**: String (storage backend name)
|
|
- **Required**: Yes
|
|
- **Examples**: `local`, `local-lvm`, `ceph-rbd`
|
|
- **Validation**: Must exist in Proxmox
|
|
- **Cloud-init Drive**: Placed on this storage
|
|
|
|
### Hostname
|
|
|
|
- **Type**: String (valid hostname)
|
|
- **Required**: No (defaults to vm-${VMID})
|
|
- **Example**: `myvm`, `web-server-01`
|
|
- **Format**: Lowercase, alphanumeric, hyphens allowed
|
|
|
|
### User
|
|
|
|
- **Type**: String (username)
|
|
- **Required**: No (defaults: root)
|
|
- **Example**: `root`, `ubuntu`, `debian`
|
|
- **Cloud-init**: User account created on first boot
|
|
|
|
### Network Mode
|
|
|
|
- **Type**: Enum (dhcp, static)
|
|
- **Default**: dhcp
|
|
- **Options**:
|
|
- `dhcp` - Dynamic IP from DHCP server
|
|
- `static` - Manual IP configuration
|
|
|
|
### Static IP
|
|
|
|
- **Format**: CIDR notation (192.168.1.100/24)
|
|
- **Example**: `192.168.1.50/24`, `10.0.0.5/8`
|
|
- **Validation**: Valid IP and netmask
|
|
- **Required**: If network mode = static
|
|
|
|
### Gateway
|
|
|
|
- **Format**: IP address (192.168.1.1)
|
|
- **Example**: `192.168.1.1`, `10.0.0.1`
|
|
- **Validation**: Valid IP
|
|
- **Required**: If network mode = static
|
|
|
|
### Nameservers
|
|
|
|
- **Format**: Space-separated IPs
|
|
- **Default**: `1.1.1.1 8.8.8.8`
|
|
- **Example**: `1.1.1.1 8.8.8.8 9.9.9.9`
|
|
|
|
### DNS Search Domain
|
|
|
|
- **Type**: String
|
|
- **Default**: `local`
|
|
- **Example**: `example.com`, `internal.corp`
|
|
|
|
---
|
|
|
|
## Data Formats
|
|
|
|
### Cloud-Init Credentials File
|
|
|
|
Generated at: `/tmp/${hostname}-${vmid}-cloud-init-credentials.txt`
|
|
|
|
**Format**:
|
|
```
|
|
========================================
|
|
Cloud-Init Credentials
|
|
========================================
|
|
VM ID: 100
|
|
Hostname: myvm
|
|
Created: Tue Dec 01 10:30:00 UTC 2024
|
|
|
|
Username: root
|
|
Password: s7k9mL2pQ8wX
|
|
|
|
Network: dhcp
|
|
DNS: 1.1.1.1 8.8.8.8
|
|
|
|
========================================
|
|
SSH Access (if keys configured):
|
|
ssh root@<vm-ip>
|
|
|
|
Proxmox UI Configuration:
|
|
VM 100 > Cloud-Init > Edit
|
|
- User, Password, SSH Keys
|
|
- Network (IP Config)
|
|
- DNS, Search Domain
|
|
========================================
|
|
```
|
|
|
|
### Proxmox Cloud-Init Config
|
|
|
|
Stored in: `/etc/pve/nodes/<node>/qemu-server/<vmid>.conf`
|
|
|
|
**Relevant Settings**:
|
|
```
|
|
ide2: local-lvm:vm-100-cloudinit,media=cdrom
|
|
ciuser: root
|
|
cipassword: (encrypted)
|
|
ipconfig0: ip=dhcp
|
|
nameserver: 1.1.1.1 8.8.8.8
|
|
searchdomain: local
|
|
```
|
|
|
|
### Network Configuration Examples
|
|
|
|
**DHCP**:
|
|
```bash
|
|
qm set 100 --ipconfig0 "ip=dhcp"
|
|
```
|
|
|
|
**Static IPv4**:
|
|
```bash
|
|
qm set 100 --ipconfig0 "ip=192.168.1.100/24,gw=192.168.1.1"
|
|
```
|
|
|
|
**Static IPv6**:
|
|
```bash
|
|
qm set 100 --ipconfig0 "ip6=2001:db8::100/64,gw6=2001:db8::1"
|
|
```
|
|
|
|
**Dual Stack (IPv4 + IPv6)**:
|
|
```bash
|
|
qm set 100 --ipconfig0 "ip=192.168.1.100/24,gw=192.168.1.1,ip6=2001:db8::100/64,gw6=2001:db8::1"
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### 1. **Always Configure SSH Keys**
|
|
|
|
```bash
|
|
# Ensure SSH keys available before cloud-init setup
|
|
CLOUDINIT_SSH_KEYS="/root/.ssh/authorized_keys"
|
|
|
|
if [ ! -f "$CLOUDINIT_SSH_KEYS" ]; then
|
|
mkdir -p /root/.ssh
|
|
# Generate or import SSH keys
|
|
fi
|
|
|
|
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes"
|
|
```
|
|
|
|
### 2. **Save Credentials Securely**
|
|
|
|
```bash
|
|
# After setup_cloud_init():
|
|
# Credentials file generated at $CLOUDINIT_CRED_FILE
|
|
|
|
# Copy to secure location:
|
|
cp "$CLOUDINIT_CRED_FILE" "/root/vm-credentials/"
|
|
chmod 600 "/root/vm-credentials/$(basename $CLOUDINIT_CRED_FILE)"
|
|
|
|
# Or display to user:
|
|
cat "$CLOUDINIT_CRED_FILE"
|
|
```
|
|
|
|
### 3. **Use Static IPs for Production**
|
|
|
|
```bash
|
|
# DHCP - suitable for dev/test
|
|
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes" "root" "dhcp"
|
|
|
|
# Static - suitable for production
|
|
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes" "root" \
|
|
"static" "192.168.1.100/24" "192.168.1.1"
|
|
```
|
|
|
|
### 4. **Validate Network Configuration**
|
|
|
|
```bash
|
|
# Before setting up cloud-init, ensure:
|
|
# - Gateway IP is reachable
|
|
# - IP address not in use
|
|
# - DNS servers are accessible
|
|
|
|
ping -c 1 "$GATEWAY" || msg_error "Gateway unreachable"
|
|
```
|
|
|
|
### 5. **Test First Boot**
|
|
|
|
```bash
|
|
# After cloud-init setup:
|
|
qm start "$VMID"
|
|
|
|
# Wait for boot
|
|
sleep 10
|
|
|
|
# Check cloud-init status
|
|
qm exec "$VMID" cloud-init status
|
|
|
|
# Verify network configuration
|
|
qm exec "$VMID" hostname -I
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Cloud-Init Not Applying
|
|
|
|
```bash
|
|
# Inside VM:
|
|
cloud-init status # Show cloud-init status
|
|
cloud-init analyze # Analyze cloud-init boot
|
|
cloud-init query # Query cloud-init datasource
|
|
|
|
# Check logs:
|
|
tail -100 /var/log/cloud-init-output.log
|
|
tail -100 /var/log/cloud-init.log
|
|
```
|
|
|
|
### Network Not Configured
|
|
|
|
```bash
|
|
# Verify cloud-init config in Proxmox:
|
|
cat /etc/pve/nodes/$(hostname)/qemu-server/100.conf
|
|
|
|
# Check cloud-init drive:
|
|
qm config 100 | grep ide2
|
|
|
|
# In VM, verify cloud-init wrote config:
|
|
cat /etc/netplan/99-cloudinit.yaml
|
|
```
|
|
|
|
### SSH Keys Not Installed
|
|
|
|
```bash
|
|
# Verify SSH keys set in Proxmox:
|
|
qm config 100 | grep sshkeys
|
|
|
|
# In VM, check SSH directory:
|
|
ls -la /root/.ssh/
|
|
cat /root/.ssh/authorized_keys
|
|
```
|
|
|
|
### Password Not Set
|
|
|
|
```bash
|
|
# Regenerate cloud-init drive:
|
|
qm set 100 --delete ide2 # Remove cloud-init drive
|
|
qm set 100 --ide2 local-lvm:vm-100-cloudinit,media=cdrom # Re-create
|
|
|
|
# Set password again:
|
|
qm set 100 --cipassword "newpassword"
|
|
```
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
### Adding New Configuration Options
|
|
|
|
1. Add parameter to `setup_cloud_init()` function signature
|
|
2. Add validation for parameter
|
|
3. Add `qm set` command to apply configuration
|
|
4. Update documentation with examples
|
|
5. Test on actual Proxmox VE
|
|
|
|
### Enhancing Interactive Configuration
|
|
|
|
1. Add new whiptail dialog to `configure_cloud_init_interactive()`
|
|
2. Export variable for use in setup
|
|
3. Add validation logic
|
|
4. Test with various input scenarios
|
|
|
|
### Supporting New Data Sources
|
|
|
|
Beyond nocloud, could support:
|
|
- ConfigDrive (cloud-init standard)
|
|
- ESXi (if supporting vSphere)
|
|
- Hyper-V (if supporting Windows)
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- Cloud-init requires **QEMU guest agent** for optimal functionality
|
|
- Network configuration applied **on first boot only**
|
|
- Credentials file contains **sensitive information** - keep secure
|
|
- SSH keys are **persisted** and not displayed in credentials file
|
|
- Cloud-init is **optional** - VMs work without it
|
|
|