Skip to content

jpurohit92/cloud-init-vmw

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

VM Provisioning — Photon OS + cloud-init + PowerCLI

Deploys a Photon OS 5.0 virtual machine on VMware vSphere and fully configures it on first boot using cloud-init — no console interaction, no post-deploy Ansible, no golden images per configuration variant.


How it works

┌─────────────────────────────────────────────────────────────────┐
│  Your workstation                                               │
│                                                                 │
│  deploy-photon.ps1                                              │
│    │                                                            │
│    ├─ 1. Connect to vCenter                                     │
│    ├─ 2. Deploy OVF from Content Library                        │
│    ├─ 3. Base64-encode YAML files                               │
│    ├─ 4. Set guestinfo.* keys on the VM  ──────────────────┐   │
│    └─ 5. Power on                                          │   │
│                                                            │   │
└────────────────────────────────────────────────────────────┼───┘
                                                             │
                                              VMware GuestInfo RPC channel
                                                             │
┌────────────────────────────────────────────────────────────▼───┐
│  Photon OS VM  (first boot)                                     │
│                                                                 │
│  cloud-init                                                     │
│    ├─ reads guestinfo.metadata  → applies static IP / hostname  │
│    └─ reads guestinfo.userdata  → installs packages, drops keys │
│                                   runs runcmd, clones repo      │
└─────────────────────────────────────────────────────────────────┘

The two YAML files (meta-data.yaml and user-data.yaml) describe the VM's entire desired state. They are the only files you need to edit for a new deployment.


Directory layout

infra/
├── README.md                   ← you are here
├── deploy-photon.ps1           ← main deployment script (PowerCLI)
├── monitor-cloud-init.ps1      ← optional SSH monitoring script
└── cloud-init/
    ├── meta-data.yaml          ← VM identity + static network config
    └── user-data.yaml          ← credentials, packages, files, commands

Prerequisites

1. VCF PowerCLI

Install-Module VCF.PowerCLI -Scope CurrentUser

2. Posh-SSH (only required for -Monitor)

Install-Module Posh-SSH -Scope CurrentUser

3. vSphere environment

Requirement Notes
vCenter 7.0 or later
Content Library with the Photon OS OVF Item name: photon-hw15-5.0-dde71ec57.x86_64 — download from github.com/vmware/photon
A distributed virtual portgroup (vDS) Standard vSwitch: replace Get-VDPortgroup with Get-VirtualPortGroup in deploy-photon.ps1
A static IP reservation for the VM Must match the address in meta-data.yaml

4. Git deploy key (only if cloning a private repository)

# Generate a dedicated key pair — do not reuse a personal key
ssh-keygen -t ed25519 -C "vm-deploy-key" -f ~/.ssh/vm_deploy_key

# Add vm_deploy_key.pub as a read-only deploy key on your repository
# (GitHub: Settings > Deploy keys > Add deploy key)

Customisation checklist

Edit these files before running the deployment script.

cloud-init/meta-data.yaml

Placeholder Replace with
<YOUR-VM-NAME> VM hostname, e.g. my-dev-vm
<YOUR-STATIC-IP>/<PREFIX> Static IP in CIDR notation, e.g. 192.168.1.100/24
<YOUR-GATEWAY> Default gateway IP
<YOUR-DNS-1> Primary DNS server
<YOUR-DNS-2> Secondary DNS server
eth0 Interface name for your distro (Photon OS = eth0, Ubuntu = ens160)

cloud-init/user-data.yaml

Placeholder Replace with
<YOUR-PASSWORD> Root password
<YOUR-NTP-SERVER> NTP server, e.g. pool.ntp.org
<PASTE YOUR ED25519 PRIVATE KEY HERE> Contents of ~/.ssh/vm_deploy_key (private key)
<YOUR-GIT-HOST> Git server hostname, e.g. github.com
<YOUR-REGISTRY-URL> npm registry URL (remove the .npmrc block for public registry)
<YOUR-AUTH-TOKEN> npm / Artifactory auth token
<YOUR-ORG>/<YOUR-REPO>.git Repository path

deploy-photon.ps1 (parameter defaults)

Override on the command line or edit the param() block defaults:

Parameter Default Description
-VCenterServer vcenter.your-lab.local vCenter hostname or IP
-VCenterUser administrator@vsphere.local vCenter username
-DatacenterName your-datacenter Datacenter name
-FolderName your-folder VM folder name
-DatastoreName your-datastore Datastore name
-PortGroupName VM Network Distributed portgroup name
-ContentLibraryName Your Content Library Content Library name
-TemplateItemName photon-hw15-5.0-dde71ec57.x86_64 OVF item name
-VMName photon-vm New VM display name
-VMIP 192.168.1.100 IP assigned in meta-data.yaml

Usage

Deploy only

pwsh infra/deploy-photon.ps1

You will be prompted for the vCenter password interactively. The password is never stored in any file.

Deploy with custom values (no file edits)

pwsh infra/deploy-photon.ps1 `
    -VCenterServer vcenter.mylab.local `
    -DatacenterName mydc `
    -FolderName     dev-vms `
    -VMName         dev-photon-01 `
    -VMIP           10.0.1.50

Deploy and monitor cloud-init in real time

pwsh infra/deploy-photon.ps1 -Monitor

This streams /var/log/cloud-init-output.log from the VM over SSH as provisioning runs. A version check is printed when cloud-init finishes:

[1/3] Waiting for SSH port on 192.168.1.100 (timeout: 300s)...
       Port 22 open after 45s.
[2/3] Waiting for stable SSH (5 consecutive successes)...
       SSH ok (5/5)
[3/3] Streaming cloud-init output...
  Installing: openjdk21-21.0.10-3.ph5.x86_64
  ...
  cloud-init: done

--- Version Check ---
  openjdk version "21.0.10-internal"
  Apache Maven 3.9.x
  v24.x.x
  PowerShell 7.x.x
  git version 2.x.x

Monitor a VM that is already provisioning

pwsh infra/monitor-cloud-init.ps1 -VMIP 192.168.1.100 -SSHPassword YourPassword

Troubleshooting

Cloud-init did not run

Check that instance-id in meta-data.yaml is unique. cloud-init skips all modules if it detects the same instance-id from a previous run (stored in /var/lib/cloud/instance/).

# On the VM — force a full re-run on next reboot
rm -rf /var/lib/cloud/instance
cloud-init clean
reboot

cloud-init status: error

# Show which module failed and why
cloud-init status --long

# Full output of all runcmd commands
cat /var/log/cloud-init-output.log

# Detailed module execution log
cat /var/log/cloud-init.log

Network not configured

  • Verify the interface name in meta-data.yaml matches the VM's actual interface (ip addr show on the VM console).
  • Photon OS 5.0 uses eth0. Ubuntu 20+/22+ on VMware typically uses ens160.
  • Use to: 0.0.0.0/0 for the default route, not to: default.

New-VM fails with EULA error

Ensure Get-OvfConfiguration is called before New-VM and that $ovfConfig.EULAs.Accept.Value = $true is set. See deploy-photon.ps1 step 4 for the correct pattern.

openjdk21 fails to install on Photon OS

The base OVF ships with chkconfig which conflicts with alternatives (required by openjdk21). The --allowerasing flag in user-data.yaml replaces chkconfig automatically:

- tdnf install -y --nogpgcheck --allowerasing alternatives
- tdnf install -y --nogpgcheck openjdk21

Adapting to other Linux distributions

The PowerCLI deployment script and the GuestInfo mechanism are the same for any cloud-init-enabled Linux distribution. Only the runcmd section of user-data.yaml needs to change:

Distro Package manager Java package name
Photon OS 5.0 tdnf openjdk21
Ubuntu 22.04 apt-get openjdk-21-jdk
Rocky Linux 9 dnf java-21-openjdk

The network interface name in meta-data.yaml also varies by distro — check with ip addr show on a running instance.


Security notes

  • Never commit real secrets to source control. All placeholders in the YAML files must be replaced locally before use.
  • The SSH deploy key should be read-only and scoped to a single repository. Do not reuse personal or organisation-wide SSH keys.
  • For production VMs, disable ssh_pwauth after provisioning is complete and rely on SSH key-based authentication only.
  • The .npmrc auth token should be a scoped, short-lived token with the minimum permissions required to download packages.

About

Sample code for Virtual Machine Deployments using Cloud-Init Configuration

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors