posted

2 Comments

Windows Cloud-Init solution

 

Ten years ago the word Cloud was the buzz word in every IT conference. The Cloud promised to bring the modern IT business to a new level of opportunities. Back at that time I was an engineer with little IT experience, attracted by the big transformations ahead and wondering where is this going to end. Almost a decade later, we have three types of cloud solutions: on-premise private cloud, public cloud and the mix of both worlds called hybrid cloud. The competition between them and the increased number of business requirements, set the need for new kind of automation tools and products to bridge the gaps and offer seamless experience. With the recent announcement of VMware Cloud Services, VMware is heading strong in this direction. Behind the scenes, VMware Cloud Services is an extensible SaaS solution designed to help us operate, secure and monitor workloads across different cloud providers.

Now that we have the flexibility to choose, which workload goes where, we have to solve another common problem. We need to find out how to customize the guest instance to fit our software application(s).

Thanks to the Cloud-Init package developed by Canonical, this is an easy task for the most popular Linux and FreeBSD operating systems. However, Cloud-Init doesn’t support windows guest instances and this is a problem for all applications that require windows to run.

The good news is that a company called “Cloudbase Solutions” developed equivalent of Cloud-Init for windows. Cloudbase-init provides out of the box: user creation, password injection, static network configuration, hostname, SSH public keys and user-data scripts, such as PowerShell, Batch, Python, Cloud Config and others.

In this blog post tutorial, I will demonstrate how to prepare Azure windows image with cloudbase-init and then customize guest instance provisioned from that image. The procedure is identical for all supported cloud vendors and versions of windows. The tutorial is split in two parts, the image preparation and the guest instance customization.

There are multiple ways to create a custom Azure windows image. To keep things simple for the purpose of this demonstration, I will customize one of the windows 10 Azure marketplace images and then capture it as custom image.

Prepare Cloudbase-init Azure windows 10 image

  1. Login to the Microsoft Azure Management portal.
  2. Click Create a Resource and search for windows 10 image in the marketplace search bar.
    Azure windows 10 image

  3. Click Create and provide the required inputs to provision new windows guest instance from this image.
    Deploy Azure guest windows 10 imageNote: Make sure to request public IP address and allow RDP inbound access, since we need them to connect to the new windows 10 instance and install cloudbase-init.
  4. When the machine is up and running, login with RDP client and follow the steps below to setup cloudbase-init:
    1. Download the cloudbase-init installation binaries from https://github.com/openstack/cloudbase-init.
      cloudbase-init on GithubSupported cloudbase-init cloud providers (stable version): 

      • OpenStack (web API) 
      • OpenStack (configuration drive) 
      • Amazon EC2 
      • CloudStack 
      • OpenNebula 
      • Ubuntu MaaS
         

      The guest instance metadata is picked up by the so called cloudbase-init metadata services.  Then they exposed the data to the cloudbase-init plugins, responsible for the guest instance customization.
      For example, configure custom instance host name, network address, username, password and others. 

      Available cloudbase-init plug-ins (stable version): 

      • Setting host name (main) 
      • Creating user (main) 
      • Setting password (main) 
      • Static networking (main) 
      • Saving public keys (main) 
      • Volume expanding (main) 
      • WinRM listener (main) 
      • WinRM certificate (main) 
      • Scripts execution (main) 
      • Licensing (main) 
      • Clock synchronization (pre-networking) 
      • MTU customization (pre-metadata-discovery) 
      • User data (main) 
      • Configuring selected plugins
         

      Available cloudbase-init user-data interpretors (stable version):  

      • PEM certificate 
      • Batch 
      • PowerShell 
      • Bash 
      • Python 
      • EC2 format 
      • Cloud config 
      • Multi-part content 
      • Sysnativeness
         

      The guest instance user-data is called with different names across the different cloud providers (Azure: custom data, AWS/Openstack/Ubuntuu MaaS/CloudStack: userdata). This is custom user content exposed to the guest instance by the currently deployed and running cloud infrastructure. Its purpose is to provide additional data for the instance to customize it as much as you need, if the cloud initialization service does support this feature.

       

    2. Run the CloudbaseInitSetup_x64 installation binary and follow the on-screen instructions.
      Cloudbase-init installer
      Cloudbase-init installer
      Cloudbase-init installer
      Cloudbase-init installer
      Cloudbase-init installer
    3. Click Install and once the installation completes, configure the cloudbase-init config, before finalizing the installation.

    4. Navigate to the chosen installation path and under the conf directory, edit the file “cloudbase-init-unattend.conf”

      [DEFAULT]
      username=vmitov
      groups=Administrators
      inject_user_password=true
      first_logon_behaviour=no
      config_drive_raw_hhd=true
      config_drive_cdrom=true
      config_drive_vfat=true
      bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe
      mtools_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
      verbose=true
      debug=true
      logdir=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\log\
      logfile=cloudbase-init-unattend.log
      default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN
      logging_serial_port_settings=COM1,115200,N,8
      mtu_use_dhcp_config=true
      ntp_use_dhcp_config=true
      local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
      metadata_services=cloudbaseinit.metadata.services.azureservice.AzureService
      plugins=cloudbaseinit.plugins.windows.createuser.CreateUserPlugin,cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin,cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin,cloudbaseinit.plugins.common.userdata.UserDataPlugin
      allow_reboot=true
      stop_service_on_exit=false
      check_latest_version=false

       Expand source


      The various config options above are used by the cloudbase-init services and plugins to customize the guest instance user experience.

       

    5. Save the file and finish the cloudbase-init installation using the options below.
      Cloudbase-init installer
    6. Once the sysprep process is complete, the windows 10 machine will shut down automatically. Wait until its state in the Azure Management portal is set to Stopped.
      Azure instance state
    7. Click Capture and provide the required inputs to convert the windows 10 instance to new custom image.
      Capture Azure instance as image
    8. Note down the image name and click Create.

    Now that we have the image created, we can easily customize the guest instance based on the predefined options in the cloudbase-init config file or via the optional instance user-data. To achieve this, we just need to request new instance from that image via the Azure Management portal, the Azure API, the Azure CLI or via the VMware Cloud Assembly blueprint.

    I will use the last option as a good opportunity to show how this can be done with VMware Cloud Services. Moreover, I will create a cloud agnostic blueprint, because it will let me deploy and customizable instance in other cloud providers, as soon as I have their cloudbase-init windows image available.

Deploy and customize windows guest instance with VMware Cloud Services.

  1. Login to VMware Cloud Services and select VMware Cloud Assembly.
  2. Navigate to Infrastructure tab and setup an Azure Cloud account.
    Cloud Accounts
  3. The next step is to create Cloud Zone associated with the Cloud Account.
    Cloud ZonesNote: Add a capability tag, which will be later on used to link our new blueprint with this cloud zone.
  4. Next we need to create new Project associated with the Cloud Zone.
    Projects
  5. To configure the same image size across the different cloud vendors, we need to create a Flavor Mapping.
    Flavor Mappings
  6. Similar to the Flavor Mapping, we need to create new Image Mapping to describe the image name across the different cloud vendors.
    Image Mappings
    If you don’t see the image created in step 1, go to Cloud Accounts and re-sync all images. By default image data-collection is automatically performed every 24 hours. 
  7. Create Storage Profile to allow Cloud Assembly provisioning of Azure images based on managed disks.
    Storage Profiles

    By default Cloud Assembly will create Azure classic Availability Set, which doesn’t support images based on managed disks, so we need to set Cloud Assembly to create Azure managed Availability Set for this to work.

  8. Navigate to the Blueprints tab and create new Cloud Assembly blueprint.
    Blueprints

    YAML code:

    inputs: {}
    resources:
      Cloud_Machine_1:
        type: Cloud.Machine
        properties:
          remoteAccess:
            username: vmitov
            password: Password1234@$
            authentication: usernamePassword
          storage:
            constraints:
              - tag: 'cloudbaseinit:hard'
          image: vmitov windows 10
          flavor: small
          cloudConfig: |
            #cloud-config
            write_files:
              encoding: b64
              content: NDI=
              path: C:\test
              permissions: '0644'
            set_hostname: demoname
          constraints:
            - tag: 'cloudbaseinit:hard'
          __computeConfigContentPreserveRawValue: true

     Expand source

    Most of the YAML properties are self-explanatory, so I will comment just the few that are more specific to the topic.
    The remoteAccess properties will set the guest instance metadata with the values provided for username, password and authentication. Then this will be picked-up by the cloudbase-init metadata services and the guest OS will be configured via the Setting Password cloudbase-init plug-in.
    The cloudConfig property will set  the userdata and expose it to the guest instance during provisioning. In this case the first line indicates that the script below is Cloud-Init YAML code and cloudbase-init will use its cloud-init plug-in to execute it.
    The _cloudConfigContentPreserveRawValue  is an important one, since it tells Cloud Assembly to keep the raw user-data provided in the cloudConfig property. If we don’t set this property to true, then Cloud Assembly will convert some of the other properties to Cloud-Init YAML code, for example it will create the Cloud-Init YAML code needed to set the remote access authentication type, username and password.
    The storage constraint, tells Cloud Assembly that we want to use the custom Storage profile that requires Azure managed Availability Set.

     

  9. Click Deploy to provision new Azure windows 10 machine, which will be customized by the configured CloudConfig script.
    Deployments
  10. Login to the new instance with RDP client and the credentials specified in the blueprint and verify that the CloudConfig script was successfully executed.
    1. Check the custom file created in C:\test
      CloudConfig - write file result
    2. Check the customized machine hostname
      CloudConfig - change hostname result

 

I hope you found the blog post useful!

If you want to learn more, check out the VMware Cloud Services and Cloudbase-Init documentation pages and stay tuned for more on VMware Blogs!