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)

    • Before=shutdown.target multi-user.target cloud-config.target cloud-init.service
    • After=local-fs.target systemd-journald.socket basic.target 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)

    • Before=multi-user.target shutdown.target systemd-user-sessions.service cloud-config.target sshd-keygen.service ssh.service
    • After=network-online.target basic.target cloud-init-local.service system.slice systemd-journald.socket local-fs.target
  • 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 multi-user.target shutdown.target
    • After=systemd-journald.socket network-online.target syslog.target system.slice basic.target cloud-config.target
  • 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)

    • Before=multi-user.target shutdown.target
    • After=rc-local.service network-online.target cloud-config.service basic.target system.slice systemd-journald.socket syslog.target
  • 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:
#cloud-config
cloud_init_modules:
  - seed_random
  - [bootcmd, once]
  - [write-files, instance]
  - growpart
  - resizefs
  - set_hostname
  - update_hostname
  - rsyslog
  - users-groups
  - ssh

cloud_config_modules:
  - disable-ec2-metadata
  - runcmd
  - byobu

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


Comments

comments powered by Disqus