(WS12-01) Cloud/Dokumentation

Aus Verteilte Systeme - Wiki
< (WS12-01) Cloud
Version vom 1. März 2013, 13:06 Uhr von Kmuel002 (Diskussion | Beiträge) (Apache Libcloud)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Einleitung

Die folgende Arbeit entstand im Rahmen eines Masterprojekts des Labors für verteilte Systeme und Anwendungen der Hochschule RheinMain. Sie evaluiert die Implementierung einer Cloud-Infrastruktur mit OpenStack.

Das erste Ziel des Projekts bestand darin, die Durchführbarkeit der hochschul-internen Praktika mit virtuellen Maschinen zu prüfen. Jeder Student sollte auf seiner eigenen virtuellen Maschine Datenbank- oder Applikationsserver installieren und konfigurieren und dort seine Aufgaben bearbeiten können. Auf diese VM könnte der Student sich mit einem Thin-Client oder seinem eigenen Rechner einloggen. Dies sollte zur Verringerung der Anschaffungs-, Installations- und Wartungskosten für physische Rechner innerhalb der Hochschule beitragen.

Das zweite Ziel sollte dann das Monitoring und die Steuerung dieser Cloud-Infrastruktur sein. Zu diesem Zweck sollte die Monitoring-Software Hyperic und die Cloud-Compute-Abstrahierungs-API Libcloud verwendet werden. Weiterhin wurden mit Deltacloud und jCloud weitere APIs für diesen Zweck evaluiert.

OpenStack ist ein Beispiel für eine Infrastructure as a Service-Plattform und wird, wie hier, meist für firmen- oder einrichtungsinterne Cloud-Umgebungen eingesetzt.

OpenStack - Ein Überblick

Der folgende Abschnitt verschafft einen Überblick über OpenStack. Dazu wird ein Einblick in den Aufbau und das Zusammenspiel der einzelnen Komponenten (Dienste) gegeben. Zuerst soll jedoch eine Aufstellung der Gründe gegeben werden, die für OpenStack als verwendete Architektur sprechen.

Gründe für OpenStack

OpenStack ist ein OpenSource-Projekt mit vielen namenhaften Unterstützern. Neben der NASA, IBM, Dell, Hewlett-Packard, AMD und Citrix Systems, den Betreibern des Xen-Hypervisors, sind Software-Unternehmen wie Canoncial, Red Hat und SUSE Linux, die Betreiber dreier großer Linux-Distributionen, die Hauptsponsoren des Projekts. Dies spricht erstens für eine rege Entwicklung und zweitens für eine aktive Community. Viele Blogs und Zeitschriften berichten aktuell (Stand 2012/2013) von OpenStack.

Community und Interesse der Medien deuten auf eine gute Dokumentation des Projekts hin. In der Tat finden sich auf der Homepage des Projekts Installations- und Wartungsanleitungen für eine Cloud-Infrastruktur mit OpenStack. Auch beschreiben viele Blogger ihre ersten Erfahrungen mit OpenStack, was einen reichen Fundus für die Anfänge des Projekts liefert.

Das Projekt scheint schon recht weit fortgeschritten und in einem einsatzbereiten Zustand zu sein. OpenStack liegt mittlerweile in der siebten Version vor. Das aktuelle Release trägt den Codenamen Grizzly. Im Zuge des Projekts wurde jedoch mit der sechsten Version, Folsom, gearbeitet.

Grundlegende Architektur von OpenStack

OpenStack gliedert sich in verschiedene Dienste. Diese werden im anschließenden Abschnitt beschrieben. Im Laufe des Projekts wurden verschiedene Verteilungen der Dienste auf den drei zur Verfügung stehenden Servern getestet. Diese Konfigurationen werden im Anschluss betrachtet und abgewogen.

Vorstellung der Dienste

OpenStack Identity Service (Keystone)

ist der Nutzer- und Rechteverwaltungsdienst von OpenStack. Keystone kann neben Datenbanken auch ein (möglicherweise schon bestehendes) LDAP-System (Lightweight Directory Access Protocol) zur Benutzerverwaltung verwenden. Dies wäre für den Hochschulbetrieb optimal, da hier die Nutzerdaten ohnehin schon darüber verwaltet werden. Der Dienst publiziert seine Daten in Form von komplexen JSON-Strings, die vom Empfänger selbst interpretiert werden müssen.

OpenStack Image Service (Glance)

ist für das Einlesen und Verwalten von System-Images innerhalb der OpenStack-Architektur zuständig.

OpenStack Object Storage (Swift)

ist für die Verwaltung von virtuellen Speichermedien und deren Zuordnung zu Instanzen zuständig. Ein Speicherblock muss dabei nicht zwingend auf einem physischen Device vorliegen, sondern kann auch über mehrere Rechner im Netz verteilt sein.

OpenStack Network Service (Nova)

dient zur Konfiguration der Netzwerke . Mit nova-network kann nur ein virtuelles Netzwerk für die VMs erzeugt werden, jedoch ist es möglich, mit Verwendung von Quantum, einem alternativen Netzwerkdienst, für jeden Kunden des Providers mehrere Netze einzurichten und gezielter in die Netzwerkumgebung einzugreifen.

OpenStack Compute Service (Nova)

ist der wichtigste Bestandteil der Umgebung. Compute erstellt, verwaltet und beendet virtuelle Maschinen und sorgt im Optimalfall auch für (Live-)Migration. Der Dienst ist somit der Vermittler zwischen dem Hypervisor des Systems (Standard für OpenStack ist KVM) und den anderen Diensten.

OpenStack Dashboard (Horizon)

ist eine optionale, aber nützliche Komponente von OpenStack. Horizon bietet eine Web-Oberfläche zur Verwaltung und Administration von OpenStack. Zum Funktionsumfang gehört u.a. das Erzeugen von Images und VMs, Anlegen und Verwalten von Volumes und Verwaltung der Flavors.

Zum Betrieb der Nova-Dienste müssen noch weitere Hilfsdienste installiert werden. Will ein anderer Dienst mit einem Nova-Dienst kommunizieren, ist die Anlaufstelle immer der Nova-API-Dienst. Dieser bietet eine REST-Schnittstelle an. Von dem API-Dienst wird die Anfrage entgegen genommen und über einen Message-Queue-Dienst an den entsprechenden Nova-Dienst weitergereicht. Als Message-Queue-Dienst, wird in diesem Projekt Rabbit-MQ benutzt. Die Nova-Dienste tauschen sich grundsätzlich untereinander über den MQ-Dienst aus. Dies bedeutet insbesondere, dass sich die Instanzen, auch gleichartiger, Nova-Dienste automatisch finden.

Nodes

Bei OpenStack werden die Dienste üblicherweise auf verschiedenen Typen von Nodes zusammengefasst. In der Praxis können Nodes verschiedener Typen auf einer physischen Maschine liegen, im Idealfall stellt jeder Node jedoch eine dedizierte physische Maschine dar. Es gibt drei Haupttypen bei den Nodes.

Controller-Node

beheimatet alle Dienste, die zur Verwaltung der OpenStack-Infrastruktur notwendig sind (Keystone, Glance, Nova-Api)

Network-Node

verwaltet das (private) Netzwerk zwischen den laufenden Instanzen und die zugeteilten öffentlichen IP-Adressen

Compute-Node

dient als Ausführungsort für die Instanzen.

Weiterhin kann z.B. die Datenbank, in der alle Dienste ihre Daten ablegen auf einem eigenen Node laufen. Auch der Speicherplatz für die verfügbaren VM-Images kann über einen Netzwerkspeicher realisiert werden.

Zuordnung der OpenStack-Entitäten in das CIMI-Modell

CIMI (Cloud Infrastructure Management Interface) möchte ein Standard sein, der Objekte des Cloud-Computing-Umfelds in der Notation des CIM (Common Information Model) beschreibt. Jedoch hält sich OpenStack nicht an die vorgeschlagene Notation. Die folgende Tabelle stellt ein paar Begriffe beider Notationen gegenüber:

OpenStack CIMI Beschreibung
Instance Machine virtuelle Maschine
Flavor MachineConfiguration Hardwareausstattung einer VM
Image MachineTemplate Image oder Snapshot
Memory RAM für eine VM
Disk Festplatte der VM
Volume Volume weitere Laufwerke

CIMI spezifiziert zudem noch eine einheitliche REST-Schnittstelle, die zum Abfragen und Steuern genutzt werden könnte. Als einzige Abstrahierungsbibliothek implementiert Deltacloud diese Schnittstelle.

Aufbau der Infrastruktur

Geplante Verteilung der Dienste
Aktuelle Verteilung der Dienste

Erster Entwurf

Ein erster Entwurf des Projekts bestand aus einer Verteilung der Dienste auf den drei zur Verfügung stehenden Rechnern (vergleiche dazu "Geplante Verteilung der Dienste"). Dazu sollten zwei der Server (die leistungsschwächeren openstack1 und openstack2) als Controller Nodes dienen, openstack0 hingegen als Compute Node. Die Controller Nodes sollten über eine virtuelle IP-Adresse erreichbar sein. Eine Verteilung der Anfragen an die tatsächlichen Endpunkte der Dienste auf den unterschiedlichen Rechnern sollte dann über den Dienst HAProxy erfolgen. Dies sollte im Fall der Controller Nodes eine erhöhte Ausfallsicherheit gewähren.

Hochverfügbarkeit und Loadbalancing

Die nachfolgende Beschreibung der Konfiguration der Dienste Keepalived und HAProxy bezieht sich auf einen im endgüligen Projekt nicht mehr verfolgten Ansatz, zwei redundante Controller-Nodes vorzuhalten.

Keepalived

Mittels Keepalived wird eine virtuelle IP-Adresse erzeugt. Diese IP-Adresse ist immer nur auf einem der beteiligten Servern aktiv. Fällt der Server mit der aktiven IP-Adresse aus, übernimmt ein anderer Server die IP-Adresse automatisch. In der Konfiguration im Anhang werden zwei Server, openstack1 und openstack2 konfiguriert. Openstack1 erhält eine höhere Priorität, da die Datenbank im Master-Slave Replikationsbetrieb läuft, und dort der Master-Server läuft.

HAProxy

HAProxy (High-Availability-Proxy) verteilt die Anfragen auf einen Dienst, der auf mehreren Rechnern laufen kann. Dazu hält HAProxy in Kombination mit Keepalived einen Endpunkt pro OpenStack-Dienst vor. Zur Einrichtung von HAProxy soll hier auf den Anhang Anhang verwiesen werden.

Probleme

Aufgrund des ständigen Ausfalls des Servers openstack2 wurde der beschriebene Ansatz nach langer Arbeit verworfen und eine einfachere Architektur implementiert (Abbildung "Aktuelle Verteilung der Dienste"). Diese sah einen zentralen Node mit Controller- und Compute-Diensten vor und einen weiteren Compute Node.

Tatsächliche Implementierung

Durch die Hochschule standen dem Projekt drei Server zur Verfügung. Auf diesen musste zunächst ein geeignetes Betriebssystem installiert werden. Offiziell empfehlen die OpenStack-Entwickler Ubuntu 12.04 als erste Wahl, da sich die für OpenStack erforderlichen Pakete bereits in den Repositories der Distribution befinden.

Grundlegende Server-Einrichtung

Proxy-Einstellungen

Um den Proxy der Hochschule nutzen zu können, muss folgende Zeile am Ende der Datei /etc/bash.bashrc angefügt werden:

export http_proxy=http://proxy.cs.hs-rm.de:8080

Danach wird die Datei /etc/apt/apt.conf mit folgendem Inhalt angelegt:

Acquire::http::Proxy "http://proxy.cs.hs-rm.de:8080";

PostgreSQL

Damit man per TCP/IP auf die Datenbank zugreifen kann, muss für den Benutzer postgres ein Passwort gesetzt werden:

sudo -u postgres psql
\password postgres
\q

OpenStack-Repository

Um die neuste Version von Folsom nutzen zu können, muss jedoch zuerst noch das von Canonical betreute Repository frei geschaltet werden:

# Installieren des Schluesselrings
# Dieser dient zum Verifizieren der Signaturen der Pakete

apt-get install ubuntu-cloud-keyring

# Paketquelle fuer Folsom (aktuelle OS-Version) in die 
# Datei /etc/apt/sources.list.d/folsom.listeintragen:

deb http://ubuntu-cloud.archive.canonical.com/ubuntu precise-updates/folsom main

# Aktualisieren der Paketquellen und installierte auf den neuesten Stand bringen

apt-get update
apt-get upgrade

Die eigentliche Installation erfolgt dann über die Paketverwaltung der Distribution. Die Konfigurationsdateien der Dienste werden jeweils in einem eigenen Verzeichnis in /etc abgelegt.

Als erstes soll gezeigt werden, wie der OpenStack Identity Service, also Keystone zu installieren und konfigurieren ist.

Konzepte

Bevor auf die Konfiguration der einzelnen Dienste eingegangen wird, werden noch ein paar der grundlegenden Konfigurationskonzepte von OpenStack erläutert.

Zugriffsrechte

Für jeden OpenStack-Dienst können Zugriffsrechte konfiguriert werden. Dazu existiert eine Datei policy.json im jeweiligen Konfigurationsverzeichnis. Die Syntax folgt der JSON-Notation. Es gibt je nach Dienst eine gewissen Menge an Rechten, denen Benutzer oder Gruppen zugeordnet werden können.

Pipelines

Viele Dienste bringen so genannte Pipelines mit. Pipelines sind in einer jeweils separaten Konfigurationsdatei abgelegt. Eine Pipeline besteht aus einer Verkettung von Factories und Filtern. Factories und Filter werden zusammen mit Pipelines in der gleichen Konfigurationsdatei festgelegt. Factories und Filter verweisen jeweils auf Python-Klassen. Bei einigen Diensten kann zwischen verschiedenen vorkonfigurierten Pipelines gewählt werden.

Authorisierung

Jedem Dienst ist ein eigener Benutzer zugeordnet. Der Tenant ist für jeden Dienst „Service“. Jedem Dienst müssen die eigenen Zugangsdaten per Konfigurationsdatei mitgeteilt werden.

Keystone

# Keystone-Paket und falls nicht schon vorhanden, Python-Anbindung an PostgreSQL
apt-get install python-psycopg2 keystone

# Datenbank-User und Datenbank fuer PostgreSQL anlegen
createuser -h openstack1 -U postgres -W -DRSP keystone
createdb -h openstack1 -U postgres -O keystone keystone

Nach der Installation muss die Konfigurationsdatei /etc/keystone/keystone.conf angepasst werden.

Die wichtigsten Einstellungen sind das so genannte Admin Token und die Datenbankverbindung:

[DEFAULT]
admin_token = ADMIN31415926

[sql]
connection = postgresql://keystone:keystone@10.18.48.145/keystone

Standardmäßig hört der Dienst auf allen verfügbaren Interfaces und IP-Adressen auf Verbindungen. Dies lässt sich mittels folgender Anweisung auf die gewünschte IP-Adresse beschränken:

bind_host = 10.18.48.142

Während der ersten Installation und Konfiguration kann es auch nützlich sein, mehr Meldungen in den Log-Dateien zu erhalten. Dazu können die Einstellungen verbose und debug aktiviert werden:

verbose = True
debug = True

Statt die Benutzer in einer eigenen Datenbank zu verwalten, können auch andere Dienste wie LDAP verwendet werden. Diese werden ebenfalls in der Keystone-Konfiguration eingerichtet. Da für die Verwendung von LDAP allerdings weitergehende Veränderungen an der LDAP-Struktur des Fachbereichs nötig gewesen wären, wurde diese Option nicht weiter verfolgt.

Glance

Glance besteht aus zwei Komponenten, Glance-API und Glance-Registry. Beide Komponenten haben ihre eigenen Konfigurationsdateien in /etc/glance, wobei jede Komponente über zwei Konfigurationsdateien verfügt.

In glance-api.conf muss, wie schon bei Keystone, die Datenbankverbindung eingetragen werden. Die Optionen für ausführlichere Fehlermeldungen und Logging sind ebenfalls vorhanden. Die verwendete Message-Queue ist gegebenenfalls zu konfigurieren, da Glance über die Message-Queue mit den Nova-Diensten kommuniziert. Die Standardvorgaben in der Konfigurationsdatei passten bereits zu den Standardeinstellungen von RabbitMQ, daher musste an der Message-Queue-Konfiguration nichts geändert werden.

Die Einstellung flavor wählt eine der bereits in den Konzepten erwähnten Pipelines aus. Der Wert keystone wählt die Pipeline mit der grundlegenden Keystone-Authentifizierung. Weitere Pipelines ermöglichen unter Anderem die Verwendung von weiteren Glance-Funktionen wie Caching und Cache-Management.

sql_connection = postgresql://glance:glance@10.18.48.142/glance
bind_host = 10.18.48.142
config_file = /etc/glance/glance-api-paste.ini
flavor = keystone

In glance-api-paste.ini muss der Zugang zu Keystone konfiguriert werden. Weiterhin kann man hier die bereits erwähnten Pipelines sehen und bei bedarf umkonfigurieren.

auth_host = 10.18.48.142
auth_port = 35357
auth_protocol = http
admin_tenant_name = service
admin_user = glance
admin_password = glance

Die ersten drei Einstellungen geben IP-Adresse, Port und Protokoll von Keystone an. Die letzten drei Einstellungen geben die Anmeldedaten für Glance an. Tenant und Benutzer für Glance wurden bei der Konfiguration von Keystone angelegt.

In glance-registry.conf muss nur die Datenbankverbindung und die gewünschte Pipeline gewählt werden. Wie bereits bei den anderen Diensten kann wieder die IP-Adresse, Loggingverhalten, etc. vorgegeben werden.

sql_connection = postgresql://glance:glance@10.18.48.142/glance
flavor = keystone


glance-registry-paste.ini wird analog zu glance-api-paste.ini konfiguriert:

auth_host = 10.18.48.142
auth_port = 35357
auth_protocol = http
admin_tenant_name = service
admin_user = glance
admin_password = glance

Nachdem alle Konfigurationsdateien bearbeitet sind, müssen beide Glance-Dienste neu gestartet werden:

service glance-api restart
service glance-registry restart

Cinder

Die Konfiguration von Cinder wird in zwei Konfigurationsdateien vorgenommen: cinder.conf und api-paste.ini. Beide Dateien liegen, wie erwartet, in /etc/cinder.

Die obligatorische Datenbankverbindung wird in cinder.conf eingetragen. Zusätzlich müssen dort noch die Einstellungen state_path und volumes_dir vorgenommen werden.

Das vollständige Listing findet sich im Anhang.

In api-paste.conf muss, wie schon zuvor bei den anderen Diensten, der Zugang zu Keystone konfiguriert werden. Das Listing befindet sich im Anhang.

Nova

Obwohl jeder Dienst in Nova prinzipiell mit einer eigenen Konfigurationsdatei gestartet werden kann, teilen sich alle Dienste eine einzige Konfigurationsdatei, nova.conf.

Die endgültige Fassung der Konfigurationsdatei weicht so stark von der Datei im Auslieferungszustand ab, dass es nicht sinnvoll ist, die einzelnen Einstellungen aufzuzählen. Die vollständige Datei befindet sich im Anhang.

Konfiguriert werden die Authentifizierung, die Verbindung zu Glance, welcher Hypervisor verwendet wird, der VNC-Proxy, Netzwerkeinstellungen, die Volume-API und die Scheduler.

Die Beschreibung der einzelnen Konfigurationsvariablen befindet sich in der Dokumentation von OpenStack.

Fazit

Die Installation von OpenStack und die Konfiguration der drei Server war im Endeffekt schwieriger, als die Zeitschriftenberichte und Blogger es hätten vermuten lassen. Dies lag zum Einen daran, dass die Konfiguration eines Systems, das in eine bestehende Umgebung hinein gefügt und produktiv genutzt werden soll, komplizierter und aufwändiger ist, als die Einrichtung eines Spiel-Systems "um mal eben die Funktionalität zu testen" und zum Zweiten, weil die genutzte Dokumentation teilweise veraltet war, beziehungsweise unvollständig. Nach einem Problem zu suchen endete meist auf der Bugtracker-Seite von OpenStack, ohne jedoch die Lösung zu nennen.

Erster Anwendungsfall - Praktikumsbetrieb mit virtuellen Maschinen

Ziele

Im ersten Anwendungsfall des Projekts sollte die Durchführung von Praktikumsveranstaltungen mit virtuellen Maschinen in der Hochschule evaluiert werden. Die Idee ist, dass es pro Praktikum für jeden Studenten eine eigene virtuelle Maschine gibt, auf der das Praktikum durchgeführt wird.

Umsetzung

Für die Umsetzung wurde ein aktuelles Ubuntu Cloud Image (http://cloud-images.ubuntu.com/) als Basis gewählt. Diese sind bereits so vorkonfiguriert, dass sie von OpenStack ein SSH-Schlüsselpaar und die Netzwerkkonfiguration holen, ein Anmelden per Passwort ist nicht vorgesehen.

Nachdem ein Ubuntu Cloud Image als virtuelle Maschine gestartet wurde, kann man sich mit Benutzername ubuntu und dem zuvor erzeugten SSH-Schlüssel anmelden.

Zuerst wurde die Konfiguration der VM an die Bedürfnisse der Hochschul-Infrastruktur angepasst. Dazu gehörte unter Anderem das Eintragen des Proxy-Servers. Weiterhin wurde der Hyperic-Agent installiert und konfiguriert (siehe zweiter Anwendungsfall).

Nach Abschluss der Konfiguration wurde ein Snapshot der VM erzeugt. Dieser Snapshot kann, genau wie ein Image, als Basis zum Starten weiterer virtueller Maschinen verwendet werden.

Ergebnisse

Es gibt zwei Ansätze für die Verwendung von OpenStack:

Im ersten Ansatz verwalten die Studenten ihre virtuellen Maschinen selbst. Dazu kann die Web-Oberfläche von OpenStack (Horizon) verwendet werden. Den Studenten sollten dann die geeigneten Images bzw. Snapshots bereitgestellt werden. Weiterhin wären die Benutzerberechtigungen von OpenStack zu prüfen und ggf. anzupassen, damit den Studenten nur der benötigte Funktionsumfang zur Verfügung steht.

Der Vorteil dieser Lösung wäre ein verhältnismäßig geringer Aufwand für Laboringenieure. Die Voraussetzung für diesen Ansatz ist jedoch, dass die LDAP-Anbindung in Keystone konfiguriert wird und damit verbunden die Anpassungen an der LDAP-Datenbank. Keystone kann zur Authentifizierung entweder eine eigene Datenbank oder LDAP verwenden. Eine Kombination aus Datenbank und LDAP ist nicht vorgesehen. Daher muss, falls LDAP verwendet wird, auch für jeden der OpenStack-Dienste ein eigener Nutzer in LDAP hinterlegt werden. Zusätzlich müssen jedem Nutzer eine oder mehrere Rollen, sowie Tenants in LDAP zugeordnet werden. Weiterhin müssen die Berechtigungen in OpenStack überprüft und gegebenenfalls angepasst werden. Der größte Nachteil dieser Lösung ist, dass Studenten sich mit einer weiteren (komplexen) Web-Anwendung innerhalb der Hochschul-Infrastruktur auseinandersetzen und diese bedienen können müssen.

Im zweiten Ansatz verwalten ausschließlich die Laboringenieure OpenStack über die Web-Oberfläche. Wie bereits im ersten Ansatz müssen Images angelegt und geeignete konfigurierte Snapshots erzeugt werden. Zusätzlich müssen die virtuellen Maschinen der Studenten gestartet und die Zugangsdaten zugeordnet werden. OpenStack Dashboard ermöglicht zwar das Starten vieler identischer virtuellen Maschinen aus einem gegebenen Image heraus, kann dabei allerdings nur ein einziges Schlüsselpaar zuordnen. Daraus folgt, dass entweder alle Studenten das gleiche Schlüsselpaar verwenden müssten oder manuell, bzw. mit selbst geschriebenen Skripten, virtuelle Maschinen gestartet werden. Zusätzlich muss ein Weg gefunden werden, jedem Studenten die Zugangsdaten, also SSH-Schlüsselpaar sowie IP-Adresse bzw. Hostname seiner zugeordneten VM, zukommen zu lassen. Dies kann über eine eigene Web-Anwendung oder durch Integration in ein bestehendes System (z.B. StudIP oder AoR) erfolgen.

Alternativ zu Schlüsselpaaren kann OpenStack auch ein zufälliges „Admin“-Passwort erzeugen und beim Start an die VM übergeben. Diese Funktionalität wird von den Ubuntu Cloud Images allerdings nicht unterstützt. Das Problem, die Zugangsdaten den Studenten zuzuordnen und zukommen zu lassen, besteht auch bei dieser Lösung.

Unabhängig vom gewählten Ansatz gibt es noch ein weiteres Problem. Im aktuellen OpenStack-Relase Folsom unterstützt OpenStack Quotas (Anzahl virtueller CPUs, RAM, etc.) nur pro Tenant, d.h. wenn eine Lehrveranstaltung als Tenant umgesetzt wird, würden sich alle Studenten die gleiche Quota teilen. Dieser Mangel wird vermutlich in einem der nächsten OpenStack-Releases behoben.

Zweiter Anwendungsfall - Monitoring der Cloud-Infrastruktur

MAPE-K-Loop

Nach dem Einrichten der Cloud-Infrastruktur soll im zweiten Schritt diese Umgebung überwacht werden. Ziel ist es, aus gemessenen Daten Aktionen abzuleiten und so zum Beispiel bei Bedarf neue Instanzen zu starten, zu stoppen oder zu migrieren.

Angedacht war, auch im Hinblick auf die Arbeiten im VS-Labor, die Orientierung am MAPE-K-Loop:

  • Monitor: über interne und externe Sensoren an der zu managenden Ressource (in diesem Projekt eine VM) Leistungsdaten überwachen
  • Analyze: die anfallenden Daten analysieren
  • Plan: mit Hilfe der in der Analyse gewonnenen Erkenntnisse eine Vorgehensweise zum Eingriff in die Ressource zurechtlegen
  • Eexcute: Eingriff in die überwachte Ressource über einen Effektor
  • Knowledge: gewonnene Erkenntnisse in einer Wissensbasis ablegen, damit diese bei zukünftigen Planungsvorgängen berücksichtigt werden können

Eingesetzte Werkzeuge

Hyperic

Für dieses Projekt wurde Hyperic (http://http://www.hyperic.com/) als Monitoring-Werkzeug ausgewählt. Zum Einsatz kam die OpenSource-Variante. Eine kommerzielle Variante wird von VMware (http://www.vmware.com/) unter dem Namen vFabric Hyperic (https://my.vmware.com/web/vmware/evalcenter?p=vfabric-hyperic) vertrieben.

Hyperic besteht aus zwei Software-Komponenten: Server und Agent.

Der Hyperic-Server wird auf einem beliebigen Rechner installiert. Im Falle dieses Projekts fiel die Entscheidung auf den Controller-Node. Hauptkomponente des Servers ist der integrierte Anwendungsserver und die darauf laufende Weboberfläche. Implementiert ist der Server in Java. Als Anwendungsserver dient Tomcat. Theoretisch können als Storage-Backend verschiedene separat zu installierende Datenbanksysteme dienen. Unterstützt werden Oracle-DB, MySQL und PostgreSQL. Mitgeliefert wird zudem eine ältere Version von PostgreSQL, die zusätzlich zu eventuell bereits vorhandenen Versionen läuft, falls sie als Backend benutzt wird. Empfohlen wird vom Hyperic-Entwickler der Einsatz von PostgreSQL. Zudem wird in der nächsten Version von Hyperic nur noch PostgreSQL als Storage-Backend unterstützt. In der Praxis kam nur der Einsatz der bei Hyperic mitgelieferten PostgreSQL-Datenbank in Frage, da sich Hyperic zwar mit der auf dem Controller-Node vorhandenen PostgreSQL-Version 9.1 installieren ließ, dann aber im Betrieb SQL-Exceptions geworfen wurden. Nach einer Recherche im Herstellerforum kam heraus, dass die eingesetzte Hyperic-Version inkompatibel mit PostgreSQL ab Version 9 ist.

Um Daten der Instanzen zu erheben und diese zur Analyse an den Server zu schicken, muss auf jeder Instanz ein Hyperic-Agent installiert werden. Der Agent ist wie der Server in Java geschrieben und läuft als Daemon im Hintergrund. Er nimmt Kontakt zum anzugebenden Server auf und liefert in konfigurierbaren Intervallen Daten an diesen.

Hyperic unterstützt viele gebräuchliche Programme in Form von Plug-Ins. Wird der Agent gestartet wird ein Auto-Discovery dieser Programme durchgeführt. Man muss dazu nichts konfigurieren und der Agent liest die Daten automatisch aus, z.B. aus Log-Dateien oder Programmschnittstellen, und liefert die Daten an den Server.

Der Server listet neu im Netzwerk gefundene Agenten automatisch auf. Anschließend müssen sie von einem Administrator manuell in das Inventar aufgenommen werden. Erst wenn Instanzen mit installiertem Agenten im Inventar sind, lassen sich Leistungsdaten und ihre Historie betrachten.

Für unterstützte Leistungsdaten wie CPU-Load oder Memory-Load des Systems, bzw. die Leistungsdaten der durch Plug-Ins unterstützten Anwendungen, lassen sich Alarme konfigurieren, die wiederum Events auslösen können. Ein Alarm kann z.B. ausgelöst werden, wenn für eine bestimmte Zeit ein Grenzwert überschritten wird.

Als Event lassen sich in der OpenSource-Variante von Hyperic leider nur das Anzeigen innerhalb der Weboberfläche und das Verschicken von E-Mails konfigurieren. Das Ausführen von Skripten ist der kommerziellen Version vorbehalten. So ist die angedachte Integration von Libcloud benutzenden Skripten nicht möglich. Allerdings bietet Hyperic eine REST-Schnittstelle, die dann regelmäßig von einem externen Programm abgefragt werden muss.

Will man Hyperic in einer Cloud-Umgebung einsetzen empfiehlt es sich, den Agenten schon auf einem Image einzurichten, so dass auf neuen Instanzen automatisch der Agent läuft.

Eine ausführliche Anleitung zum Einrichten von Hyperic befindet sich im Anhang.

Apache Libcloud

Apache Libcloud ist eine in Python geschriebene Bibliothek, welche die APIs verschiedener Cloud-Provider abstrahiert.

Die aktuelle Version teilt die Funktionalität in vier Bereiche auf:

  • Cloud-Compute: Abstrahiert Funktionen eines Cloud-Servers (Beispiele: Amazon EC2, Rackspace CloudServers, Openstack)
  • Cloud-Storage: Abstrahiert Funktionen eines Cloud-Speichers (Beispiele: Amazon S3, Rackspace CloudFiles)
  • Load-Balancers-as-a-Service: steuert Nodes, die als Load-Balancer eingesetzt werden
  • DNS-as-a-Service: erlaubt die Steuerung der DNS-Services einiger Provider

Bezeichnungen (Entitäten)

  • Node bezeichnet einen virtuellen Server (OpenStack: instance)
  • NodeSize bezeichnet eine Hardwarekonfiguration (OpenStack: flavor)
  • NodeImage bezeichnet ein OS-Image (Openstack: image)
  • NodeLocation bezeichnet die physikalische Location (Openstack: tenant)
  • NodeState bezeichnet den Status einer Node (running, rebooting, terminated, pending und unknown)

Funktionen (API)

  • list_nodes() liefert alle Nodes
  • list_images() liefert alle verfügbaren Images
  • list_sizes() liefert alle verfügbaren Sizes
  • list_locations() liefert alle physikalischen Locations
  • create_node(name, size, image) erstellt einen neuen Node
  • deploy_node(name, size, image, deploy) wie create_node, allerdings kann ein Deployment-Skript übergeben werden
  • reboot_node(node) startet eine Node neu
  • destroy_node(node) löscht eine Node

Im Zuge des Projekts soll Libcloud zur Abstrahierung der nativen OpenStack-Compute-Funktionen verwendet werden, um eine möglichst hohe Providerunabhängigkeit zu gewährleisten. Nach Evaluation der Funktionalität muss jedoch gesagt werden, dass wichtige Funktionen nicht in der Standard-API von Libcloud enthalten sind. So können Nodes nicht mehr verändert (keine Änderung der Hardwarekonfiguration) und gestoppt werden, lediglich das Löschen von Nodes ist möglich.

Will man Funktionen wie resize (Ändern der Hardwarekonfiguration, OpenStack: Flavor) oder share_ip (Zuteilen einer IP-Adresse an eine Node, OpenStack: Floating IP) verwenden, muss man auf die sogenannten ex_-Funktionen zurückgreifen. Diese Funktionen sind jedoch nur im Driver des entsprechenden Cloud-Providers (z.B. OpenStack) implementiert und damit providerabhängig.

Genau wie ex_-Funktionen gibt es auch ex_-Parameter, die dann zum Zug kommen, wenn für den Aufruf einer Funktion providerabhängige Parameter benötigt werden (z.B. Verbindungsaufbau bei OpenStack). Somit kann von einer grundsätzlichen Providerunabhängigkeit mit Hilfe von Libcloud nicht gesprochen werden, da nur der kleinste gemeinsame Nenner aller Cloud-Provider in der Standard-API unterstützt wird.

Prinzipielle Durchführung des Monitorings mit Hyperic und Libcloud

Wie schon in der Einleitung zu Hyperic erwähnt, lassen sich in der Community-Version zwar Alarme definieren, die auch zuverlässig ausgelöst werden, jedoch ist es nicht möglich, auf diese mit benutzerdefinierten Befehlen oder gar ganzen Skripten zu reagieren. Abhilfe verschafft hier die ebenfalls erhältliche API von Hyperic. Über diese können alle Funktionen, die die Monitoring-Software bietet ausgeführt werden. Sie kapselt die Requests an die vom Hyperic-Server bereitgestellte REST-Schnittstelle. Über dies hinaus können so auch Alarme definiert und auf diese reagiert werden. Statt erst Alarme zu definieren, besteht auch direkt die Möglichkeit, auf die zugrunde liegenden Messwerte zuzugreifen.

HQApi api = new HQApi("10.18.48.142", 7080, false, "hqadmin", "hqadmin");
AlertApi alertApi = api.getAlertApi();
ResourceApi resourceApi = api.getResourceApi();
MetricApi metricApi = api.getMetricApi();

Zugriff auf die Funktionalität gewährt die Klasse HQApi. Zur Initialisierung vgl. untenstehenden Code. Sie stellt für jeden Funktionsbereich der Monitoring-Anwendung eine eigene Sub-Api bereit.

So lassen sich über die AlertApi Alarme abfragen oder neu definieren, mit der MetricsApi auf Messdaten zugreifen und mit ResourceApi Applikationen und Devices abfragen. Neben diesen definiert die HQApi noch weitere. Für einen Überblick empfiehlt sich http://support.hyperic.com/display/DOC/HQApi+Java+API.

for(Resource r: rr.getResource()){
  MetricsResponse metricsResponse = metricApi.getMetrics(r, true);
  for (Metric m : metricsResponse.getMetric()) {
    try {
      MetricDataResponse mdr = metricApi.getMetricData(m.getId(), begin, now);
      double value = mdr.getMetricData().getDataPoint().get(0).getValue();
      System.out.println(m.getName() +" "+ value+" "+m.getMetricTemplate().getUnits() +" Updates every "+m.getInterval()/1000+" s");
      // Reaktion auf bestimmten Wert
      if (m.getName()=="Load Average 5 Minutes" && value<1){
        lib.changeFlavour(r.getName().replace(".novalocal", ""));
      }
    } catch(Exception e){
      e.printStackTrace();
    }
  }
}

Untenstehender Code listet alle Metrics eines Systems auf. Dies sind Daten, wie die generelle Verfügbarkeit des Servers, die CPU-Auslastung der letzten 5 Minuten, der verwendete und freie Arbeitsspeicher. Die Daten werden über ein SNMP-Plugin von Hyperic bereitgestellt. Die Verwendung von MetricDataTemplates eröffnet noch weitere Daten, abhängig vom Typ der Ressource. Eine Ressource bezeichnet im Hyperic-Umfeld eine Anwendung oder einen Rechner unter Monitoring.

Das Listing zeigt auch einen einfachen Weg auf, auf Schwellwert-Überschreitungen zu reagieren. Hierzu kann einfach der zu überwachende Wert programmatisch überprüft werden und bei Überschreitung einer Schwelle kann eine Aktion ausgelöst werden.

Zum Controlling der überwachten virtuellen Maschinen dient in diesem Fall ein Libcloud-Skript, das aus einer eigenen Java-Klasse, Libcloud aufgerufen werden kann. Sie kapselt den Aufruf eines Skripts mit verschiedenen Parametern zur Manipulation einer OpenStack-VM.

public class Libcloud {	
  Runtime runtime;	
  protected Libcloud(){
    runtime = Runtime.getRuntime();
  }	
  //Gibt die Ausgabe des Kommandos zurueck und im Fehlerfall auch den Fehlertext
  private void processOutput(Process process) throws Exception{
    // gekuerzt
  }
  //param ('delete','create'...), name=Name der Instanz
  private void execute(String param, String name){
   try {
     Process process = runtime.exec("libcloud/libcloud.py "+param+" "+name);
     processOutput(process);
    }
    catch(Exception e){ e.printStackTrace(); }
  }	
  // Erstellt neue Instanz
  protected void createInstance(String name, String image, String size){
    execute("create", name, image, size); }
  // Loescht vorhandene Instanz  
  protected void deleteInstance(String name){
    execute("delete", name); }
  // Startet Instanz neu
  protected void rebootInstance(String name){		
    execute("reboot", name); } 
  // Stoppt laufende Instanz
  protected void stopInstance(String name){
    execute("stop", name); }
  // Aendert die Flavor einer VM
  protected void changeFlavor(String name){
    execute("changeFlavor", name); }
}

Das in obigem Listing referenzierte Python-Skript nutzt den über die Libcloud-API bereitgestellten OpenStack_1_1_NodeDriver, um auf die Funktionalität von OpenStack zugreifen zu können. Dieser kapselt dazu die entsprechenden nova-Services. Anders als bei Deltacloud besteht hier nicht die Möglichkeit, die REST-Apis der einzelnen Komponenten aufzurufen, die sich zudem noch von der CIMI-Spezifikation unterscheiden.

#! /usr/bin/python

from libcloud.compute.types import Provider, NodeState
from libcloud.compute.providers import get_driver
from sys import argv

Driver = get_driver(Provider.OPENSTACK)
conn = Driver('admin', 'admin', ex_force_auth_url='http://10.18.48.142:5000/v2.0/',ex_tenant_name='admin', ex_force_auth_version='2.0_password', host='10.18.48.142', port=8774 )

size_name = argv[4]
image_name= argv[3]
node_name = argv[2]
operation = argv[1]

# Hilfsfunktionen fuer Node, Image, Size

if operation == "create":
        print "Create Instance", node_name
        image = get_image(image_name)
        size = get_size(size_name)
        node = conn.create_node(name=node_name ,image=image, size=size)
if operation == "delete":
        print "Delete Instance", node_name
if operation == "reboot":
        print "Reboot instance", node_name
        conn.reboot_node(get_node(node_name))
if operation == "shutdown":
        print "Shutdown Instance", node_name
if operation == "changeFlavor":
        print "change flavor", node_name
        n = get_node(node_name)
        print n.extra['flavorId']
        n.extra['flavorId'] = 2
        conn.ex_confirm_resize(n)

Eine Besonderheit ist hier der Abschnitt "changeFlavor". Node, libclouds Name für eine virtuelle Maschine, hat von Haus aus nur ein paar Attribute, die jedem Provider gemein sind. Für providerspezifische Attribute stellt der Node ein extra-Feld bereit, ein Hash, in dem weitere Eigenschaften gespeichert werden können. Sollen diese Werte durch Libcloud-Funktionen geändert werden, nutzt man die, ebenfalls providerspezifischen, ex_-Funktionen. Dazu gehört auch die Funktion zum Resizen eines Node, was, wenn man auf Providerunabhängigkeit Wert legt, einen Mehraufwand bedeutet. Dieser rechtfertigt aber schon fast, dass man sich direkt der Shell-Skripte des Providers bedient.

Ansätze zum Überwachen der Cloud-Umgebung

Der erste im Projekt verfolgte Ansatz bestand darin, die eigentlichen Virtuellen Maschinen auf ihre Auslastung zu überwachen. Dazu kam der in Abschnitt "Prinzipielle Durchführung des Monitorings mit Hyperic und Libcloud" verwendete Ansatz zum Einsatz. Durch den auf den VMs installierten Hyperic-Agent konnten die Messdaten sowohl über die Weboberfläche des Servers angezeigt werden, als auch programmatisch über den Polling-Daemon ausgelesen werden. Das Zuweisen weiterer Ressourcen an diese VM stellte sich dabei aber als nicht machbar heraus. OpenStack unterstützt weder eine direkte Erhöhung des CPU-Shares für eine VM auf dem Hypervisor, noch ist es möglich, zur Laufzeit den Flavor einer Instanz zu verändern. OpenStack ist es nur möglich, die betreffende VM zu pausieren (Suspend), dann die VM zu migrieren, dabei dann die Hardwarekonfiguration zu verändern und setzt anschließend den Betrieb der VM fort (Resume). Die im Projekt eingesetzten Server, die als Compute-Nodes dienten unterschieden sich jedoch in ihren CPU-Flags, so dass eine Migration nach diesem Schema ebenfalls nicht möglich war.

Ein weiterer Ansatz sollte darin bestehen, den Hypervisor zu überwachen. Im Projekt wurde KVM als Hypervisor verwendet. Bei zu hoher Auslastung des Hypervisors eines Compute-Nodes sollten, so die Idee, VMs zu einem weniger ausgelasteten Compute-Node migriert werden. Allerdings gibt es für Hyperic kein Modul, welches einen KVM-Hypervisor überwachen kann. Ein entsprechendes Modul für Xen existiert jedoch. Ein Umstellen auf diesen Hypervisor war allerdings aus Zeitgründen nicht mehr möglich. Ein weiteres Problem bestand darin, dass OpenStack in Verbindung mit KVM keine Live-Migration unterstützt und die Suspend-Migrate-Resume-Migration aufgrund unterschiedlicher CPU-Merkmale der Compute-Nodes nicht möglich war.

Fazit

Dadurch, dass schon sehr viel Zeit für die eigentliche Installation von OpenStack verwendet wurde, konnte im Zuge des Projekts nur sehr oberflächlich auf den Punkt des Monitorings eingegangen werden. Nach Evaluation der Werkzeuge stellte sich heraus, dass diese für ein produktives Monitoring und eine automatisierte Steuerung nur bedingt zu gebrauchen sind.

Hyperic stellte sich als ungeeignet heraus, da die Fähigkeit fehlte, über die grafische Oberfläche Alarme zu definieren und ihnen auch gleichzeitig ein Reaktionsskript zuordnen zu können. Dies erfordert, dass Watchdog-Prozesse in Java geschrieben werden müssten, um die Funktionalität der HQApi nutzen zu können, über die, wie unter "Prinzipielle Durchführung des Monitorings mit Hyperic und Libcloud" beschrieben, dies möglich wäre.

Libcloud ist durchaus ein guter Ansatz für die Abstraktion verschiedener Cloud-APIs, doch noch sind zu wenige Funktionen wirklich providerunabhängig. Da gerade Kernfunktionalitäten, wie das Resizen eines Nodes, auf ex_-Funktionen und -Parameter zugreifen müssen, müssten bei einem Wechsel des Providers (bzw. der in der Hochschule genutzten Cloud-Infrastruktur) auch die Steuerungsskripte angepasst werden. Daraus wäre also kein wirklicher Vorteil entstanden.

Ein weiteres Hindernis stellte die Heterogenität der Hardware aller im Projekt eingesetzten Compute-Nodes dar. Trotz gleichen Hypervisors ließ sich keine Migration durchführen.

Schlussbetrachtung

Prinzipiell funktioniert OpenStack als Cloud-Computing-Lösung. Virtuelle Maschinen lassen sich anlegen, verwalten und starten. Die Web-Oberfläche ermöglicht eine komfortable Administration der meisten Funktionen.

Die Installation von OpenStack war sehr viel aufwändiger als ursprünglich eingeplant. Dies lag vor allem an der unzureichenden und unübersichtlichen Dokumentation. Der ursprüngliche Ansatz mit Redundanz der Controller-Nodes musste verworfen werden. Ein Netzwerkproblem entstand durch die Verwendung von zwei Netzwerkschnittstellen in Verbindung mit der Standardkonfiguration von Ubuntu.

Zur Skalierbarkeit von OpenStack lässt sich sagen, dass es sehr einfach ist, weitere Compute-Nodes zu integrieren, da es ausreicht weitere Server hinzuzufügen und die Nova-Compute Software zu installieren.

Als abschließendes Fazit lässt sich sagen, dass OpenStack für die untersuchten Anwendungsfälle nicht geeignet ist. Für den ersten Anwendungsfall ist OpenStack überdimensioniert, es bietet Funktionen die nicht unbedingt gebraucht werden (z.B. VNC Proxy, Accounting), andererseits ist es schwierig viele VMs für unterschiedliche Benutzer anzulegen. Bezogen auf den zweiten Anwendungsfall bietet OpenStack leider keine Möglichkeit die Details der Ressourcenzuweisung zu beeinflussen. Eine Monitoring-Schnittstelle ist ebenfalls nicht vorhanden.