Advanced : customized creation

Custom creation with cloud-init

You can customise your instance’s creation by providing a user data file.

Cloud-init package is used to manage the initialization of an instance using user data.
It can only act on user data of following types :

  • include-once-url
  • include-url
  • cloud-config-archive
  • upstart-job
  • cloud-config
  • part-handler
  • shellscript
  • cloud-boothook

The type defines how the data file should start:

  • a data script will start with: #!
  • an include file: #include
  • a cloud configuration file (cloud-config): #cloud-config
  • an upstart job: #upstart-job
  • a cloud boothook: #cloud-boothook
  • a part handler: #part-handler

In this documentation, we will focus on the cloud-config type.
But you can read more about the cloud-init documentation: https://cloudinit.readthedocs.io/en/latest/topics/format.html

Cloud-config file

Cloud-config is an easy way to define tasks to be performed when the instance is launched.

A cloud-config file must be written with valid yaml syntax.

First, the file must begin with #cloud-config.

#cloud-config
# vim: syntax=yaml
# This is a cloud-config file for user-data

Installing packages

The packages keyword is used to install packages. To upgrade them, set package_upgrade to true.
Then, all you have to do is list the packages to install.

package_upgrade: true

packages:
  - aptitude
  - linuxlogo
  - vim
  - ssh
  - python
  - gcc
  - g++

Note that you do not need to specify the repository to collect them from.

Add users

By using keyword users, you can add users.
These users can then access the instance using their public key.

users:

  - name: "user1"
    gecos: "user 1"
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: [ wheel , sudo ]
    homedir: "/home/user1"
    shell: "/bin/bash"
    ssh-authorized-keys: [ < public_key_user1 > ]
    
  - name: "ubuntu"
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: [ wheel , sudo ]
    homedir: "/home/ubuntu"
    shell: "/bin/bash"
    ssh-authorized-keys: [ < public_key_user1 > , < public_key_user2 > ]
    
  - name: "user2"
    gecos: "user 2"
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: [ wheel , sudo ]
    homedir: "/home/user2"
    shell: "/bin/bash"
    ssh-authorized-keys: [ < public_key_user2 > ]

File writing

It is possible to write files on first launch with write_files.
Then, please specify its content, its access path, its permissions and its owner.

write_files:

  - content: |
      #!/bin/bash
      var="Hello World"
      echo "$var"
    owner: root:root
    path: /home/ubuntu/hello.sh
    permissions: '0777'
    
  - content: |
      #!/bin/bash
      now="$(date)"
      computer_name="$(hostname)"
      echo "Current date and time : $now"
      echo "Computer name : $computer_name"
    owner: root:root
    path: /home/ubuntu/Hello/date.sh
    permissions: '0777'

Run commands

The runcmd keyword lists commands you want to run in a terminal.

runcmd:
  # Customize bash for user
  - echo "linuxlogo" >> /home/user/.bashrc
  - source /home/user/.bashrc
  # Run two previous scripts
  - bash /home/ubuntu/hello.sh
  - bash /home/ubuntu/Hello/date.sh

Final message

A final message can be displayed in the launch logs of an instance.
This will show that all the cloud-init correctly ran.

final_message: "The system is finally up, after $UPTIME seconds"

Create a custom instance

Creating a custom instance is done in the same way as for a basic instance.
Just add the user data file option (--user-data cloud-config).

$ openstack server create \
    --image <image> \
    --flavor <flavor> \
    --user-data cloud-config \
    --network <project>-int-net \
    --security-group <group> \
    --key-name <rsa-key> \
    <instance-name>

Create instance from volume

You can start an instance from a volume rather than an image.

For this, use the instance creation command $ openstack server create with the following options

  • --block-device : allows to boot from an existing source (image, volume or snapshot).
    For example, booting instance from an image and attaching a non-bootable volume. Or create volume from an image, then launch an instance from that volume.
  • --swap : joined a swap disk to instance.
  • --ephemeral : joined an ephemeral disk to instance.

To learn more about creating instance from volume, please refer to the OpenStack documentation page.
OpenStack documentation