Cloud-init can be found on most cloud images provided by an elastic cloud vendor. If you are rolling/baking your own cloud image, you can typically install cloud-init via your distro's package manager.

Cloud-init executes in several key stages.

Stage-1 - Init Local

  • /etc/init/cloud-init-local.conf (Upstart)

    • start on mounted MOUNTPOINT=/
  • /lib/systemd/system/cloud-init-local.service (Systemd)

    • cloud-init.service
    • systemd-journald.socket system.slice
  • Execute: /usr/bin/cloud-init init --local

  • Runs prior to network setup. It looks for a NoCloud data source at /var/lib/cloud/seed/nocloud/{meta-data,user-data,network-data,vendor-data}. If present, it will copy to /var/lib/cloud/instances/<instance-id> and execute all Python modules listed in init stage at /etc/cloud/cloud.cfg.

  • If a data source is not found at the above, it will look for VFAT or ISO device with LABEL="cidata". If present, it will copy to /var/lib/cloud/instances/<instance-id> and excute all Python modules listed in init stage at /etc/cloud/cloud.cfg.

Stage-2 - Init

  • /etc/init/cloud-init.conf (Upstart)

    • start on mounted MOUNTPOINT=/
    • stopped cloud-init-nonet (After network is up)
  • /lib/systemd/system/cloud-init.service (Systemd)

    • systemd-user-sessions.service sshd-keygen.service ssh.service
    • cloud-init-local.service system.slice systemd-journald.socket
  • Execute: /usr/bin/cloud-init init

  • datasource_list: [ NoCloud, ConfigDrive, OpenNebula, Azure, AltCloud, OVF, MAAS, GCE, OpenStack, CloudSigma, Ec2, CloudStack, None ] (/etc/cloud/cloud.cfg.d/90_dpkg.cfg)

  • By default, first datasource listed is the priority. If metadata is discovered, it is copied to /var/lib/cloud/instances/<instance-id>/.

  • All Python modules listed in init stage (/etc/cloud/cloud.cfg) will execute.

Stage-3 - Config

  • /etc/init/cloud-config.conf (Upstart)

    • start on (filesystem and started rsyslog)
  • /lib/systemd/system/cloud-config.service (Systemd)

    • Before=cloud-final.service
    • After=systemd-journald.socket system.slice
  • Execute: /usr/bin/cloud-init modules --mode=config

  • All Python modules listed in config stage (/etc/cloud/cloud.cfg) will execute.

Stage-4 - Final

  • /etc/init/cloud-final.conf (Upstart)

    • start on (stopped rc RUNLEVEL=[2345] (starts after rc.local)
    • stopped cloud-config
  • /lib/systemd/system/cloud-final.service (Systemd)

    • After=rc-local.service cloud-config.service system.slice systemd-journald.socket
  • Execute: /usr/bin/cloud-init modules --mode=final

  • All Python modules listed in final stage (/etc/cloud/cloud.cfg) will execute.

Additional Info

  • Most cloud-init Python modules have a default run frequency: per_always (run on every boot), per_instance (run only if it has never run with this specific instance-id), per_boot (run only once, regardless of the instance-id).
  • Cloud-init keeps track of whether particular modules have been run by using semaphores. These get placed into the /var/lib/cloud/sem and /var/lib/cloud/sem/instances/<instance-id>/sem directories.
  • One can specify which specific modules to run at specific stages and override default module frequency:
  - seed_random
  - [bootcmd, once]
  - [write-files, instance]
  - growpart
  - resizefs
  - set_hostname
  - update_hostname
  - rsyslog
  - users-groups
  - ssh

  - disable-ec2-metadata
  - runcmd
  - byobu

  - scripts-per-boot
  - scripts-per-instance
  - [scripts-user, always]


comments powered by Disqus