Introduction
Cloud instances are based on default cloud images. Since each instance uses a template operating system, it is up to the user to configure and set up a unique instance using user data.
Instead of configuring each after it runs up, there is an open source tool which automates the initialization- cloud-init.
What Is cloud-init?
Cloud-init is a service used for customizing Linux-based operating systems in the cloud. It allows you to customize virtual machines provided by a cloud vendor by modifying the generic OS configuration on boot. Canonical initially developed cloud-init for Ubuntu but expanded to most major Linux and FreeBSD operating systems. Today, it officially supports 8 Unix OSs - Ubuntu, Arch Linux, CentOS, Red Hat, FreeBSD, Fedora, Gentoo Linux, and openSUSE.
The service is used as an industry standard for early-stage initialization of a VM once it has been provisioned. Therefore, it allows you to set up a VM to work as needed on first boot.
Most vendors have the service preinstalled on Unix OS images. When creating a virtual machine using the cloud vendor dashboard, you will most likely have a cloud-init or user data section to specify the wanted configuration.
Cloud-init is used to install packages, configure users and security, write files, and do other tasks you want automatically handled on the first or subsequential boots.
How Does cloud-init Work?
Cloud-init is a service that sets up your VM instance with the wanted configuration and software ready to use. The service starts at boot and uses the metadata provided by the cloud provider or the direct user.
It does so by executing scripts, most commonly from the cloud-config file. Therefore, to change any default settings, you need to edit the cloud-config file on your VM image. This is a YAML file that follows basic YAML syntax rules, such as:
- Relationships between items are defined by indentations with whitespaces.
- A pipe character (|) before a text indicates it should be interpreted as is.
- Text blocks are indented.
- A leading dash (-) identifies members of a list.
- A colon (:) + space + value is used to create associative array entries.
You can add the cloud-config file:
- In the control plane interface, when selecting additional options. The provider will have a cloud-init or User data option where you can paste the configuration file.
- Through a file in the JSON object in an API request.
cloud-init Capabilities
The cloud-init service is used for a variety of things, including:
- Adding users and groups.
- Writing out arbitrary files.
- Adding YUM repositories.
- Running commands on first boot.
To learn the syntax used for each capability, read the subsections below.
Add Users and Groups Using cloud-init
To add users and groups to a VM during provisioning, use the following syntax in your cloud-config file:
#cloud-config
# Add groups to the system.
groups:
- group_name: [member1,member2]
# Add users to the system.
users:
- default
- name: User’s login name.
gecos: User’s real name.
primary_group: The primary group the user belongs to. If omitted, a new group is created under the user’s name.
groups: Additional groups to which you want to add the user.
selinux_user: The SELinux user for the user's login. If omitted, the system selects the default SELinux user.
expiredate: 'year-month-day' - Data when the user’s account should be disabled.
ssh_import_id: SSH IDs which you want to import.
lock_passwd: Use true or false to define whether you want to lock the password to disable password login. By default, the value is set to true.
inactive: 'x' - The number of days until the account is disabled after a password expires.
passwd: The hash of the password you want to use.
ssh_authorized_keys: Add keys to user’s authorized keys file:
- <ssh pub key 1>
- <ssh pub key 2>
system: Use true or false to define the new user as a system user.
sudo: Use sudo rule string(s) to define the user privileges. The user has no privileges by default, but it can accept one or multiple sudo rule strings. For example, add ALL=(ALL) NOPASSWD:ALL to give the user unrestricted access. To prevent sudo access, type: False.
- snapuser: Specify the email for your Ubuntu SSO account to allow snap to import a username and public keys into the system.
You don’t need to include all the options when adding a new user. The configurations listed above apply only if the user is new. If the user already exists, the system only modifies the following options:
- plain_text_passwd
- hashed_passwd
- lock_passwd
- sudo
- ssh_authorized_keys
- ssh_redirect_user
Writing Out Arbitrary Files
You can write out arbitrary files using the yaml configuration syntax. The content can be encoded (base64 or gzip) and specified in plain text or binary. Before the data is written to the defined path, it is decoded. The module supports all distros and has a frequency module of once-per-instance.
Note: If working with binary data, make sure to use the !!!binary
yaml option.
To write out arbitrary files with cloud-init, use the following syntax:
#cloud-config
# Write out arbitrary files
write_files:
path: The file path to which the content is added.
content: The content you want to add to the path.
owner: The user/group that has ownership. By default, the owner is root:root.
permissions: The permission of the specified path, defined with the appropriate octal string. The default permission is ‘0644’.
append: Use true or false to choose whether to append the specified content to an existing file if the path provided exists. The default value is false.
Adding YUM Repositories
You may need to configure a yum repository to ensure you are using the correct packages to install the wanted software. Use cloud-init to add yum repository configurations to the system. The configuration file is added to /etc/yum.repos.d.
To add a yum repository configuration, use the syntax:
yum_repos:
<repo_name>:
baseurl: Repository URL.
name: Repository name.
enabled: true/false
+ any other repository configuration option
Running Commands on First Boot
To run arbitrary commands early in the boot process, you can use the bootcmd or runcmd module.
bootcmd
run specific commands on every boot, after running a boothook. It supports all distros and accepts commands specified as lists or strings. The syntax is:
bootcmd:
- array of (array of string)/(string)
For instance:
bootcmd:
- echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts
- [cloud-init-per, once, mymkfs, mkfs, /dev/vdb ]
runcmd
runs a command only on first boot. It can execute commands specified as lists or strings. All the commands have to be in the yaml syntax (therefore, make sure to quote any problematic characters). The syntax is:
runcmd:
- array of (array of string)/(string)
Like in the following example:
runcmd:
- [ ls, -l, / ]
- [ sh, -xc, "echo $(date) ': hello world!'" ]
- [ sh, -c, echo "=========hello world'=========" ]
- ls -l /root
Note: Make sure not to write files to /tmp from cloud-init. Instead, use /run/somedir.
Configure SSH Keys
You can manage SSH configuration using cloud-init.
Authorized keys are SSH keys stored in the user's home directory, in .ssh/authorized_keys. They define which keys can connect to that specific user account on the system. Add the public keys as a list when configuring a user using ssh_authorized_key:
ssh_authorized_keys:
- ssh_pub_key_1
- ssh_pub_key_2
The listed keys will belong to the configured user or the first one defined in the user's module.
If you already have pre-generated private SSH keys, you can store them on the server. Cloud-init supports RSA, DSA, and ECDS public key cryptosystems. Make sure to pay attention to formatting when adding the SSH keys - use line breaks, blocks, pipe keys, and always specify the BEGINING PRIVATE KEY and END PRIVATE KEY.
ssh_keys:
rsa_private: |
-----BEGIN RSA PRIVATE KEY-----
your_rsa_private_key
-----END RSA PRIVATE KEY-----
rsa_public: your_rsa_public_key
Set Up a Locale
To set up and apply a system locale system wide, utilize the cc_locale module. Use the following configuration shema to define the:
locale: What you want to configure as the system's locale.
locale_configfile: The path to the file where you want to write the locale configuration.
Define the Hostname
With cloud-init, you can set the hostname and FQDN (fully qualified domain name). There are several ways to do so:
- Specify the full domain name using the
fqdn
key. - Define the hostname using the
hostname
key. - Use the
hostname
key to define fqdn (not recommended). - Use both the the
hostname
key and thefqdn
key.
The configuration keys for defining the hostname include:
preserve_hostname: Use true or false to set whether to preserve the host name or allow altering.
prefer_fqdn_over_hostname: Use true or false to set whether to force the use of FQDN in all distros.
fqdn: FQDN
hostname: FQDN/hostname
Note: Learn how to use Cloud-init on Bare Metal Cloud via Portal and API.
Conclusion
Use the cloud-init package to seamlessly initialize your cloud instances with the configuration and software set up and ready to use. Add users and groups, write out arbitrary files, add yum repositories or run commands on first boot with the help of this powerful tool.