Heat Orchestration Template
- By Lehbot
- Wed 01 March 2017
Im Zuge einer automatisierten Installation von RedHat OpenShift auf OpenStack wollte ich das natürlich möglichst automatisiert ausführen.
Dazu bringt OpenStack die Komponente Heat mit, mit der es möglich ist einen ganzen Stack auf einmal automatisiert auszurollen, zu ändern, zu skalieren und zu löschen.
Heat kann mittels Template, das wiederum HOT(=Heat Orchestration Template) heißt, gefüttert werden.
Die Notationssprache in diesem Template ist YAML(=YAML Ain’t Markup Language).
Das Regelwerk für YAML ist grundsätzlich wie folgt aufgebaut:
-
Einrücken über Leerzeichen bestimmt die Struktur und die Beziehung der einzelnen Elemente zueinander. Elemente die mehr eingerückt sind, sind Unterlemente des vorherigen Elements, dass nicht so weit eingerückt ist bzw. nicht so viele Leerzeichen davor hat.
-
Listenmitglieder werden über einen Bindestrich definiert, d.h. alle weiter untergeordneten Elemente, die auf der gleichen Ebene oder weiter eingerückt sind, gehören dann zu dieser Liste.
-
Zusammenhängende Daten, werden über einen Schlüssel, direkt gefolgt von einem Doppelpunkt(:), Leerzeichen und dem dazugehörigen Wert definiert. Im Prinzip handelt es sich um eine Variableninitialisierung.
-
Zusammenhängende Textblöcke werden über eine Pipe(|) gekennzeichnet, d.h. auch hier dass alle weiter untergeordneten Elemente, die auf der gleichen Ebene oder weiter eingerückt sind, zu diesem Textblock gehören.
-
Kommentare werden von einem # angeführt.
Weiterführende Informationen auf Englisch finden sich unter folgendem Link:
https://www.digitalocean.com/community/tutorials/an-introduction-to-cloud-config-scripting
Bevor wir beginnen möchte ich darauf Hinweisen einen vernünftigen Editor dafür zu benutzen, der über ein entsprechendes Highlighting verfügt.
Ich habe bisher Notepad++ benutzt, aber evtl. gibt es noch bessere. Update 08.05.2020: Ja, Visual Studio Code https://code.visualstudio.com/
Kommen wir nun zum Template. Der Aufbau ist unter dem folgenden Link beschrieben:
http://docs.openstack.org/developer/heat/template_guide/index.html
Der Grundaufbau eines Template ist hier beschrieben:
http://docs.openstack.org/developer/heat/template_guide/hot_spec.html
Ressourcentypen sind unter folgendem Link zu finden:
http://docs.openstack.org/developer/heat/template_guide/openstack.html
Die Grundstruktur sieht wie folgt aus:
heat_template_version: 2016-10-14
# Bestimmt die Version des Templates und dem entsprechenden Featureset und spiegelt bei Neuerstellung die Version des verwendeten OpenStack wieder. Allerdings kann man hier auch die Strategie fahren, dass man ein OpenStack übergreifendes Template erstellen möchte, dass mit möglichst vielen Umgebungen unterschiedlicher Versionen zusammenarbeitet.
description:
# Eine einfache Beschreibung des Templates
parameter_groups:
# Deklaration von Parameter Gruppen
parameters:
# Deklaration von Eingabeparametern, die im weiteren Verlauf des Templates verwendet werden können. Im jeweiligen Element kann dieser Wert mittels {get_param: <Variablenname> } abgefragt werden. Verschiedene Typen sind möglich: <string | number | json | comma_delimited_list | boolean> und können mit konkreten Werten vorbelegt werden.
Diese hier erstellten Werte werden bei Erstellung des Stacks in der WebGUI angezeigt und können entsprechend verändert werden. Ist kein default Wert vorhanden, so muss ein Wert bei Erstellung mitgegeben werden. Weiteres unter obigem Link.
resources:
# Hier werden die eigentlich zu erstellenden Ressourcen festgelegt. Welche Typen hier erstellt werden können ist hier zu finden: http://docs.openstack.org/developer/heat/template_guide/openstack.html
Welche Resource Types aber wirklich zur Verfügung stehen hängt a) von den Rechten des Benutzers ab und b) von der verwendeten OpenStack Version. Unter jedem Ressourcentyp steht die OpenStack Version ab wann sie verfügbar ist.
outputs:
# Hier können Ausgaben definiert werden. Beispielsweise möchte man sich ausgeben lassen, welche IP nun ein Server erhalten hat, da diese im Erstellvorgang automatisch vergeben wird. Das geht bspw. mit dem Befehl {get_attr: [<ressource>, name] } . Wobei "name" ein Attribut des Objekts ist, dass sich hinter der abgefragten Ressource befindet. Welche Attribute abgefragt werden können ist im jeweiligen "Resource Type" festgelegt. Siehe obigen Link.
conditions:
# Hier können Bedingungen definiert werden.
Das sind erst einmal genug Informationen um mit einem Template zu beginnen. Folgend sind zwei Templates gelistet, die ein Netzwerk und einen Server erstellen.
Die Templates wurden mit den Informationen aus dem folgenden PDF erstellt:
https://access.redhat.com/sites/default/files/attachments/ocp-on-osp.pdf
Voraussetzung:
- Ein bestehendes Public Netz innerhalb OpenStack mit dem Namen "floating" bzw. diese Stelle muss dann angepasst werden.
Weitere Bemerkung:
-
Ich habe hier für das Beispiel nur ein Netzwerk angelegt und den Bastion Host von dem aus OpenShift weiter installiert wird. Es fehlen hier noch weitere SecurityGroups für die Master-,Infra- und Nodeserver.
-
Alle anzupassenden Punkte sind mit "Todo:" gekennzeichnet. Der entsprechende Kommentar sollte dann auch entfernt werden.
Netzwerkerstellung:
heat_template_version: 2015-10-15 #Definition der OpenStack Version, die unterstützt werden soll.
description: "OpenShift Template for the networking component. It creates a network, subnet inside the network, gateway and security group"
parameters:
#--------------------Definition of Security Groups---------------------
secGroupBasicBastion: #Namensvergabe für den Parameter. Hierauf wird intern referenziert mit bspw. { get_param: secGroupBasicBastion }.
type: string
description: Security Group for Bastion Hosts
default: BasicBastion #Default Wert, der bei Erstellung über die WebGui im Eingabefenster angezeigt wird.
#--------------------Definition of network names----------------------
private_net_name:
type: string
description: Name of private network to be created
default: OpenShiftSharedNetwork
private_subnet_name:
type: string
description: Name of private network to be created
default: OpenShiftSharedNetworkSubnet
public_net:
type: string
description: ID or name of public network for which floating IP addresses will be allocated
default: floating #Todo: Das Public Netz muss bereits existieren bzw. im Template oder während der Erstellung geändert werden.
#--------------------Definition of network Range-----------------------
private_net_cidr:
type: string
description: Private network address (CIDR notation)
default: 172.17.0.0/16 #Todo: Netzwerkrange bei Bedarf ändern
all_net_cidr:
type: string
description: Private network address (CIDR notation)
default: 0.0.0.0/0 #Das ist der default Wert, der bei Erstellung des Stacks geändert werden kann. allerdings ist damit auch nur ein Ziel oder eine Quelle im Internet gemeint und wird primär in den Security Groups als Quelle bzw. Ziel benötigt.
resources: #Ab diesem Eintrag werden nun die tatsächlichen Objekte definiert und erstellt. Man kann nun die Parameter aus dem obigen Bereich nehmen oder Werte hartcoden.
#------------------------Creation of Network and Subnet----------------
private_net: #Ebenfalls wieder eine Namensvergabe der Ressource um darauf intern verweisen zu können bspw. { get_resource: private_net }
type: OS::Neutron::Net #Der Typ des Objektes das angelegt werden soll. Mithilfe der Dokumentation werden die gewünschten Properties definiert: OS::Neutron::Net
properties:
name: { get_param: private_net_name }
private_subnet:
type: OS::Neutron::Subnet
properties:
name: { get_param: private_subnet_name }
dns_nameservers: [192.168.17.1,192.168.17.2] #Todo: DNS Server müssen hier angepasst werden.
network_id: { get_resource: private_net }
cidr: { get_param: private_net_cidr }
#------------------------Creation of Gateway---------------------------
router: #Beschreibung des Gateway: Es wird ein Router erstellt, dessen externe Schnittstelle sich im öffentlichen Netz befindet.
type: OS::Neutron::Router
properties:
external_gateway_info:
network: { get_param: public_net }
router_interface: #Das Interface des Gateway ist ersteinmal unabhängig vom Gateway selbst. Es wird separat erstellt und an den Router und in das Subnet gehangen.
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: router }
subnet_id: { get_resource: private_subnet }
#------------------------Creation of Security Group---------------------------
secGroupBasicBastion_res: #Hier wird eine Security Group mit eingehendem SSH erstellt.
type: OS::Neutron::SecurityGroup
properties:
description: Security Group for Bastion Host
name: { get_param: secGroupBasicBastion }
rules: [{"direction": ingress, "port_range_min": 22, "port_range_max": 22, "remote_mode": remote_ip_prefix, "protocol": tcp, "remote_ip_prefix": { get_param: all_net_cidr }}]
Zweites Template zur Erstellung eines Hosts:
heat_template_version: 2015-10-15
description: "OpenShift Template for the Bastion host Component"
parameters:
#--------------------Definition of instance Name-----------------------
nodenameBastion:
type: string
description: Name of Bastion
default: Servername.alleserver.com #Todo: Servername sollte geändert werden.
#----------------------------------------------------------------------
#--------------------Definition of image and flavor sizes--------------
image:
type: string
description: Name of image to use for servers
default: "Red Hat Enterprise Linux 7.2" #das zu verwendende OS wird hier definiert.
flavor:
type: string
description: Flavor to use for servers
default: ocp.bastion #die zu verwendende Größe des Servers wird hier definiert.
#----------------------------------------------------------------------
#--------------------Definition of availability Zones------------------
availabilityZone1:
type: string
description: Availability Zone DC1
default: dc1
#----------------------------------------------------------------------
#--------------------Definition of Security Groups---------------------
secGroupBasicBastion:
type: string
description: Security Group for Bastion Hosts
default: BasicBastion
#----------------------------------------------------------------------
#--------------------Definition of Networks----------------------------
private_net_name:
type: string
description: Name of private network to be created
default: OpenShiftSharedNetwork
private_subnet_name:
type: string
description: Name of private network to be created
default: OpenShiftSharedNetworkSubnet
public_net:
type: string
description: ID or name of public network for which floating IP addresses will be allocated
default: floating
#----------------------------------------------------------------------
resources:
#--------------------Creation of Instances-----------------------------
#
ServerBastion:
type: OS::Nova::Server
properties:
name: {get_param: nodenameBastion}
image: { get_param: image }
flavor: { get_param: flavor }
key_name: OpenShiftsharedKP #Todo: Ändern !Der Private Key sollte innerhalb OpenStack vorher erstellt sein. Ich habe ihn hier hardcoded, sollte aber als Parameter auftauchen.Mehr Arbeit für Dich !
availability_zone: { get_param: availabilityZone1}
networks:
- port: { get_resource: Bastion_port } #Hier wieder das Gleiche wie beim Gateway. Interface und Serverobjekt sind voneinander getrennt.
user_data_format: RAW
user_data: #User_data ist ein sehr interessanter Teil und wird von mir in einem anderen Artikel behandelt werden. Grundsätzlich wird hier alles verarbeitet was innerhalb des OS stattfinden soll. Ein Beispiel ist unten aufgeführt.
str_replace: #Das ist eine Funktion, die im Bereich params definiert hat nach welchem Text sie im Bereich template ersetzen soll. In diesem Fall wird der Parameter $shortname vorbelegt mit dem Wert des Bastion Hostnames, ein Split über das Zeichen . durchgeführt und aus dem Ergebnis wird das erste Element genommen. Danach wird das Ergebnis im Bereich template das Wort "$shortname" ersetzen.
template: |
#!/bin/bash -ex
echo "Running boot script"
/usr/sbin/subscription-manager register --name=$shortname #Hier weitere Optionen einfügen, die für Sie passen !
/usr/sbin/subscription-manager repos --disable=*
/usr/sbin/subscription-manager repos --enable=rhel-7-server-rpms --enable=rhel-7-server-extras-rpms --enable=rhel-7-server-ose-3.3-rpms
yum install -y atomic-openshift-utils
params:
$shortname: {str_split: ['.', { get_param: nodenameBastion }, 0]}
#---------------------Instance private Network Interface---------------
Bastion_port:
type: OS::Neutron::Port
properties:
network_id: { get_param: private_net_name }
fixed_ips:
- subnet_id: { get_param: private_subnet_name }
security_groups:
- { get_param: secGroupBasicBastion}
#---------------------Instance public Network--------------------------
Bastion_public:
type: OS::Neutron::FloatingIP
properties:
floating_network: { get_param: public_net }
port_id: { get_resource: Bastion_port }
#----------------------------------------------------------------------
outputs: #Hier werden Werte entsprechend ausgegeben.
BastionName:
description: Name
value: {get_attr: [ServerBastion, name] } #Der Name des Servers wird ausgegeben. get-attr Wie geschrieben muss man sich die möglichen Attribute aus der Objekt Dokumentation holen. Für dieses Objekt OS::Nova::Server existiert das Attribut "Name".
BastionPrivateIP:
description: Private IP Address
value: {get_attr: [ServerBastion, networks, {get_param: private_net_name},0] }
BastionPublicIP:
description: Public IP Address
value: {get_attr: [Bastion_public, floating_ip_address]}
# Bastion_long:
# description: Long output of server
# value: {get_attr: [ServerBastion]}