Publish Virtual Machine Image
Publishing a VirtualMachine as a new VM image enables you to capture the current state of a VM and make it available as a reusable image template. VM Operator provides the VirtualMachinePublishRequest API to facilitate this process, allowing you to create custom VM images from running or powered-off VirtualMachines.
Overview
The VirtualMachinePublishRequest API enables you to:
- Capture VM State: Create a snapshot of a VirtualMachine's current configuration and disk state
- Publish to Content Library: Store the captured image in a vSphere Content Library for reuse
- Automate Image Creation: Integrate with tools like Packer for automated image building workflows
- Version Control: Maintain multiple versions of VM images with descriptive metadata
How VM Publishing Works
The VM publishing process follows these steps:
- Request Creation: A VirtualMachinePublishRequest is created specifying the source VM and target location
- Validation: The controller validates that the source VM exists and the target Content Library is accessible
- VM Capture: The VM is captured as an OVF template using vSphere APIs
- Upload: The captured template is uploaded to the specified Content Library
- Image Creation: A new VirtualMachineImage resource is created referencing the published template
- Completion: The request is marked as complete and optionally cleaned up based on TTL settings
VirtualMachinePublishRequest API
Basic Structure
apiVersion: vmoperator.vmware.com/v1alpha5
kind: VirtualMachinePublishRequest
metadata:
  name: my-vm-publish-request
  namespace: my-namespace
spec:
  source:
    name: source-vm-name
    apiVersion: vmoperator.vmware.com/v1alpha5
    kind: VirtualMachine
  target:
    item:
      name: my-custom-image
      description: "Custom VM image created from my-vm"
    location:
      name: my-content-library
      apiVersion: imageregistry.vmware.com/v1alpha1
      kind: ContentLibrary
  ttlSecondsAfterFinished: 3600
Field Reference
Source Configuration
- source.name: Name of the VirtualMachine to publish (defaults to the VirtualMachinePublishRequest name)
- source.apiVersion: API version of the source object (default:- vmoperator.vmware.com/v1alpha5)
- source.kind: Kind of the source object (default:- VirtualMachine)
Target Configuration
- target.item.name: Display name for the published image (defaults to- {source.name}-image)
- target.item.description: Optional description for the published image
- target.location.name: Name of the target ContentLibrary resource
- target.location.apiVersion: API version of the target (default:- imageregistry.vmware.com/v1alpha1)
- target.location.kind: Kind of the target (default:- ContentLibrary)
TTL Configuration
- ttlSecondsAfterFinished: Time-to-live for the request after completion (optional)
Examples
Basic VM Publishing
apiVersion: vmoperator.vmware.com/v1alpha5
kind: VirtualMachinePublishRequest
metadata:
  name: ubuntu-golden-image
  namespace: default
spec:
  source:
    name: ubuntu-vm-template
  target:
    item:
      name: ubuntu-22.04-golden
      description: "Ubuntu 22.04 golden image with security patches"
    location:
      name: default-content-library
Publishing with Automatic Cleanup
apiVersion: vmoperator.vmware.com/v1alpha5
kind: VirtualMachinePublishRequest
metadata:
  name: temp-build-publish
  namespace: ci-cd
spec:
  source:
    name: build-vm
  target:
    item:
      name: app-server-v2.1.0
      description: "Application server image v2.1.0"
    location:
      name: production-images
  ttlSecondsAfterFinished: 300  # Clean up after 5 minutes
Minimal Configuration (Using Defaults)
apiVersion: vmoperator.vmware.com/v1alpha5
kind: VirtualMachinePublishRequest
metadata:
  name: web-server
  namespace: default
# Uses defaults:
# - source.name: web-server (same as metadata.name)
# - target.item.name: web-server-image
# - target.location: ContentLibrary with label "imageregistry.vmware.com/default"
Integration with Packer
VM Operator integrates seamlessly with HashiCorp Packer's vSphere Supervisor builder, enabling automated image building workflows.
Packer Configuration Example
source "vsphere-supervisor" "ubuntu-image" {
  # Source image configuration
  image_name = "ubuntu-22.04-base"
  class_name = "best-effort-large"
  storage_class = "wcplocal-storage-profile"
  # Bootstrap configuration for guest customization
  bootstrap_provider = "CloudInit"
  bootstrap_data_file = "cloud-init-config.yaml"
  # Publish configuration
  publish_location_name = "golden-images-library"
}
build {
  sources = ["source.vsphere-supervisor.ubuntu-image"]
  # Provisioning steps
  provisioner "shell" {
    scripts = [
      "scripts/install-security-updates.sh",
      "scripts/install-monitoring-agent.sh",
      "scripts/cleanup.sh"
    ]
  }
  # Post-processing
  post-processor "manifest" {
    output = "manifest.json"
  }
}
Bootstrap Provider Support
The Packer vSphere Supervisor builder supports all VM Operator bootstrap providers:
CloudInit Bootstrap
source "vsphere-supervisor" "linux-vm" {
  bootstrap_provider = "CloudInit"
  bootstrap_data_file = "cloud-init.yaml"
  # ... other configuration
}
Sysprep Bootstrap (Windows)
source "vsphere-supervisor" "windows-vm" {
  bootstrap_provider = "Sysprep"
  bootstrap_data_file = "sysprep.xml"
  # ... other configuration
}
vAppConfig Bootstrap
source "vsphere-supervisor" "appliance-vm" {
  bootstrap_provider = "vAppConfig"
  bootstrap_data_file = "vapp-properties.json"
  # ... other configuration
}
Status and Monitoring
Checking Publication Status
# Check the status of a publish request
kubectl get vmpub ubuntu-golden-image -o yaml
# Watch the progress
kubectl get vmpub ubuntu-golden-image -w
Status Conditions
The VirtualMachinePublishRequest reports its progress through status conditions:
- SourceValid: Source VM exists and is accessible
- TargetValid: Target Content Library exists and is accessible
- Uploaded: VM has been successfully uploaded to the Content Library
- ImageAvailable: VirtualMachineImage resource has been created
- Complete: All operations completed successfully
Example Status
status:
  ready: true
  imageName: ubuntu-22.04-golden
  startTime: "2024-01-15T10:00:00Z"
  completionTime: "2024-01-15T10:15:00Z"
  attempts: 1
  conditions:
  - type: SourceValid
    status: "True"
    lastTransitionTime: "2024-01-15T10:00:30Z"
  - type: TargetValid
    status: "True"
    lastTransitionTime: "2024-01-15T10:01:00Z"
  - type: Uploaded
    status: "True"
    lastTransitionTime: "2024-01-15T10:12:00Z"
  - type: ImageAvailable
    status: "True"
    lastTransitionTime: "2024-01-15T10:14:00Z"
  - type: Complete
    status: "True"
    lastTransitionTime: "2024-01-15T10:15:00Z"
Best Practices
VM Preparation
- Power Off VMs: While publishing powered-on VMs is supported, powering off ensures consistency
- Clean Up Temporary Files: Remove logs, temporary files, and sensitive data before publishing
- Generalize the Image: Remove machine-specific configurations (hostnames, SSH keys, etc.)
- Install VMware Tools: Ensure VMware Tools are installed for optimal performance
Content Library Management
- Use Descriptive Names: Choose meaningful names for published images
- Add Metadata: Include comprehensive descriptions and version information
- Organize by Purpose: Use separate Content Libraries for different image types (base images, application images, etc.)
- Regular Cleanup: Remove unused images to manage storage consumption
Automation Considerations
- Use TTL: Set appropriate ttlSecondsAfterFinishedvalues for automated workflows
- Monitor Progress: Implement proper status checking in CI/CD pipelines
- Handle Failures: Plan for retry logic and error handling
- Version Control: Maintain consistent naming conventions for image versions
Troubleshooting
Common Issues
Source VM Not Found
conditions:
- type: SourceValid
  status: "False"
  reason: "SourceNotFound"
  message: "VirtualMachine 'missing-vm' not found in namespace 'default'"
Solution: Verify the source VM name and namespace are correct.
Target Content Library Unavailable
conditions:
- type: TargetValid
  status: "False"
  reason: "TargetLocationNotFound"
  message: "ContentLibrary 'missing-library' not found"
Solution: Ensure the ContentLibrary resource exists and is accessible.
Upload Failures
conditions:
- type: Uploaded
  status: "False"
  reason: "UploadFailure"
  message: "Failed to upload VM to content library: insufficient storage"
Solution: Check Content Library storage capacity and vCenter connectivity.
Debugging Commands
# Get detailed status
kubectl describe vmpub my-publish-request
# Check related VirtualMachineImage
kubectl get vmi -l "virtualmachinepublishrequest.vmoperator.vmware.com/name=my-publish-request"
# View controller logs
kubectl logs -n vmware-system-vmop deployment/vmware-system-vmop-controller-manager
Related Resources
- VirtualMachine Images - Learn about VM image management
- Content Libraries - vSphere Content Library documentation
- Packer vSphere Supervisor Builder - Packer integration guide