Machine test panel used after a cloud image first boot

cloud-init vs Image Build: Put Configuration in the Right Phase

Decide which Linux configuration belongs in a reusable image and which belongs in cloud-init, with first-boot stages, schema checks, security boundaries, and release tests.

September 24, 2026

← Back to Blog

Bake shared, expensive, and security-sensitive state into the image. Keep identity and small site-specific values in cloud-init. Test both the reusable artifact and a launched instance.

cloud-init is first-boot configuration management for an image that already exists. Its current project documentation describes initialization of networking, storage, SSH keys, packages, and other instance state across public cloud, private cloud, and bare-metal provisioning systems. That breadth does not turn it into an installer or an image compiler.

Split configuration by change frequency

ConfigurationPreferred phaseReason
Kernel, bootloader, filesystemImage buildThey must exist before cloud-init can run.
Large package setsImage buildAvoid repeating downloads and package failure on every launch.
Security baselineImage buildScan and test one reviewed artifact before release.
Hostname and instance identitycloud-initValues differ for each launched instance.
SSH authorized keyscloud-initThe platform can inject the operator or workload identity.
Small site-specific filescloud-initThey bind a reusable image to one region, role, or environment.

Keep first-boot data small and observable

#cloud-config
hostname: edge-01
ssh_pwauth: false
users:
  - default
  - name: ops
    groups: [adm, sudo]
    lock_passwd: true
    ssh_authorized_keys:
      - "ssh-ed25519 AAAA... operator@example"
package_update: true
packages:
  - prometheus-node-exporter
write_files:
  - path: /etc/openfactory/site.conf
    permissions: "0644"
    content: |
      region=eu-central
runcmd:
  - [systemctl, enable, --now, prometheus-node-exporter]
final_message: "cloud-init finished after $UPTIME seconds"

The first line must identify cloud-config. Do not place plain-text credentials in user data. Platform metadata services and serial output can expose more than an application owner expects, and a copied launch template can spread one credential across a fleet. Inject public keys and retrieve runtime secrets through the platform's approved secret path.

Image build and cloud-init boot stagesA tested image is released first. A launched instance then passes cloud-init detect, local, network, config, and final stages before instance acceptance.Tested imageshared baselineDetectLocalNetworkConfigFinalcloud-init status --waitdata sourcenetwork onlineusers and filespackages and scriptsInstance acceptanceidentity, SSH, service, network, storage, reboot
SSH may become reachable before final-stage package and script work has finished. Wait for cloud-init before testing the workload.

Validate YAML, then wait for runtime completion

The official user-data validation guide provides a static schema command:

cloud-init schema -c cloud-config.yml --annotate

After launch, wait with cloud-init status --wait. Then read the status result and logs before running machine checks. A reachable SSH port can coexist with unfinished final-stage package work, so an early probe can produce a false failure or accept a partially configured host.

Test both layers independently

  1. Boot the image with empty or minimal instance data and test its baseline.
  2. Launch with representative cloud-config and wait for final completion.
  3. Confirm per-instance identity changed without altering the shared security policy.
  4. Restart without replay assumptions and prove the workload returns.

This split keeps a failed instance customization from hiding a broken image, and keeps a good image from masking a bad cloud-config file. OpenFactory fits on the reusable side by building and booting the Linux artifact before it receives site-specific launch data.

Frequently asked questions

Does cloud-init build a machine image?

No. cloud-init runs inside an existing image. It discovers a data source and applies instance configuration during boot stages.

Should package installation happen in cloud-init?

Small, instance-specific additions can fit. Large or release-critical package sets are usually better in the image so they are downloaded, scanned, and tested once before launch.

How can I validate cloud-config before launch?

Run cloud-init schema against the file, then launch a disposable instance and wait for cloud-init status. Static validation cannot prove repository, network, or command behavior.

Ready to ship this in production?

OpenFactory's free flow is for browsing. Persistent VMs, SSH access, snapshots, your own ISO, and fleet deployment live on a paid plan.