1. Übersicht
Die Codelabs-Reihe zur Serverless Migration Station (zum Selbststudium, praxisorientierte Anleitungen) und ähnliche Videos sollen Entwickler von Google Cloud Serverless bei der Modernisierung ihrer Anwendungen unterstützen, indem sie eine oder mehrere Migrationen durchgehen, in erster Linie von Legacy-Diensten. Dadurch werden Ihre Anwendungen portabler und bieten mehr Optionen und Flexibilität, sodass Sie eine breitere Palette von Cloud-Produkten einbinden und darauf zugreifen sowie einfacher auf neuere Sprachversionen upgraden können. Der Schwerpunkt dieser Reihe liegt anfangs auf die ersten Cloud-Nutzer, in erster Linie auf Entwicklern von App Engine (Standardumgebung). Sie ist aber umfassend genug, um auch andere serverlose Plattformen wie Cloud Functions und Cloud Run oder gegebenenfalls andere Plattformen einzubeziehen.
In diesem Codelab erfahren Sie, wie Sie App Engine Memcache in die Beispiel-App aus dem Codelab für Modul 1 einbinden und verwenden. In dieser Anleitung in Modul 12 fügen wir die Verwendung von Memcache hinzu. Als Nächstes wird in Modul 13 die Migration zu Cloud Memorystore beschrieben.
Sie werden lernen,
- Verwenden der App Engine Memcache API/-Bibliothek
- Caching einer einfachen Python 2 Flask-App Engine NDB-Anwendung hinzufügen
Voraussetzungen
- Ein Google Cloud Platform-Projekt mit einem aktiven GCP-Rechnungskonto
- Grundlegende Python-Kenntnisse
- Erfahrung mit gängigen Linux-Befehlen
- Grundkenntnisse zum Entwickeln und Bereitstellen von App Engine-Anwendungen
- Eine funktionierende App Engine-Anwendung für Modul 1 (führen Sie ihr Codelab aus [empfohlen] oder kopieren Sie die Anwendung aus dem Repository)
Umfrage
Wie möchten Sie diese Anleitung nutzen?
<ph type="x-smartling-placeholder">Wie würden Sie Ihre Erfahrung mit Python bewerten?
<ph type="x-smartling-placeholder">Wie würden Sie Ihre Erfahrungen im Umgang mit Google Cloud-Diensten bewerten?
<ph type="x-smartling-placeholder">2. Hintergrund
Für die Migration von App Engine Memcache fügen Sie dessen Nutzung der vorhandenen Flask- und App Engine NDB-Anwendung hinzu, die sich aus dem Codelab für Modul 1 ergibt. Die Beispiel-App zeigt dem Nutzer die zehn letzten Besuche an. Wenn derselbe Nutzer seinen Browser aktualisiert, ist es nicht optimal, kontinuierlich neue Besuchsentitäten zu erstellen und die letzten Besuche aus Datastore abzurufen. Diese letzten Besuche werden also im Cache gespeichert.
Wenn derselbe Besucher die Seite aufruft, werden diese Besuche aus dem Cache zurückgegeben. Wenn ein neuer Nutzer die Website besucht oder eine Stunde vergangen ist, wird der Cache geleert und durch die neuesten Einträge ersetzt (ganz zu schweigen von einem neu registrierten Besuch). Wenn diese App Engine Memcache-Integration implementiert ist, können wir sie im nächsten Codelab (Modul 13) zu Cloud Memorystore migrieren.
Diese Anleitung umfasst die folgenden Schritte:
- Einrichtung/Vorarbeit
- Konfiguration aktualisieren
- Anwendungscode ändern
3. Einrichtung/Vorarbeit
Bevor wir zum Hauptteil des Tutorials kommen, richten wir unser Projekt ein, rufen den Code ab und stellen dann die Referenzanwendung bereit, damit wir wissen, dass wir mit funktionierendem Code beginnen.
1. Projekt einrichten
Wenn Sie das Codelab für Modul 1 abgeschlossen haben, empfehlen wir Ihnen, dasselbe Projekt und denselben Code wiederzuverwenden. Alternativ können Sie ein ganz neues Projekt erstellen oder ein anderes vorhandenes Projekt wiederverwenden. Achten Sie darauf, dass das Projekt ein aktives Rechnungskonto hat und App Engine aktiviert ist.
2. Baseline-Beispiel-App abrufen
Eine der Voraussetzungen für dieses Codelab ist eine funktionierende Beispiel-App für Modul 1. Falls Sie keines der Anleitungen haben, lesen Sie die Links oben und folgen Sie der Anleitung, bevor Sie fortfahren. Wenn Sie bereits mit dem Inhalt vertraut sind, können Sie einfach mit dem Code des Moduls 1 unten beginnen.
Unabhängig davon, ob Sie Ihren oder unseren verwenden, beginnen wir mit dem Code für Modul 1. Dieses Codelab führt Sie durch die einzelnen Schritte und endet mit Code, der dem im Repository-Ordner von Modul 11 (FINISH) ähnelt.
- START: Modul 1 Ordner (Python 2)
- FINISH: Modul 12 Ordner (Python 2)
- Gesamtes Repository (um die ZIP-Datei zu klonen oder herunterzuladen)
Das Verzeichnis der START-Dateien von Modul 1 (Ihre oder unsere) sollte wie folgt aussehen:
$ ls README.md main.py templates app.yaml requirements.txt
3. Referenz-App noch einmal bereitstellen
Sie müssen die verbleibenden Schritte jetzt ausführen:
- Machen Sie sich noch einmal mit dem
gcloud
-Befehlszeilentool vertraut - Beispielanwendung mit
gcloud app deploy
noch einmal bereitstellen - Prüfen, ob die Anwendung in App Engine problemlos ausgeführt wird
Sobald Sie diese Schritte erfolgreich ausgeführt haben und feststellen, dass Ihre Webanwendung funktioniert (mit einer Ausgabe ähnlich der unten), können Sie Ihrer Anwendung die Nutzung des Cachings hinzufügen.
4. Konfiguration aktualisieren
An den App Engine-Standardkonfigurationsdateien (app.yaml
, requirements.txt
, appengine_config.py
) sind keine Änderungen erforderlich.
5. Anwendungsdateien ändern
Da nur eine App Engine API hinzugefügt wird, sind keine externen Pakete beteiligt und es müssen keine Konfigurationsdateien (app.yaml
, requirements.txt
, appengine_config.py
) aktualisiert werden. Es gibt nur die Anwendungsdatei main.py
. Daher wirken sich alle Änderungen in diesem Abschnitt nur auf diese Datei aus.
Importe
Der wichtigste Schritt besteht darin, die Memcache-Bibliothek google.appengine.api.memcache
zu importieren. Da wir die letzten Besuche eine Stunde lang im Cache speichern, fügen wir auch eine Konstante für die Anzahl der Sekunden in einer Stunde hinzu. So sieht Ihr Code vor und nach dieser Änderung aus:
VORHER:
from flask import Flask, render_template, request
from google.appengine.ext import ndb
app = Flask(__name__)
NACHHER:
from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb
app = Flask(__name__)
HOUR = 3600
Caching mit Memcache-Unterstützung hinzufügen
Die wichtigste Änderung besteht darin, dass wir Caching in unserer Anwendung verwenden. Genauer gesagt sollten wir die letzten Besuche im Cache speichern, prüfen, ob im Cache gespeicherte Besuche verfügbar sind, und versuchen, die im Cache gespeicherten Ergebnisse gemäß unserem Plan so oft wie möglich zu verwenden. Die App führt folgende Schritte aus, um unser Ziel zu erreichen:
- Aktuellen Besuch festlegen und
visitor
nennen - Versuch, die neueste
visits
aus dem Cache abzurufen - Wenn der Cache leer ist oder der letzte Besucher (
visits[0]['visitor']
) vom aktuellenvisitor
abweicht: Speichern Sie diesen neuesten Besuch, rufen Sie die letzten Besuche ab und speichern Sie sie eine Stunde lang im Cache. visits
dem Nutzer über die Webvorlage anzeigen
Hier sind die Vorher- und Nachher-Änderungen dieser Änderungen:
VORHER:
@app.route('/')
def root():
'main application (GET) handler'
store_visit(request.remote_addr, request.user_agent)
visits = fetch_visits(10)
return render_template('index.html', visits=visits)
NACHHER:
@app.route('/')
def root():
'main application (GET) handler'
# check for (hour-)cached visits
ip_addr, usr_agt = request.remote_addr, request.user_agent
visitor = '{}: {}'.format(ip_addr, usr_agt)
visits = memcache.get('visits')
# register visit & run DB query if cache empty or new visitor
if not visits or visits[0]['visitor'] != visitor:
store_visit(ip_addr, usr_agt)
visits = list(fetch_visits(10))
memcache.set('visits', visits, HOUR) # set() not add()
return render_template('index.html', visits=visits)
Hier ist eine bildliche Darstellung der vorgenommenen Änderungen:
Damit sind alle erforderlichen Änderungen zum Hinzufügen der Verwendung von App Engine memcache
zur Beispiel-App für Modul 1 abgeschlossen. Lassen Sie uns diese App erstellen und bereitstellen, um zu sehen, wie sie funktioniert!
6. Zusammenfassung/Bereinigung
In diesem Abschnitt wird dieses Codelab abgeschlossen. Dazu wird die App bereitgestellt und geprüft, ob sie wie vorgesehen und in allen ausgegebenen Ausgabedaten funktioniert. Führen Sie nach der App-Überprüfung alle Bereinigungsschritte durch und erwägen Sie die nächsten Schritte.
Anwendung bereitstellen und prüfen
Stellen Sie die Anwendung noch einmal mit gcloud app deploy
bereit und prüfen Sie, ob sie funktioniert. Dein Code sollte jetzt mit den Inhalten in FINISH übereinstimmen, dem Modul 12-Ordner. Die Ausgabe sollte mit der App für Modul 1 identisch sein, die Sie zuvor bereitgestellt haben:
Wir haben lediglich die User Experience für denselben Nutzer beschleunigt. Wenn sie aktualisiert werden, sollten Sie die Ergebnisse direkt aus dem Cache erhalten. Dadurch wird weder ein neuer Besuch erstellt noch ein Datastore-Abruf durchgeführt.
Herzlichen Glückwunsch. Sie haben das Codelab für Modul 12 zum Hinzufügen der Verwendung des App Engine-memcache
-Dienstes zu unserer Beispielanwendung abgeschlossen. Sie haben jetzt die Möglichkeit, diese Python 2-Anwendung im Bonusschritt nach Python 3 zu portieren.
Bereinigen
Allgemein
Falls Sie bereits fertig sind, empfehlen wir Ihnen, Ihre App Engine-Anwendung zu deaktivieren, um Gebühren zu vermeiden. Wenn Sie jedoch weitere Tests oder Experimente durchführen möchten, bietet die App Engine-Plattform ein kostenloses Kontingent. Solange Sie diese Nutzungsstufe nicht überschreiten, sollten Ihnen keine Kosten in Rechnung gestellt werden. Das bezieht sich auf die Rechenleistung. Es können jedoch auch Gebühren für relevante App Engine-Dienste anfallen. Weitere Informationen finden Sie auf der Preisseite. Wenn diese Migration andere Cloud-Dienste betrifft, werden diese separat abgerechnet. Lesen Sie in beiden Fällen gegebenenfalls den Abschnitt „Speziell für dieses Codelab“. weiter unten.
Zur vollständigen Offenlegung fallen bei der Bereitstellung auf einer serverlosen Computing-Plattform von Google Cloud wie App Engine geringfügige Build- und Speicherkosten an. Für Cloud Build und Cloud Storage gibt es ein eigenes kostenloses Kontingent. Die Speicherung dieses Images verbraucht einen Teil dieses Kontingents. Möglicherweise leben Sie in einer Region, in der es keine solche kostenlose Stufe gibt. Achten Sie daher auf Ihre Speichernutzung, um potenzielle Kosten zu minimieren. Bestimmte Cloud Storage-„Ordner“ sollten Sie Folgendes überprüfen:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
- Die Speicherlinks oben hängen von Ihrer
PROJECT_ID
- und *LOC
*-Adresse ab, z. B. „us
“ wenn Ihre App in den USA gehostet wird.
Wenn Sie jedoch nicht mit dieser Anwendung oder anderen verwandten Migrations-Codelabs fortfahren und alles vollständig löschen möchten, beenden Sie Ihr Projekt.
Nur für dieses Codelab
Die unten aufgeführten Dienste gelten nur für dieses Codelab. Weitere Informationen finden Sie in der Dokumentation des jeweiligen Produkts:
- Der App Engine Memcache-Dienst ist in zwei verschiedenen Ausführungen erhältlich, von denen jede eine eigene Preisstruktur hat. Daher müssen Sie die Nutzung im Zusammenhang mit der Abrechnung nachverfolgen.
- Der App Engine Datastore-Dienst wird von Cloud Datastore (Cloud Firestore im Datastore-Modus) bereitgestellt, der ebenfalls eine kostenlose Stufe hat. Weitere Informationen finden Sie auf der Preisseite.
Nächste Schritte
Die nächste zu berücksichtigende logische Migration wird in Modul 13 behandelt. Darin wird Entwicklern gezeigt, wie sie vom App Engine-memcache
-Dienst zu Cloud Memorystore migrieren. Diese Migrationen sind alle optional und stehen Nutzern zur Verfügung, die verschiedene Schritte zur Modernisierung ihrer Anwendungen ausführen möchten. Der Cloud Memorystore-Dienst ist aus vielen Gründen ein erhebliches Upgrade für die memcache
von App Engine:
- Cloud Memorystore ist nicht serverlos. Das bedeutet, dass Sie einen Server für den Cache zuweisen müssen. Cloud Memorystore hat ebenfalls keine kostenlose Stufe. Beide Faktoren können erhebliche Auswirkungen auf die Kosten haben.
- Cloud Memorystore unterstützt zwei verschiedene zugrunde liegende Speichermechanismen (Caching-Engines), Redis und Memcached.
- Cloud Memorystore (für Redis) verfügt über einen wesentlich umfangreicheren und umfassenderen Funktionsumfang als App Engine Memcache.
- Zur Verwendung von Cloud Memorystore müssen Sie einen Cloud Memorystore-Server einrichten, ihn einem Google Cloud VPC-Netzwerk hinzufügen und Ihre App Engine-Anwendung dann dieses Netzwerk verwenden lassen, um mit Ihrem Memorystore-Server zu kommunizieren.
Wenn Sie nicht alle von Cloud Memorystore verfügbaren Funktionen benötigen oder sich die Auswirkungen auf die Kosten Sorgen machen, können Sie App Engine Memcache verwenden.
Über Modul 13 hinaus gibt es eine ganze Reihe anderer möglicher Migrationen wie Cloud NDB und Cloud Datastore oder Cloud Tasks. Außerdem werden produktübergreifende Migrationen zu Cloud Run und Cloud Functions durchgeführt. Sie finden sie alle im Migrations-Repository.
Ein weiterer möglicher nächster Schritt ist die Portierung zu Python 3, die im nächsten Abschnitt als optionaler Schritt behandelt wird.
7. BONUS: Migration zu Python 3
Übersicht
Dieser Abschnitt enthält optionale Bonusinhalte durch die Migration der Anwendung für Modul 12, die wir gerade abgeschlossen haben, zu Python 3. Wir beginnen mit der Konfiguration, gefolgt von der Anwendung.
app.yaml vereinfachen
Einer der Vorteile der Python 3-Laufzeit besteht darin, dass die app.yaml
erheblich vereinfacht werden kann.
VORHER:
Unten sehen Sie, was in app.yaml
am Ende von Modul 12 steht:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
Da für die Python 3-Laufzeit Web-Frameworks für ihr eigenes Routing erforderlich sind, müssen alle Routing-Handler in app.yaml
zu auto
geändert werden. Wenn keine statischen Dateien bereitgestellt werden, können Nutzer einfach den gesamten handlers:
-Abschnitt entfernen. Außerdem wurden threadsafe
und api_version
eingestellt.
NACHHER:
Mit den gerade beschriebenen erforderlichen Änderungen ist dies der Ersatz-app.yaml
für Python 3:
runtime: python39
app_engine_apis: true
Die einzige Zeile, die erklärt werden muss, ist app_engine_apis: true
. Als die alten App Engine-Dienste 2021 für Laufzeiten der zweiten Generation verfügbar wurden, ist für einige Laufzeiten, einschließlich Python 3, ein zusätzliches Bootstrapping für den Zugriff auf diese APIs wie ndb
, taskqueue
und memcache
erforderlich. Diese Zeile in der Konfiguration dient diesem Zweck.
Anforderungen.txt aktualisieren
In requirements.txt
ist ein weiteres Bootstrapping der ursprünglichen APIs erforderlich: Zugriff auf das neue App Engine SDK muss eingeschlossen werden.
VORHER:
Unten sehen Sie, was in app.yaml
am Ende von Modul 12 steht:
flask
NACHHER:
Fügen Sie einfach das App Engine Python SDK hinzu. Sie sollten nun über Folgendes verfügen:
flask
appengine-python-standard
appengine_config.py und lib löschen
App Engine-Laufzeiten der nächsten Generation überarbeiten die Nutzung von Drittanbieterpaketen:
- Integrierte Bibliotheken wurden von Google geprüft und auf App Engine-Servern zur Verfügung gestellt. Wahrscheinlich enthalten sie C/C++-Code, den Entwickler nicht in der Cloud bereitstellen dürfen. Diese Bibliotheken sind in den Laufzeiten der 2. Generation nicht mehr verfügbar.
- Das Kopieren von nicht integrierten Bibliotheken (manchmal als „Vendoring“ oder „self-bundling“ bezeichnet) ist in Laufzeiten der 2. Generation nicht mehr erforderlich. Sie sollten stattdessen in
requirements.txt
aufgeführt werden. Dort werden sie vom Build-System zum Zeitpunkt der Bereitstellung automatisch in Ihrem Namen installiert.
Aufgrund dieser Änderungen an der Paketverwaltung durch Drittanbieter werden weder die Datei appengine_config.py
noch der Ordner lib
benötigt. Löschen Sie sie daher. In Laufzeiten der 2. Generation installiert App Engine automatisch Drittanbieterpakete, die in requirements.txt
aufgeführt sind. Zusammenfassung:
- Keine selbst gebündelten oder kopierten Bibliotheken von Drittanbietern; in
requirements.txt
auflisten - Kein
pip install
in einemlib
-Ordner, d. h. keinlib
-Ordnerzeitraum - Keine Auflistung von integrierten Bibliotheken von Drittanbietern (daher kein Abschnitt
libraries
) inapp.yaml
vorhanden; inrequirements.txt
auflisten - Wenn du keine Bibliotheken von Drittanbietern aus deiner App referenzierst, gibt es keine
appengine_config.py
-Datei
Die einzige Anforderung für Entwickler besteht darin, alle gewünschten Drittanbieterbibliotheken in requirements.txt
aufzulisten.
Anwendung zur Verwendung des App Engine SDK aktualisieren
Wie bereits oben erwähnt, sind bei Python 3-Anwendungen einige Änderungen erforderlich, um auf gebündelte App Engine-Dienste zugreifen zu können:
- App Engine SDK-Bundle (in
requirements.txt
) - App Engine SDK aktivieren (in
app.yaml
) - WSGI-Objekt umschließen (in
main.py
)
Das erste Paar wurde oben ausgefüllt. Die letzte Anforderung besteht also darin, main.py
zu aktualisieren.
VORHER:
Unten sehen Sie die main.py
von Python 2 am Ende von Modul 12:
from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb
app = Flask(__name__)
HOUR = 3600
NACHHER:
Importieren Sie für den Python 3-Port das SDK und verpacken Sie das Flask-App-Objekt damit (den SDK-Wrapper). Dies führt zu folgendem Ergebnis:
from flask import Flask, render_template, request
from google.appengine.api import memcache, wrap_wsgi_app
from google.appengine.ext import ndb
app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600
Entwickler müssen diese Änderungen an ihren Python-Anwendungen vornehmen, wenn sie von 2.x auf 3.x portieren, um auf die gebündelten Dienste zugreifen zu können. Wenn Sie Flask nicht verwenden, finden Sie in den Dokumenten auch Django- und Pyramid-Beispiele. Wenn Ihr Python 2-Code keine Webanwendung ist, reicht es bei der Portierung zu Python 3 aus, nur das SDK-Paket hinzuzufügen. Unser Anwendungscode wurde ursprünglich für Python 2 und 3 entwickelt, sodass keine zusätzlichen Kompatibilitätsänderungen erforderlich sind.
Anwendung bereitstellen
Nachdem Sie die oben genannten Änderungen vorgenommen haben, können Sie die aktualisierte Beispiel-App bereitstellen. Es gibt keine Probleme, wenn Sie eine Python 3-Version Ihrer App über eine ursprüngliche Python 2-Version im selben GCP-Projekt bereitstellen. Das Verhalten der App sollte sich nicht ändern. Wenn Sie Ihre aktualisierte App mit unserer App vergleichen möchten, sehen Sie sich den Ordner „Module 12b“ im Migrations-Repository an. Weitere Informationen zur Unterstützung gebündelter App Engine-Dienste in den neuesten Laufzeiten wie Python 3 finden Sie in der Ankündigung zu neuen Funktionen und im Codelab für Modul 17.
Glückwunsch! Sie haben den Bonusschritt in Modul 12 abgeschlossen. Weitere Informationen finden Sie auch in der Dokumentation zum Vorbereiten von Konfigurationsdateien für die Python 3-Laufzeit. Lesen Sie oben im Abschnitt „Zusammenfassung/Bereinigung“ die nächsten Schritte und die Bereinigung.
8. Zusätzliche Ressourcen
Im Folgenden finden Sie zusätzliche Ressourcen für Entwickler, die sich näher mit diesem oder verwandten Migrationsmodul und ähnlichen Produkten befassen. Dazu gehören Orte, an denen Sie Feedback zu diesen Inhalten geben können, Links zum Code und verschiedene Dokumentationen, die für Sie nützlich sein könnten.
Codelab-Probleme/Feedback
Wenn Sie Probleme mit diesem Codelab feststellen, suchen Sie bitte zuerst nach Ihrem Problem, bevor Sie es einreichen. Links zum Suchen und Erstellen neuer Ausgaben:
Migrationsressourcen
Links zu den Repository-Ordnern für Modul 2 (START) und Modul 12 (FINISH) finden Sie in der folgenden Tabelle. Sie können auch über das Repository für alle App Engine-Codelab-Migrationen auf sie zugreifen. Sie können eine ZIP-Datei klonen oder herunterladen.
Codelab | Python 2 | Python 3 |
code (in dieser Anleitung nicht enthalten) | ||
Modul 12 (dieses Codelab) |
Onlinereferenzen
Nachfolgend finden Sie Onlineressourcen, die für diese Anleitung relevant sein könnten:
App Engine
- App Engine-Dokumentation
- Python 2-Laufzeit der App Engine (Standardumgebung)
- Python 3-Laufzeit von App Engine (Standardumgebung)
- Unterschiede zwischen Python 2 und 3 Laufzeiten der App Engine (Standardumgebung)
- Python 2 zu 3 Migrationsanleitung für App Engine (Standardumgebung)
- Informationen zu Preisen und Kontingenten für App Engine
- Einführung der App Engine-Plattform der zweiten Generation (2018)
- Vergleichen Sie zuerst und Plattformen der zweiten Generation
- Langzeitsupport für Legacy-Laufzeiten
- Repository mit Beispielen für die Migration der Dokumentation
- Repository für von der Community beigetragene Migrationsbeispiele
Cloud Memorystore und Cloud Datastore
- Produktseite von Cloud Memorystore
- Dokumentation zu Cloud Memorystore for Redis
- Dokumentation zu Cloud Memorystore for Memcached
- Preisinformationen zu Cloud Memorystore (for Redis)
- Cloud Datastore -Dokumentation
- Cloud Datastore-Preisinformationen
Weitere Cloud-Informationen
- Python auf der Google Cloud Platform
- Google Cloud-Clientbibliotheken für Python
- „Immer kostenlos“ von Google Cloud Stufe
- Google Cloud SDK (
gcloud
-Befehlszeilentool) - Gesamte Google Cloud-Dokumentation
Videos
- Serverlose Migrationsstation
- Serverlose Expeditionen
- Google Cloud Tech abonnieren
- Google Developers abonnieren
Lizenz
Dieser Text ist mit einer Creative Commons Attribution 2.0 Generic License lizenziert.