Search code examples
configurationopenstackopenstack-heat

How to spread number of instances across availability zones in heat?


I have an instance resource along these lines:

 masters:
type: OS::Heat::ResourceGroup
properties:
  count: { get_param: num_masters }
  resource_def:
    type: heat_stack_server.yaml
    properties:
      name:
        str_replace:
          template: cluster_id-k8s_type-%index%
          params:
            cluster_id: { get_param: cluster_id }
            k8s_type: master
      cluster_env: { get_param: cluster_env }
      cluster_id:  { get_param: cluster_id }
      type:        master
      image:       { get_param: master_image }
      flavor:      { get_param: master_flavor }
      key_name:    { get_resource: keypair }
      net:         { get_resource: net }
      subnet:      { get_resource: subnet }
      secgrp:
        - { get_resource: master-secgrp }
        - { get_resource: node-secgrp }
      floating_network: { get_param: external_net }
      net_name:
        str_replace:
          template: openshift-ansible-cluster_id-net
          params:
            cluster_id: { get_param: cluster_id }
depends_on:
  - interface

It creates num_masters. Now, I want to guarantee these masters will be created in different availability zones (so that when one of them fails, the other will continue to work).

Say, I have 3 AZ and num_masters == 5. How to spread them, so that zone1 contains nodes 1 and 4, zone2 - 2 and 5, and so on?

Ansible has that loop.cycle thing where you could pass over a list of options over and over. Any ideas how to do it in OS?


Solution

  • OK, I found a solution. I see that someone ticked my question up, so I understand that there's someone else searching for a solution, so I'd better share mine.

    You rarely use (and I certainly don't) Heat in isolation from other Configuration Management frameworks. I use it alongside Ansible. So in order to spread nodes between availability zones (AZ) you may consider to prepare this spread yourself. First, I have in my Ansible vars file a list of all AZ available (sorry for the pun):

    zones:
     - 'zone1'
     - 'zone2'
    

    Alternatively, you can query Openstack for that list. When you have it, you fill it into the environment file of your stack like this:

    {% set zone_cycler = cycler( *zones ) %}
    master_availability_zones: [{% for n in range(1,master_number+1) %}"{{ zone_cycler.next() }}"{% if not loop.last %}{{','}} {% endif %}{% endfor %}]
    

    So for five hosts and two zones you'll get this:

    master_availability_zones: ["zone1","zone2","zone1","zone2","zone1"]
    

    Then you pass this list into your host resource group like this:

      master_availability_zones:
        type: comma_delimited_list
        label: Master Availability zones
        description: Availability zone mapping for masters
    
      master_nodes:
        type: OS::Heat::ResourceGroup
        properties:
          count: { get_param: master_number }
          resource_def:
            type: master_template.yaml
            properties:
              ...
              availability_zones: { get_param: master_availability_zones }
              index: "%index%"
              ...
    

    Don't forget to pass along index variable as well, you'll need it on the other side, in master_template.yaml:

      master_node:
        type: OS::Nova::Server
        properties:
          ...
          availability_zone: { get_param: [ availability_zones, { get_param: index } ] }
          ...
    

    Voila, you now have scalable procedure accomodating for arbitrary host and zone numbers.