Cloud InitIn the previous post we’ve seen how to setup and configure Cloud Automation Services, how to use Cloud Assembly to create a fully Cloud agnostic blueprint, how to use input variables and how to integrate Cloud Automation Services with Puppet. In this post I will discuss how to use Cloud-Init to customize the deployment eg. how to install applications on top of that virtual machine component in the blueprint.

In vRealize Automation this process depends on a vRealize Automation guest- and a bootstrap agent. With Cloud Automation Services, VMware stepped away from this and adopted an industry standard method called Cloud-Init.

 

What is Cloud-Init?

When deploying virtual machines using Cloud Automation Services, every instance starts out as a clone of a template, ami, or image. To give the virtual machine its specific role and configuration you need a tool that does this customization. Cloud-init is the service that is installed inside the instance and applies a cloud-config automatically as soon as the instance is started. Cloud-config is the language of the scripts that cloud-init knows to execute.

While cloud-init started life in Ubuntu, it is now available for most major Linux and FreeBSD operating systems. It is currently installed in the Ubuntu Cloud Images and also in the official Ubuntu images available on EC2, Azure, GCE and many other clouds. For a list of Cloud-Init enabled virtual machines in Azure see this list.

For Microsoft Windows workloads, the equivalent is CloudBase-init but is this is currently not usable within Cloud Assembly.

Cloud-Init starts early at boot, retrieves metadata that has been provided from an external provider (metadata) or by direct user data supplied by the user.

You can use Cloud Init to perform a variety of actions:

  • Create users.
  • Setting a default locale.
  • Modifying configuration files.
  • Setting a hostname.
  • Creating files or folders.
  • Setting up mount points.
  • Configuring network devices.
  • Install applications.
  • …..

 

How do I prepare for Cloud-Init?

If you’re using images that are not Cloud-Init enabled, like on your vSphere environment, you can set it up in the following way.

Red Hat/CentOS

For Red Hat / CentOS run the following commands:

sudo yum install -y cloud-init gdisk
sudo yum check-update cloud-init -y
sudo yum install cloud-init -y

Ubuntu/Debian

For Ubuntu 14.04 and 16.04, please use vanilla cloud-init. Use the stock Ubuntu images provided by Canonical, which come with cloud-init pre-installed.
If you’re using non-Canonical images, use the following command-line to install cloud-init on Debian-based systems.

apt-get -y update
apt-get -y install cloud-init

 

How do I use Cloud-Init?

Now that you’ve enabled Cloud-Init on your templates or images, it’s time to look at some examples/possibilities. Cloud-Init starts at the virtual machine’s first boot and retrieves the metadata that has been provided from an external provider. In the case of Cloud Automation Services, the metadata or instructions that are needed to perform are provided in the blueprint YAML code. See the image below:

inputs: {}
resources:
  Web_Server:
    type: Cloud.Machine
    properties:
      image: ubuntu
      flavor: small
      constraints:
        - tag: "env:dev"
      networks:
        - name: '${WP-Network.name}'
      cloudConfig: |
        #cloud-config
        
  WP-Network:
    type: Cloud.Network
    properties:
      name: WP-Network
      networkType: public

 

In the red square, below line 13 you can now insert your code. Make sure you have the right indentation.

Cloud-Init examples

For instance, create a directory using Cloud-init.

#cloud-config
  runcmd:
  - mkdir -p [directory_location]
  - mkdir -p /var/www/html/mywebsite

Restart a service.

#cloud-config
  runcmd:
  - service [servicename] reload
  - service apache2 reload

Set hostname.

#cloud-config
  hostname: [host_name] #static hostname
  hostname: ${input.vmname} #using input variable
  hostname: 'srv-web01'

Run commands on first boot.

#cloudConfig
  <script>
  sh [command or script]
  sh, -xc, "echo $(date) ': Hello World!'"
  </script>

Create a new user with ssh-rsa key access and bash shell environment.

#cloud-config
users:
  - name: demo
    ssh-authorized-keys:
      - ssh-rsa <public_key>
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: [admin, root, sudo]  #add required groups
    shell: /bin/bash

Create a new user with password access and bash shell environment.

#cloud-config
  ssh_pwauth: yes
  chpasswd:
    list: |
      '[username]:[password]'
    expire: false
  users:
    - default
    - name: [user-name]
      passwd: [password]
      lock_passwd: false
      sudo: ['ALL=(ALL) NOPASSWD:ALL']
      groups: [wheel, sudo, admin] #add required groups
      shell: '/bin/bash'

Install application packages like ‘apache‘, ‘php‘, ‘mysql-client‘, etc.

#cloud-config
  repo_update: true
  repo_upgrade: all

  packages:
  - [package_name]
  - apache2
  - php
  - mysql-client  
  - php-mysql
  - libapache2-mod-php
  - php-mcrypt

Install and configure a Postgres Database.
(credits: Cody  De Arkland)

#cloud-config
  packages:
  - postgresql
  runcmd:
  - |
    sudo -u postgres psql <<SQL
      CREATE DATABASE [database_name];
      CREATE USER dbuser with encrypted password '[password]';
      grant all privileges on database [database_name] to dbuser;
      \connect [database_name];
      CREATE TABLE textData (
      id        SERIAL PRIMARY KEY,
      title       TEXT,
      text        TEXT
      );
      ALTER DATABASE posts OWNER TO dbuser;
      ALTER TABLE textData OWNER TO dbuser;
    SQL
  - echo "Restarting Postgres Services"
  - [ systemctl, stop, postgresql.service ]
  - ufw allow 5432
  - echo "host    all    all       0.0.0.0/0   md5" >> /etc/postgresql/9.5/main/pg_hba.conf
  - echo "listen_addresses = '*'" >> /etc/postgresql/9.5/main/postgresql.conf
  - [ systemctl, start, postgresql.service ]

This is not the end of this series because there are a lot of topics still to be explained. Next up, how to define dependencies in your CAS blueprints. So check-in regular for new content!