Anpassen von Konfigurationsdateien mit Ausgabewerten von CloudFormation Stacks
This content is more than 4 years old and the cloud moves fast so some information may be slightly out of date.
Bei der Migration von Anwendungen auf AWS müssen auch die Konfigurationsdateien der Anwendungen angepasst werden. Auch dabei gilt der Grundsatz “Automatisiere alles”. Doch wie kommen die Daten aus der neu auf AWS provisionierten Infrastruktur auf die Server? Hierzu ein paar Tipps zu CloudFormation und Anpassung von Konfigurationsdateien mit Shell Skripten.
Den Inhalt habe ich in drei Teile aufgeteilt:
Daten aus Cloudformation Exports auslesen
Wie kommen die Daten aus durch CloudFormation generierten Infrastrukturkomponenten in ein Script?
Anpassen von Property Konfigurationsdateien
Wie ersetze ich automatisiert die Parameter der AWS Infrastruktur in Property Dateien
Anpassen von XML Dateien
Per ssh auf 10 Maschinen und händisch Scripte ausführen? Nein, Automate everything, auch wenn es nur 10 Instanzen sind.
Daten aus Cloudformation Exports auslesen-
Um Attribute von mit CloudFormation erzeugten Resourcen auslesen zu können, muss man im Template diese Werte auslesen und dann exportieren. Die Werte kann ich aus den CloudFormation Ressourcen mit “Fn::GetAtt” auslesen.
Hier sind alle unterstützen Attribute gelistet.
Für den Typ “AWS::RDS::DBInstance” kann ich z.B. Endpoint.Address und Endpoint.Port auslesen, woraus ich mit die Verbindungsstring zur Datenbank zusammenbauen kann.
Wenn ich im CloudFormation Template nur mit “Ref” zugreife, bekomme ich die eindeutige ID der Resource. Beim VPC z.B. die VPC ID, beim S3 Bucket den Bucketnamen. Hier ein Beispiel in CloudFormation für “Outputs” um die ID eines VPCs zu exportieren (in YAML):
Outputs:
VPC:
Description: A reference to the created VPC
Value: !Ref VPC
Export:
Name: VpcId
Dazu wird die “Outputs” Abteilung im Template angelegt.
Durch den Extra Eintrag “Export” lässt sich die Variable mit “Fn::ImportValue” auch durch andere Templates importieren.
Auch in serverless lässt sich so ein Wert einfach importieren. Wie kann ich diesen Wert dann in Bash Scripten verwenden? Das geht durch die AWS cli.
aws cloudformation list-exports --query 'Exports\[?Name==\`VpcId\`\].Value' --output text
Ergibt bei mir im Beispiel die Ausgabe “vpc-ac16c2c7”. Im Detail betrachtet:
- cloudformation list-exports ist der Befehl der AWS cli zum Anzeigen der Variablen der Templates
- Der query Teil selektiert den Teil der JSON Ausgabe, der wir hier haben wollen
- output text ergibt als Standardausgabe statt JSON Text. Interessant für Übersichten ist auch die Ausgabe “table”
Diesen Wert kann ich in einer Umgebungsvariable speichern:
export vpcid=$(aws cloudformation list-exports --query 'Exports\[?Name==\`VpcId\`\].Value' --output text)
Damit kann ich jetzt die VPCId im Shell Skript weiter verwenden. Das kann ich jetzt auf alle Resourcen anwenden, z.B. auch RDS Datenbanken. Diese Ausgaben kann ich jetzt an die passenden Stellen in Konfigurationsdateien einfügen. Nachdem wir jetzt Werte haben, schauen wir uns an, wie ich die Werte in Konfigurationsdateien einsetze.
Anpassen von Property Konfigurationsdateien -
In property Dateien sind die Werte als “parameter=wert” kodiert.
Wenn z.B. Zugangsdaten oder wie im Beispiel der Link zu einer Datenbank in Konfigurationsdateien hinterlegt sind, so kann man diese mit Shell Scripten anpassen. Wichtig ist, es die Ersetzung von Daten mehrfach zu testen. Der Aufwand ist für eine reibungslose Migration dann gut investiert. Die Daten können aus CloudFormation Stacks mit Exports ausgelesen werden (siehe oben). Ein eleganter Weg ist das Programm ‘sed’. Die Kunst ist es, die Parameter richtig zu setzen. Dies geschieht mit Hilfe von regular Expressions. Patchen mit sed auf der Kommandozeile geht so:
Ersetzen von Attributwerten hinter dem Gleichheitszeichen
Im Beispiel ist die neue Datenbank unter ‘jdbc:funnysql://rds.amazonaws’ erreichbar. Die Konfiguration steht in der Datei “konfiguration.properties”. Eine Zeile davon ist “jdbc.url=irgendwas”. Diese Zeile wollen wir verändern. Dies passiert mit diesem Skriptbeispiel.
#!/bin/bash
file=konfiguration.properties
newprop='jdbc:funnysql://rds.amazonaws'
myprop='jdbc.url'
sed -i '' "s#$myprop=\[^ \]*#$myprop=$newprop#" $file
Vorher steht in der Konfigurationsdatei “jdbc.url=irgendwas”, nach dem Ausführen des Scripts wird die Zeile ersetzt durch “jdbc.url=jdbc:funnysql://rds.amazonaws”. Im Detail betrachtet:
- “-i” steht für ein In-Place reeplacement, die Datei wird also direkt verändert
- “s#alt#neu#” ersetz den alten Ausdruck durch den neuen. Häufig wird auch “/” als Trenner verwendet. Dann darf aber das Zeichen “/” nicht im Ausdruck selber vorkommen
- mit “[^ ]*” findet man alle Zeichen bis zum ersten Leerzeichen
- Damit wird die ganz Zeile ersetzt
Verändern von XML Dateien
Viele Programme, gerade Java Programme, verwenden XML Dateien zur Konfiguration. In zwei Sätzen: XML ist so ähnlich wie HTML, das bekannt sein sollte.
Elemente werden in <> gesetzt. Sie müssen geöffnet
Ich kann davon nur abraten. XML kann variabel aufgebaut werden und dennoch die gleichen Informationen enthalten. Daher verwenden wir hier ein kleines Tool, welches XML kennt und einfach auf Amazon Linux Instanzen installiert werden kann xmlstar: Auf Amazon Linux kann das Programm einfach installiert werden: yum -y install xmlstarlet Z.B. Confluence arbeitet wie viele Java Programme mit XML Konfigrationsdateien. Bekommt man jetzt eine neue Datenbank, so kann man mit xmlstar und so einem Script die Werte anpassen. Dabei kann man den Pfad oder auch Attribute selektieren. Die newurl baue ich mir mit den Endpoint.Address und Port aus dem CloudFormation Stack zusammen.
#!/bin/bash
file="/pfad/confluence.cfg.xml"
newurl="newurl"
xmlstarlet ed -P -u "/confluence-configuration/properties/property\[@name='hibernate.connection.url'\]" -v "$newurl" $file >$tmp
mv -f $tmp $file
Zusammenfassung
Damit habe ich das Handwerkszeug zusammen, um mit CloudFormation Resourcen automatisiert aufzubauen und die Attribute der Ressourcen aus dem CloudFormation Stack auszulesen. Damit kann man der Automatisierung wieder einen Schritt näher kommen.