When bootstrapping a new server or instance, the first boot is often very different from all the other boots the instance will experience in its life, and most often we want some commands to be executed very early or very late in the boot process. For example, let's say our cloud instance is launched with an attached block storage. We might want to format this storage space and be sure it's mounted on the host, but while we always want the disk to mount, we probably don't want it to be formatted at each boot! The bootcmd
directive is there to handle everything related to commands to be executed very early in the boot process, while the runcmd
directive is executed much later in the boot process (and only once).
To step through this recipe, you will need:
We'll launch three commands during boot. The first one is a simple file with a dynamic content (the $INSTANCE_ID
variable made available to us by cloud-init), which will always be rewritten, no matter what, at each boot. The second command is printing the date in the logs (so we know when the boot process started). The final command is the ext4
formatting of a block device attached on /dev/xvdb
. For the sake of the exercise, we'll also mount the new device under /srv/www
on the host.
To launch any command at boot time that will be run as early as possible, every time the machine boots, simply add it to the list of the bootcmd
directive:
#cloud-config bootcmd: - echo bootcmd started at $(date) - echo $INSTANCE_ID > /etc/instance_id
If we delete or modify this file, at the next reboot it will be overwritten.
On the other hand, if we want to run a command only once inside the bootcmd
directive, we can use the helper script cloud-init-per
. You can choose to launch the command once per boot
or once per instance
. In our case, we want to format the /dev/xvdb
device (so, unless we want to format our drive each time we reboot, we probably want this to happen only once on this instance. So let's add the instance
argument to the cloud-init-per
helper script):
#cloud-config bootcmd: - cloud-init-per instance mkfs-xvdb mkfs -t ext4 /dev/xvdb
Finally, let's use the mounts
directive to mount the now formatted /dev/xvdb
on the /srv/www
folder:
mounts: - [ /dev/xvdb, /srv/www ]
After boot, let's verify the block device is mounted:
# df -h /srv/www/ Filesystem Size Used Avail Use% Mounted on /dev/xvdb 4.8G 10M 4.6G 1% /srv/www
We can also test the existence of the file we created:
# cat /etc/instance_id i-03005dd324599df11
Try to delete this file and reboot the server: the file will be there again.
Now, let's take a look at how different the runcmd
directive is. Let's add a very similar command to the date output in the bootcmd
directive:
runcmd: - 'echo runcmd started at $(date)'
Start a new instance, and observe the difference in timestamps:
$ grep "started at" /var/log/cloud-init-output.log bootcmd started at Fri Sep 23 07:02:35 UTC 2016 + echo runcmd started at Fri Sep 23 07:02:47 UTC 2016 runcmd started at Fri Sep 23 07:02:47 UTC 2016
The runcmd
directive started 12 seconds later than the bootcmd
directive.
Now reboot the instance, and observe that runcmd
didn't run again:
$ grep "started at" /var/log/cloud-init-output.log bootcmd started at Fri Sep 23 07:04:31 UTC 2016
Now we know what directive to use in each case.
18.227.46.69