Migrieren von Tomcat-Anwendungen zu Containern unter Azure Kubernetes Service

In diesem Leitfaden wird beschrieben, was Sie beachten sollten, wenn Sie eine vorhandene Tomcat-Anwendung für die Ausführung unter Azure Kubernetes Service (AKS) migrieren möchten.

Vor der Migration

Führen Sie vor Beginn einer Migration die in den folgenden Abschnitten beschriebenen Schritte zur Bewertung und Bestandsermittlung aus, um eine erfolgreiche Migration zu gewährleisten.

Bestand: Externe Ressourcen

Externe Ressourcen, z. B. Datenquellen, JMS-Nachrichtenbroker und andere, werden per JNDI (Java Naming and Directory Interface) eingefügt. Für einige dieser Ressourcen ist unter Umständen eine Migration oder erneute Konfiguration erforderlich.

Innerhalb Ihrer Anwendung

Untersuchen Sie die Datei META-INF/context.xml. Suchen Sie im <Context>-Element nach <Resource>-Elementen.

Auf den Anwendungsservern

Untersuchen Sie die Dateien $CATALINA_BASE/conf/context.xml und $CATALINA_BASE/conf/server.xml sowie die XML-Dateien, die in Verzeichnissen der Art $CATALINA_BASE/conf/[Engine-Name]/[Hostname] enthalten sind.

In context.xml-Dateien werden JNDI-Ressourcen im <Context>-Element der obersten Ebene mithilfe von <Resource>-Elementen beschrieben.

In server.xml-Dateien werden JNDI-Ressourcen im <GlobalNamingResources>-Element mithilfe von <Resource>-Elementen beschrieben.

Datenquellen

Datenquellen sind JNDI-Ressourcen, für die das type-Attribut auf javax.sql.DataSource festgelegt ist. Dokumentieren Sie für jede Datenquelle die folgenden Informationen:

  • Wie lautet der Name der Datenquelle?
  • Wie ist der Verbindungspool konfiguriert?
  • Wo ist die JAR-Datei mit den JDBC-Treibern zu finden?

Weitere Informationen finden Sie in der Tomcat-Dokumentation unter Anleitung zur JNDI-Datenquelle.

Alle anderen externen Ressourcen

Es würde den Rahmen dieses Leitfadens sprengen, jede mögliche externe Abhängigkeit zu dokumentieren. Ihr Team ist dafür verantwortlich, zu überprüfen, dass nach der Migration die Anforderungen aller externen Abhängigkeiten Ihrer Anwendung abgedeckt werden können.

Bestand: Geheimnisse

Kennwörter und sichere Zeichenfolgen

Überprüfen Sie alle Eigenschaften und Konfigurationsdateien auf den Produktionsservern auf Geheimniszeichenfolgen und Kennwörter. Überprüfen Sie unbedingt server.xml und context.xml in $CATALINA_BASE/conf. Unter Umständen finden Sie in Ihrer Anwendung auch Konfigurationsdateien mit Kennwörtern oder Anmeldeinformationen. Dies können Dateien wie META-INF/context.xml und für Spring Boot-Anwendungen application.properties oder application.yml sein.

Ermitteln, ob und wie das Dateisystem verwendet wird

Für jegliche Nutzung des Dateisystems auf dem Anwendungsserver sind erneute Konfigurationen oder in selteneren Fällen auch Architekturänderungen erforderlich. Es kann sein, dass für Sie einige bzw. alle folgenden Szenarien zutreffen.

Schreibgeschützter statischer Inhalt

Falls mit Ihrer Anwendung derzeit statischer Inhalt bereitgestellt wird, benötigen Sie dafür einen anderen Speicherort. Sie können beispielsweise erwägen, statischen Inhalt in Azure Blob Storage zu verschieben und Azure CDN hinzuzufügen, um global eine sehr hohe Downloadgeschwindigkeit zu erzielen. Weitere Informationen finden Sie unter Hosten von statischen Websites in Azure StorageundSchnellstart: Integrieren eines Azure-Speicherkontos in Azure CDN. Sie können den statischen Inhalt auch direkt in einer App im Azure Spring Apps Enterprise-Plan bereitstellen. Weitere Informationen finden Sie unter Bereitstellen statischer Webdateien.

Dynamisch veröffentlichter statischer Inhalt

Wenn Ihre Anwendung statischen Inhalt zulässt, der von Ihrer Anwendung hochgeladen bzw. produziert wird, nach der Erstellung aber unveränderlich ist, können Sie Azure Blob Storage und Azure CDN wie oben beschrieben nutzen. Hierbei können Sie auch eine Azure-Funktion zum Verarbeiten von Uploads und der CDN-Aktualisierung verwenden. Eine entsprechende Beispielimplementierung finden Sie unter Hochladen und CDN-Vorabladen von statischem Inhalt mit Azure Functions. Sie können den statischen Inhalt auch direkt in einer App im Azure Spring Apps Enterprise-Plan bereitstellen. Weitere Informationen finden Sie unter Bereitstellen statischer Webdateien.

Dynamischer oder interner Inhalt

Für Dateien, für die von Ihrer Anwendung häufige Schreib- und Lesevorgänge durchgeführt werden (z. B. temporäre Datendateien), oder für statische Dateien, die nur für Ihre Anwendung sichtbar sind, können Sie Azure Storage-Freigaben als persistente Volumes bereitstellen. Weitere Informationen finden Sie unter Dynamisches Erstellen und Verwenden eines persistenten Volumes mit Azure Files in Azure Kubernetes Service (AKS).

Identifizieren eines Mechanismus für Sitzungspersistenz

Untersuchen Sie die context.xml-Dateien in Ihrer Anwendung und der Tomcat-Konfiguration, um den verwendeten Manager für Sitzungspersistenz zu ermitteln. Suchen Sie nach dem <Manager>-Element, und notieren Sie sich den Wert des className-Attributs.

Die integrierten PersistentManager-Implementierungen von Tomcat, z. B. StandardManager oder FileStore, sind nicht für die Nutzung mit einer verteilten skalierten Plattform wie Kubernetes konzipiert. AKS nimmt ggf. einen Lastenausgleich zwischen verschiedenen Pods vor und kann für Pods jederzeit einen transparenten Neustart durchführen. Das dauerhafte Speichern eines veränderlichen Zustands in einem Dateisystem ist daher nicht zu empfehlen.

Ist Sitzungspersistenz erforderlich, müssen Sie eine andere PersistentManager-Implementierung verwenden, bei der in einen externen Datenspeicher geschrieben wird, z. B. VMware Tanzu-Sitzungs-Manager mit Redis Cache. Weitere Informationen finden Sie unter Verwenden von Redis als Sitzungscache mit Tomcat.

Sonderfälle

Für bestimmte Produktionsszenarien sind unter Umständen zusätzliche Änderungen erforderlich, oder es gelten zusätzliche Einschränkungen. Szenarien dieser Art treten zwar meist nicht sehr häufig auf, aber Sie sollten trotzdem sicherstellen, dass sie für Ihre Anwendung entweder nicht zutreffen oder korrekt behoben werden.

Ermitteln, ob für die Anwendung geplante Aufträge benötigt werden

Geplante Aufträge, z. B. Quartz Scheduler-Aufgaben oder cron-Aufträge, können für Tomcat-Bereitstellungen in Containern nicht verwendet werden. Wenn Ihre Anwendung horizontal hochskaliert wird, wird ein geplanter Auftrag unter Umständen mehrmals pro geplantem Zeitraum ausgeführt. Diese Situation kann unerwünschte Konsequenzen haben.

Inventarisieren Sie alle geplanten Aufträge innerhalb oder außerhalb des Anwendungsservers.

Ermitteln, ob Ihre Anwendung betriebssystemspezifischen Code enthält

Falls Ihre Anwendung Code enthält, in den das Betriebssystem für die Ausführung Ihrer Anwendung einbezogen ist, müssen Sie Ihre Anwendung so umgestalten, dass KEINE Abhängigkeit vom zugrunde liegenden Betriebssystem besteht. Beispielsweise müssen alle Vorkommen von / oder \ in Dateisystempfaden ggf. durch File.Separator oder Path.get ersetzt werden.

Ermitteln, ob MemoryRealm genutzt wird

Für MemoryRealm wird eine persistente XML-Datei benötigt. Unter Kubernetes muss diese Datei dem Containerimage hinzugefügt oder in freigegebenen Speicher hochgeladen werden, der für Container verfügbar gemacht wird. Der Parameter pathName muss entsprechend geändert werden.

Gehen Sie wie folgt vor, um zu ermitteln, ob MemoryRealm derzeit verwendet wird: Untersuchen Sie Ihre server.xml- und context.xml-Dateien, und suchen Sie nach <Realm>-Elementen, für die das className-Attribut auf org.apache.catalina.realm.MemoryRealm festgelegt ist.

Ermitteln, ob die SSL-Sitzungsverfolgung genutzt wird

Bei Bereitstellungen in Containern werden SSL-Sitzungen normalerweise außerhalb des Anwendungscontainers angeordnet. Dies erfolgt meist über den Eingangscontroller. Wenn für Ihre Anwendung die SSL-Sitzungsverfolgung benötigt wird, sollten Sie sicherstellen, dass SSL-Datenverkehr direkt an den Anwendungscontainer übergeben wird.

Ermitteln, ob AccessLogValve genutzt wird

Bei Verwendung von AccessLogValve sollte der Parameter directory auf eine bereitgestellte Azure Files-Freigabe oder eines der zugehörigen Unterverzeichnisse festgelegt werden.

Direktes Testen

Migrieren Sie Ihre Anwendung vor der Erstellung von Containerimages zu dem JDK und der Tomcat-Instanz, das bzw. die Sie unter AKS nutzen möchten. Führen Sie für Ihre Anwendung gründliche Tests durch, um die Kompatibilität und Leistung sicherzustellen.

Parametrisieren der Konfiguration

Bei der Migrationsvorbereitung haben Sie in server.xml- und context.xml-Dateien ggf. Geheimnisse und externe Abhängigkeiten identifiziert, z. B. Datenquellen. Ersetzen Sie für alle hierbei identifizierten Elemente den Benutzernamen, das Kennwort, die Verbindungszeichenfolge und die URL durch eine Umgebungsvariable.

Angenommen, die context.xml-Datei enthält das folgende Element:

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
    driverClassName="org.postgresql.Driver"
    username="postgres"
    password="t00secure2gue$$"
/>

In diesem Fall können Sie die Änderungen vornehmen, die im folgenden Beispiel angegeben sind:

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="${postgresdb.connectionString}"
    driverClassName="org.postgresql.Driver"
    username="${postgresdb.username}"
    password="${postgresdb.password}"
/>

Migration

Wir empfehlen Ihnen, für jede zu migrierende Anwendung (WAR-Datei) die unten angegebenen Schritte auszuführen (mit Ausnahme des ersten Schritts „Bereitstellen von Containerregistrierung und AKS“).

Hinweis

Einige Tomcat-Bereitstellungen verfügen ggf. über mehrere Anwendungen, die auf einem einzelnen Tomcat-Server ausgeführt werden. Falls dies für Ihre Bereitstellung zutrifft, empfehlen wir Ihnen dringend, jede Anwendung in einem separaten Pod auszuführen. Auf diese Weise können Sie die Ressourcenverwendung für jede Anwendung optimieren und gleichzeitig die Komplexität und Kopplung minimieren.

Bereitstellen von Containerregistrierung und AKS

Erstellen Sie eine Containerregistrierung und einen Azure Kubernetes-Cluster, für den der Dienstprinzipal in der Registrierung über die Rolle „Leser“ verfügt. Achten Sie darauf, dass Sie für die Netzwerkanforderungen Ihres Clusters das richtige Netzwerkmodell auswählen.

az group create \
    --resource-group $resourceGroup \
    --location eastus
az acr create \
    --resource-group $resourceGroup \
    --name $acrName \
    --sku Standard
az aks create \
    --resource-group $resourceGroup \
    --name $aksName \
    --attach-acr $acrName \
    --network-plugin azure

Vorbereiten der Bereitstellungsartefakte

Klonen Sie das GitHub-Repository für die Schnellstartanleitung für Tomcat in Containern. Es enthält eine Dockerfile und Tomcat-Konfigurationsdateien mit einigen empfohlenen Optimierungen. In den unten angegebenen Schritten werden Änderungen beschrieben, die für diese Dateien ratsam sind, bevor Sie das Containerimage erstellen und unter AKS bereitstellen.

Öffnen von Ports für das Clustering (falls erforderlich)

Wenn Sie das Tomcat-Clustering unter AKS nutzen möchten, sollten Sie sicherstellen, dass in der Dockerfile die erforderlichen Portbereiche verfügbar gemacht werden. Achten Sie beim Angeben der Server-IP-Adresse in server.xml darauf, einen Wert aus einer Variablen zu verwenden, für die beim Starten des Containers die Initialisierung auf die IP-Adresse des Pods durchgeführt wird.

Alternativ kann der Sitzungszustand auch an einem anderen Ort dauerhaft gespeichert werden, damit er für alle Replikate verfügbar ist.

Suchen Sie für die Ermittlung, ob für Ihre Anwendung das Clustering verwendet wird, in der server.xml-Datei in den Elementen <Host> oder <Engine> nach dem <Cluster>-Element.

Hinzufügen von JNDI-Ressourcen

Bearbeiten Sie server.xml, um die Ressourcen hinzuzufügen, die Sie in den Schritten für die Migration vorbereitet haben, z. B. Datenquellen.

Beispiel:

<!-- Global JNDI resources
      Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"
               />

    <!-- Migrated datasources here: -->
    <Resource
        name="jdbc/dbconnection"
        type="javax.sql.DataSource"
        url="${postgresdb.connectionString}"
        driverClassName="org.postgresql.Driver"
        username="${postgresdb.username}"
        password="${postgresdb.password}"
    />
    <!-- End of migrated datasources -->
</GlobalNamingResources>

Weitere Anweisungen zu Datenquellen finden Sie in der Tomcat-Dokumentation in den folgenden Abschnitten der Anleitung zur JNDI-Datenquelle:

Erstellen und Pushen des Images

Die einfachste Möglichkeit zum Erstellen und Hochladen des Images in Azure Container Registry (ACR) zur Verwendung durch AKS ist die Nutzung des Befehls az acr build. Für diesen Befehl ist es nicht erforderlich, dass Docker auf Ihrem Computer installiert ist. Wenn Sie im aktuellen Verzeichnis beispielsweise über die obige Dockerfile und das Anwendungspaket petclinic.war verfügen, können Sie das Containerimage in ACR in nur einem Schritt erstellen:

az acr build \
    --image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" \
    --registry $acrName \
    --build-arg APP_FILE=petclinic.war \
    --build-arg=prod.server.xml .

Sie können den Parameter --build-arg APP_FILE... weglassen, wenn Ihre WAR-Datei den Namen ROOT.war hat. Sie können den Parameter --build-arg SERVER_XML... weglassen, wenn die XML-Datei des Servers den Namen server.xml hat. Beide Dateien müssen sich in demselben Verzeichnis wie die Dockerfile befinden.

Alternativ können Sie die Docker-CLI verwenden, um das Image lokal zu erstellen. Dieser Ansatz kann das Testen und Optimieren des Images vor der ersten Bereitstellung unter ACR vereinfachen. Hierfür muss allerdings die Docker-CLI installiert und der Docker-Daemon ausgeführt werden.

# Build the image locally
sudo docker build . --build-arg APP_FILE=petclinic.war -t "${acrName}.azurecr.io/petclinic:1"

# Run the image locally
sudo docker run -d -p 8080:8080 "${acrName}.azurecr.io/petclinic:1"

# Your application can now be accessed with a browser at http://localhost:8080.

# Log into ACR
sudo az acr login --name $acrName

# Push the image to ACR
sudo docker push "${acrName}.azurecr.io/petclinic:1"

Weitere Informationen finden Sie im Lernmodul zum Erstellen und Speichern von Containerimages in Azure.

Bereitstellen einer öffentlichen IP-Adresse

Wenn für Ihre Anwendung der Zugriff von außerhalb Ihrer internen oder virtuellen Netzwerke möglich sein soll, ist eine öffentliche statische IP-Adresse erforderlich. Diese IP-Adresse sollte innerhalb der Ressourcengruppe des Clusterknotens bereitgestellt werden.

export nodeResourceGroup=$(az aks show \
    --resource-group $resourceGroup \
    --name $aksName \
    --query 'nodeResourceGroup' \
    --output tsv)
export publicIp=$(az network public-ip create \
    --resource-group $nodeResourceGroup \
    --name applicationIp \
    --sku Standard \
    --allocation-method Static \
    --query 'publicIp.ipAddress' \
    --output tsv)
echo "Your public IP address is ${publicIp}."

Bereitstellen für AKS

Erstellen und Anwenden Ihrer Kubernetes-YAML-Dateien. Wenn Sie einen externen Lastenausgleich erstellen (ob für Ihre Anwendung oder einen Eingangscontroller), sollten Sie darauf achten, dass Sie die IP-Adresse aus dem vorherigen Abschnitt als LoadBalancerIP angeben.

Binden Sie externalisierte Parameter als Umgebungsvariablen ein. Vermeiden Sie die Einbindung von Geheimnissen (z. B. Kennwörter, API-Schlüssel und JDBC-Verbindungszeichenfolgen). Geheimnisse werden im Abschnitt Konfigurieren von KeyVault FlexVolume beschrieben.

Konfigurieren von persistentem Speicher

Konfigurieren Sie ein oder mehrere persistente Volumes, wenn für Ihre Anwendung nicht flüchtiger Speicher benötigt wird.

Es kann ratsam sein, ein persistentes Volume mit Azure Files zu erstellen, das im Tomcat-Protokollverzeichnis (/tomcat_logs) bereitgestellt wird. Die Protokolle können dann zentral aufbewahrt werden. Weitere Informationen finden Sie unter Dynamisches Erstellen und Verwenden eines persistenten Volumes mit Azure Files in Azure Kubernetes Service (AKS).

Konfigurieren von KeyVault FlexVolume

Erstellen Sie eine Azure KeyVault-Instanz, und fügen Sie alle erforderlichen Geheimnisse ein. Konfigurieren Sie anschließend eine KeyVault FlexVolume-Instanz, um diese Geheimnisse für Pods zugänglich zu machen.

Sie müssen das Startskript ändern (startup.sh im GitHub-Repository für Tomcat in Containern), um die Zertifikate in den lokalen Keystore des Containers zu importieren.

Migrieren von geplanten Aufträgen

Definieren Sie zum Ausführen von geplanten Aufträgen in Ihrem AKS-Cluster je nach Bedarf Cron-Aufträge.

Nach der Migration

Nachdem Sie Ihre Anwendung zu AKS migriert haben, sollten Sie sich vergewissern, dass sie wie erwartet funktioniert. Als Nächstes können Sie sich über unsere Empfehlungen informieren, mit denen Sie Ihre Anwendung cloudnativer gestalten können.

  • Erwägen Sie, einen DNS-Namen der IP-Adresse hinzuzufügen, die Ihrem Eingangscontroller oder dem Lastenausgleichsmodul der Anwendung zugeordnet ist. Weitere Informationen finden Sie unter Erstellen eines Eingangscontrollers mit einer statischen öffentlichen IP-Adresse in AKS.

  • Erwägen Sie, HELM-Diagramme für Ihre Anwendung hinzuzufügen. Mit einem Helm-Diagramm können Sie Ihre Anwendungsbereitstellung parametrisieren, damit diese von unterschiedlichen Kunden genutzt werden kann.

  • Entwerfen und implementieren Sie eine DevOps-Strategie. Sie können Bereitstellungen automatisieren und mit Azure Pipelines testen, um die Zuverlässigkeit sicherzustellen, während gleichzeitig die Entwicklungsgeschwindigkeit erhöht wird.

  • Aktivieren Sie die Azure-Überwachung für den Cluster, um das Sammeln von Containerprotokollen, Nachverfolgen der Nutzung und andere Optionen zu ermöglichen.

  • Erwägen Sie, anwendungsspezifische Metriken über Prometheus verfügbar zu machen. Prometheus ist ein Open-Source-Framework für Metriken, das von der Kubernetes-Community viel genutzt wird. Sie können die Erfassung von Prometheus-Metriken in Azure Monitor konfigurieren, anstatt Ihren eigenen Prometheus-Server zu hosten. So ermöglichen Sie die Aggregation von Metriken aus Ihren Anwendungen und die automatisierte Reaktion auf anomale Bedingungen bzw. deren Eskalation.

  • Entwerfen und implementieren Sie eine Strategie für Geschäftskontinuität und Notfallwiederherstellung. Bei unternehmenskritischen Anwendungen sollten Sie erwägen, eine Bereitstellungsarchitektur mit mehreren Regionen zu verwenden.

  • Informieren Sie sich über die Richtlinie zur Unterstützung der Kubernetes-Version. Wir sind dafür verantwortlich, Ihren AKS-Cluster zu aktualisieren und auf dem neuesten Stand zu halten, damit sichergestellt ist, dass immer eine unterstützte Version ausgeführt wird.

  • Sorgen Sie dafür, dass alle Teammitglieder, die für die Clusterverwaltung und Anwendungsentwicklung zuständig sind, über die entsprechenden bewährten Methoden für AKS informiert sind.

  • Sehen Sie sich die Elemente in der Datei logging.properties an. Erwägen Sie, einen Teil der Protokollierungsausgabe zu entfernen bzw. zu reduzieren, um die Leistung zu verbessern.

  • Sie haben auch die Möglichkeit, die Größe des Codecaches zu überwachen und der Variablen JAVA_OPTS in der Dockerfile die Parameter -XX:InitialCodeCacheSize und -XX:ReservedCodeCacheSize hinzuzufügen, um die Leistung weiter zu optimieren.