Skip to content

Provision with cloud-init

cloud-init is the industry-standard multi-distribution method for cross-platform cloud instance initialization. Garden Linux uses cloud-init on all major cloud platforms (AWS, Azure, GCP, OpenStack) for first-boot provisioning and configuration.

What is cloud-init?

cloud-init is a widely-adopted provisioning tool that automates the initialization of cloud instances. It runs on every boot (not just first boot) and performs tasks including:

  • Creating users and groups
  • Adding SSH authorized keys
  • Configuring networking (DHCP, static IPs)
  • Writing files to disk
  • Running custom shell scripts
  • Installing packages
  • Configuring system services

cloud-init fetches its configuration from the cloud platform's metadata service or via user-data mechanisms specific to each platform.

When to Use cloud-init

Use cloud-init for:

  • AWS deployments — EC2 instances
  • Azure deployments — Virtual machines
  • GCP deployments — Compute Engine instances
  • OpenStack deployments — Nova instances
  • VMware deployments — vSphere virtual machines

For bare-metal and PXE boot deployments, use Ignition instead, as Ignition is designed for first-boot-only metal provisioning.

Prerequisites

  • Garden Linux cloud platform image (aws, azure, gcp, openstack, vmware flavors automatically include cloud-init)
  • Access to the cloud platform's user-data mechanism (varies by platform)

Common Provisioning Tasks

Enable SSH

Garden Linux disables SSH by default for security. Enable SSH using cloud-init user-data:

bash
#!/usr/bin/env bash
systemctl enable --now ssh

This is the minimal user-data required for all Garden Linux cloud deployments to enable remote SSH access.

Create Users

Add a new user with SSH key authentication:

yaml
#cloud-config
users:
  - name: myuser
    groups: wheel
    shell: /bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExamplePublicKeyHere user@host

The wheel group provides passwordless sudo access in Garden Linux.

Default Usernames per Platform

Garden Linux cloud images include a platform-specific default user:

PlatformDefault Username
AWSec2-user
Azureazureuser
GCPgardenlinux
OpenStackadmin

These users are pre-configured with SSH key access via the cloud platform's metadata service. You only need to enable SSH to access them.

Configure Networking

Most cloud platforms handle networking automatically via DHCP and metadata services. For custom network configuration, use cloud-init network configuration:

yaml
#cloud-config
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: false
      addresses:
        - 192.168.1.100/24
      gateway4: 192.168.1.1
      nameservers:
        addresses:
          - 9.9.9.9
          - 1.1.1.1

Run Custom Scripts

Execute shell commands or scripts during instance initialization:

bash
#!/usr/bin/env bash
# Enable SSH
systemctl enable --now ssh

# Install additional packages
mount -o remount,rw /usr
apt-get update
apt-get install -y htop vim curl
mount -o remount,ro /usr

# Configure application
mkdir -p /opt/myapp
cat > /opt/myapp/config.yaml <<EOF
database:
  host: db.example.com
  port: 5432
EOF

Garden Linux mounts /usr read-only by default. Remount it read-write before installing packages, then remount read-only afterward.

Write Configuration Files

Use cloud-config to write files to disk:

yaml
#cloud-config
write_files:
  - path: /etc/hostname
    content: |
      my-server.example.com
    owner: root:root
    permissions: '0644'
  - path: /opt/myapp/config.yaml
    content: |
      database:
        host: db.example.com
        port: 5432
    owner: root:root
    permissions: '0600'

Install Packages

Install additional software packages on first boot:

yaml
#cloud-config
packages:
  - htop
  - vim
  - curl
  - jq

runcmd:
  - mount -o remount,rw /usr
  - apt-get update
  - apt-get install -y htop vim curl jq
  - mount -o remount,ro /usr

Configure Systemd Services

Enable and start systemd units:

yaml
#cloud-config
runcmd:
  - systemctl enable --now ssh
  - systemctl enable --now my-custom-service

Deliver the Configuration

How you deliver cloud-init configuration depends on the cloud platform. Each platform provides its own mechanism for attaching user-data to instances:

PlatformDelivery MechanismOfficial DocumentationGarden Linux Guide
AWSEC2 user-dataEC2 User DataInstall on AWS
AzureCustom dataAzure Custom DataInstall on Azure
GCPMetadataGCP cloud-initInstall on GCP
OpenStackConfigDrive or metadata serviceOpenStack User DataInstall on OpenStack

For step-by-step deployment walkthroughs including instance creation with user-data, see the platform-specific tutorials:

cloud-config vs Shell Scripts

cloud-init supports two user-data formats:

Shell Scripts (Shebang Format)

Start with a shebang (#!/usr/bin/env bash). cloud-init executes the script directly:

bash
#!/usr/bin/env bash
systemctl enable --now ssh
echo "Hello from Garden Linux" > /etc/motd

cloud-config (YAML Format)

Start with #cloud-config. Provides declarative configuration:

yaml
#cloud-config
users:
  - name: myuser
    groups: wheel
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3Nza...

write_files:
  - path: /etc/motd
    content: |
      Hello from Garden Linux

Use shell scripts for simple tasks and procedural logic. Use cloud-config for declarative user and file management.

Troubleshooting

View cloud-init Logs

Check cloud-init execution logs:

bash
# View cloud-init status
cloud-init status --long

# View cloud-init logs
journalctl -u cloud-init

# View detailed logs
cat /var/log/cloud-init.log
cat /var/log/cloud-init-output.log

Validate Configuration Syntax

Test cloud-config syntax before deploying:

bash
# Validate cloud-config YAML
cloud-init schema --config-file user_data.yaml

# Dry-run cloud-init
cloud-init devel schema --config-file user_data.yaml

Common Errors

  • SSH not enabled — Ensure user-data includes systemctl enable --now ssh
  • User not created — Verify cloud-config YAML syntax and check /var/log/cloud-init.log
  • Metadata not fetched — Confirm the instance has network connectivity to the metadata service
  • Script not executed — Ensure shell scripts start with a valid shebang (#!/usr/bin/env bash)

Advanced Configuration

Multi-Part MIME User-Data

Combine multiple user-data formats (cloud-config + shell script):

python
#!/usr/bin/env python3
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

combined = MIMEMultipart()

# Part 1: cloud-config
cloud_config = """#cloud-config
users:
  - name: myuser
    groups: wheel
"""
combined.attach(MIMEText(cloud_config, 'cloud-config'))

# Part 2: shell script
shell_script = """#!/usr/bin/env bash
systemctl enable --now ssh
"""
combined.attach(MIMEText(shell_script, 'x-shellscript'))

print(combined.as_string())

Conditional Execution

Run commands only on specific platforms:

yaml
#cloud-config
runcmd:
  - [ sh, -c, 'if [ "$(cloud-init query platform)" = "aws" ]; then echo "Running on AWS"; fi' ]

Fetch External Configuration

Download and apply configuration from external sources:

yaml
#cloud-config
runcmd:
  - curl -o /tmp/setup.sh https://example.com/setup.sh
  - bash /tmp/setup.sh

Reference