Hinweis:
- Dieses Tutorial erfordert Zugriff auf Oracle Cloud. Informationen zum Registrieren eines kostenlosen Accounts finden Sie unter Erste Schritte mit Oracle Cloud Infrastructure Free Tier.
- Es verwendet Beispielwerte für Oracle Cloud Infrastructure-Zugangsdaten, -Mandanten und -Compartments. Wenn Sie Ihre Übung abgeschlossen haben, ersetzen Sie diese Werte durch spezifische Werte für Ihre Cloud-Umgebung.
Multi-Tier-Backend-Anwendungen in Oracle Cloud Infrastructure Functions hosten
Einführung
Oracle Cloud Infrastructure Functions (OCI Functions) ist eine vollständig verwaltete, mehrmandantenfähige, hoch skalierbare und On-Demand-Funktionalität. Sie basiert auf Oracle Cloud Infrastructure (OCI) für Unternehmen und wird von der Fn-Projekt-Open-Source-Engine unterstützt. Verwenden Sie OCI Functions, wenn Sie sich auf das Schreiben von Code konzentrieren möchten, um die Geschäftsanforderungen zu erfüllen. Die serverlose und elastische Architektur von OCI Functions bedeutet, dass Sie keine Infrastruktur oder Software verwalten müssen. Sie müssen keine Compute-Instanzen bereitstellen oder verwalten, und Softwarepatches und -upgrades für das Betriebssystem werden automatisch angewendet. OCI Functions stellt sicher, dass Ihre Anwendung hochverfügbar, skalierbar und sicher ist sowie überwacht wird. Mit OCI Functions können Sie Code in Java, Python, Node, Go, Ruby und C# schreiben (und bei erweiterten Anwendungsfällen eine eigene Docker-Datei und Graal VM verwenden). Anschließend können Sie Ihren Code bereitstellen, direkt aufrufen oder als Antwort auf Ereignisse auslösen. Außerdem werden nur die während der Ausführung verwendeten Ressourcen abgerechnet.
Bei der Arbeit in OCI oder einer anderen Cloud kann es erforderlich sein, Ihren Anwendungs-Backend-Code auf einer serverlosen Architektur zu hosten, und OCI Functions kann dafür verwendet werden. Angenommen, Ihre Anwendung verfügt über mehrere Backend-Komponenten, die von mehreren Teams entwickelt werden. Ein Team entwickelt seine Komponenten in Java, während ein anderes Python verwendet. Sie können diese mehreren Anwendungskomponenten in OCI Functions verschieben und sie dann mit API-Endpunkten aufrufen.
Ziele
-
Erstellen Sie eine Anwendung in der OCI-Konsole.
-
Erstellen Sie in dieser Anwendung mehrere Funktionen, die auf mehreren Programmiersprachen basieren, in unserem Fall Java und Python.
-
Rufen Sie die Funktion aus anderen Funktionen auf, um den Zweck einer mehrschichtigen Backend-Anwendung zu erfüllen, die mit mehreren Programmiersprachen entwickelt wurde.
Voraussetzungen
-
Sie verfügen über die erforderlichen Zugriffsberechtigungen in Oracle Cloud Infrastructure Identity and Access Management (OCI IAM). Die erforderlichen Ressourcen sind zum Erstellen und Aufrufen von Anwendungen und Funktionen sowie der erforderlichen IAM-Policys und dynamischen Gruppen zulässig.
-
Zugriff auf alle erforderlichen Komponenten, um ihre OCIDs und andere relevante Informationen anzuzeigen.
-
Zugriff auf OCI Cloud Shell oder clientähnlichen PuTTY, mit dem der Benutzer auf die Funktionen zur Codeentwicklung zugreifen kann.
Aufgabe 1: Erforderliche dynamische Gruppen und Policys erstellen
-
Gehen Sie zur OCI-Konsole, navigieren Sie zu Identität und Sicherheit, Identität, Dynamische Gruppe, und klicken Sie auf Dynamische Gruppe erstellen.
-
Geben Sie Details wie Name, Beschreibung und Abgleichsregeln für die dynamische Gruppe ein. Fügen Sie Regeldetails sorgfältig hinzu, da sie definieren, welche Ressource den Zugriff in welchem Compartment erhält.
-
Speichern Sie die Details für die dynamische Gruppe, und warten Sie, bis die dynamische Gruppe mit den Details in der OCI-Konsole erstellt wurde. Nachdem die dynamische Gruppe erstellt wurde, erstellen Sie die IAM-Policys für diese neu erstellte dynamische Gruppe.
-
Navigieren Sie zu Identität und Sicherheit, Identität, Policys, und klicken Sie auf Policy erstellen.
-
Geben Sie Details wie Name, Beschreibung und Compartments für die dynamische Gruppe ein. Fügen Sie Policy-Details sorgfältig hinzu, da sie definieren, auf welche andere Ressource Ihre Funktion in welchem Compartment zugreifen kann.
-
Speichern Sie die Details für die Policys, und warten Sie, bis die Policys mit den Details in der OCI-Konsole erstellt wurden. Nachdem die Policy erstellt wurde, erstellen Sie die Anwendung und Funktion.
Aufgabe 2: Anwendung und Funktionen mit mehreren Programmiersprachen erstellen
-
Gehen Sie zur OCI-Konsole, navigieren Sie zu Entwicklerservices, Funktionen, Anwendungen, und klicken Sie auf Anwendung erstellen.
-
Geben Sie Details wie Name, VCN, Subnetz und Ausprägung für Ihre Anwendung ein. Wählen Sie das VCN und das Subnetz unter Berücksichtigung des Netzwerks aus, damit Ihre Anwendung in den zulässigen Netzwerken aufgerufen werden kann.
-
Speichern Sie Details für die Anwendung, und warten Sie, bis die Anwendung mit den Details in der OCI-Konsole erstellt wurde. Nachdem die Anwendung erstellt wurde, erstellen Sie die zugehörigen Funktionen.
-
Navigieren Sie zu Ressourcen, und klicken Sie auf Anwendungen. Sie finden alle Befehle, die Sie benötigen, um eine Verbindung zur erstellten Anwendung herzustellen und eine Funktion zu erstellen. Sie können eine beliebige Option unter Cloud Shell-Setup oder Lokales Setup auswählen und für dieses Tutorial Cloud Shell-Setup auswählen.
-
Um zu prüfen, ob Sie mit OCI Functions verbunden sind, sollten Sie den folgenden Befehl verbinden und auslösen können.
fn list apps
-
Erstellen Sie einige Funktionen in mehreren Programmiersprachen wie Java und Python, und fügen Sie den Code entsprechend Ihren Geschäftsanforderungen hinzu.
fn init --runtime python getStreamData fn init --runtime java pushObjectStorageFile fn init --runtime java getADWSecret fn init --runtime python pushADWData
-
Wir haben vier verschiedene Funktionen erstellt, zwei in Java und zwei in Python. Stellen Sie sicher, dass Sie den Code bereitgestellt und geprüft haben, ob der Code wie erwartet funktioniert, indem Sie ihn manuell aufrufen.
cd getStreamData fn -v deploy --app oci-app-demo fn invoke oci-app-demo getStreamData
cd pushObjectStorageFile fn -v deploy --app oci-app-demo fn invoke oci-app-demo pushObjectStorageFile
cd getADWSecret fn -v deploy --app oci-app-demo fn invoke oci-app-demo getADWSecret
cd pushADWData fn -v deploy --app oci-app-demo fn invoke oci-app-demo pushADWData
Der Fluss dieser Backend-Anwendung ist unsere primäre Anwendung, die einige Daten im Streaming erzeugt und die Daten von der in Python geschriebenen Funktion getStreamData
konsumiert werden. Anschließend pushen wir die Daten als Datei an OCI Object Storage und erhalten das Secret-Kennwort für Autonomous Data Warehouse. Anschließend werden die Daten zur weiteren Verarbeitung und Analyse an Autonomous Data Warehouse übertragen.
In Aufgabe 3 sehen wir, wie wir Java- und Python-basierten Funktionsaufruf zu unserer Anwendung und unserem Funktionscode hinzufügen können, damit wir einen Ablauf erstellen können.
Aufgabe 3: Code hinzufügen, um eine Funktion aus einer anderen Funktion aufzurufen
Sie können eine Funktion mit OCI-SDKs von einer anderen Funktion aufrufen oder aufrufen. Die Beispiel-Snippets sind in Java und Python geschrieben und können gemäß Ihrer Geschäftslogik verwendet werden.
-
Fügen Sie das folgende Code-Snippet für Java Software Development Kit (SDK) hinzu.
package com.example.fn; import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider; import com.oracle.bmc.objectstorage.ObjectStorage; import com.oracle.bmc.objectstorage.ObjectStorageClient; import com.oracle.bmc.objectstorage.requests.GetObjectRequest; import com.oracle.bmc.objectstorage.responses.GetObjectResponse; import com.oracle.bmc.Region; import com.oracle.bmc.functions.FunctionsInvokeClient; import com.oracle.bmc.functions.FunctionsManagementClient; import com.oracle.bmc.functions.model.FunctionSummary; import com.oracle.bmc.functions.model.ApplicationSummary; import com.oracle.bmc.functions.requests.ListApplicationsRequest; import com.oracle.bmc.functions.responses.ListApplicationsResponse; import com.oracle.bmc.functions.requests.ListFunctionsRequest; import com.oracle.bmc.functions.responses.ListFunctionsResponse; import com.oracle.bmc.functions.requests.InvokeFunctionRequest; import com.oracle.bmc.functions.responses.InvokeFunctionResponse; import com.oracle.bmc.util.StreamUtils; import java.nio.charset.StandardCharsets; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.stream.Collectors; public class HelloFunction { private ObjectStorage objStoreClient = null; final ResourcePrincipalAuthenticationDetailsProvider provider = ResourcePrincipalAuthenticationDetailsProvider.builder().build(); public HelloFunction() { try { objStoreClient = new ObjectStorageClient(provider); } catch (Throwable ex) { System.err.println("Failed to instantiate ObjectStorage client - " + ex.getMessage()); } } public static class GetObjectInfo { private String bucketName; private String name; public String getBucketName() { return bucketName; } public void setBucketName(String bucketName) { this.bucketName = bucketName; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public String handleRequest(GetObjectInfo objectInfo) { String result = "FAILED"; final ResourcePrincipalAuthenticationDetailsProvider provider = ResourcePrincipalAuthenticationDetailsProvider.builder().build(); final Region region = Region.US_PHOENIX_1; final String compartmentId = "ocid1.compartment.oc1..<your_compartment_ocid>"; final String name = "oci-java-sdk-function"; final String payload = "Hii"; if (objStoreClient == null) { System.err.println("There was a problem creating the ObjectStorage Client object. Please check logs"); return result; } try { String nameSpace = System.getenv().get("NAMESPACE"); GetObjectRequest gor = GetObjectRequest.builder() .namespaceName(nameSpace) .bucketName(objectInfo.getBucketName()) .objectName(objectInfo.getName()) .build(); System.err.println("Getting content for object " + objectInfo.getName() + " from bucket " + objectInfo.getBucketName()); GetObjectResponse response = objStoreClient.getObject(gor); result = new BufferedReader(new InputStreamReader(response.getInputStream())) .lines().collect(Collectors.joining("\n")); System.err.println("Finished reading content for object " + objectInfo.getName()); invokeFunction(provider, region, compartmentId, name, payload); } catch (Throwable e) { System.err.println("Error fetching object " + e.getMessage()); result = "Error fetching object " + e.getMessage(); } //invokeFunction(provider, region, compartmentId, name, payload); return result; } public static FunctionSummary getUniqueFunctionByName( final FunctionsManagementClient fnManagementClient, final String compartmentId, final String applicationDisplayName, final String functionDisplayName) throws Exception { final ApplicationSummary application = getUniqueApplicationByName( fnManagementClient, compartmentId, applicationDisplayName); return getUniqueFunctionByName( fnManagementClient, application.getId(), functionDisplayName); } public static FunctionSummary getUniqueFunctionByName( final FunctionsManagementClient fnManagementClient, final String applicationId, final String functionDisplayName) throws Exception { final ListFunctionsRequest listFunctionsRequest = ListFunctionsRequest.builder() .applicationId(applicationId) .displayName(functionDisplayName) .build(); final ListFunctionsResponse listFunctionsResponse = fnManagementClient.listFunctions(listFunctionsRequest); if (listFunctionsResponse.getItems().size() != 1) { throw new Exception( "Could not find function with name " + functionDisplayName + " in application " + applicationId); } return listFunctionsResponse.getItems().get(0); } public static ApplicationSummary getUniqueApplicationByName( final FunctionsManagementClient fnManagementClient, final String compartmentId, final String applicationDisplayName) throws Exception { final ListApplicationsRequest listApplicationsRequest = ListApplicationsRequest.builder() .displayName(applicationDisplayName) .compartmentId(compartmentId) .build(); final ListApplicationsResponse resp = fnManagementClient.listApplications(listApplicationsRequest); if (resp.getItems().size() != 1) { throw new Exception( "Could not find unique application with name " + applicationDisplayName + " in compartment " + compartmentId); } final ApplicationSummary application = resp.getItems().get(0); return application; } private static String invokeFunction( final FunctionsInvokeClient fnInvokeClient, final FunctionSummary function, final String payload) throws Exception { String response; try { System.err.println("Invoking function endpoint - " + function.getInvokeEndpoint()); fnInvokeClient.setEndpoint(function.getInvokeEndpoint()); final InvokeFunctionRequest invokeFunctionRequest = InvokeFunctionRequest.builder() .functionId(function.getId()) .invokeFunctionBody( StreamUtils.createByteArrayInputStream(payload.getBytes())) .build(); final InvokeFunctionResponse invokeFunctionResponse = fnInvokeClient.invokeFunction(invokeFunctionRequest); response = "Done executing func1..."; //StreamUtils.toString( //invokeFunctionResponse.getInputStream(), StandardCharsets.UTF_8); } catch (final Exception e) { e.printStackTrace(); System.err.println("Failed to invoke function: " + e); throw e; } return response; } public static void invokeFunction( final ResourcePrincipalAuthenticationDetailsProvider provider, final Region region, final String compartmentId, final String name, final String payload) throws Exception { final FunctionsManagementClient fnManagementClient = FunctionsManagementClient.builder().region(region).build(provider); final FunctionsInvokeClient fnInvokeClient = FunctionsInvokeClient.builder().build(provider); try { final String appName = "e2e-function-demo"; final String fnName = "java_func2"; final FunctionSummary fn = getUniqueFunctionByName(fnManagementClient, compartmentId, appName, fnName); final String response = invokeFunction(fnInvokeClient, fn, payload); if (response != null) { System.out.println("Response from function: " + response); } } finally { fnInvokeClient.close(); fnManagementClient.close(); } } }
-
Fügen Sie das folgende Code-Snippet für das Python-SDK hinzu.
def trigger_function(): logging.getLogger().info("Reached python function func1...") function_endpoint = "https://932jksmn9.us-ashburn-1.functions.oci.oraclecloud.com" function_ocid = "ocid1.fnfunc.oc1.iad.your_function_ocid" function_body = "Hii" signer = oci.auth.signers.get_resource_principals_signer() client = oci.functions.FunctionsInvokeClient(config={}, signer=signer, service_endpoint=function_endpoint) resp = client.invoke_function(function_id=function_ocid, invoke_function_body=function_body) logging.getLogger().info("Completed calling func2")
Verwandte Links
Danksagungen
- Autor - Lovelesh Saxena (Cloud Engineering Architect)
Weitere Lernressourcen
Lernen Sie andere Übungen auf docs.oracle.com/learn kennen, oder greifen Sie auf weitere kostenlose Lerninhalte im Oracle Learning YouTube Channel zu. Besuchen Sie außerdem education.oracle.com/learning-explorer, um Oracle Learning Explorer zu werden.
Produktdokumentation finden Sie im Oracle Help Center.
Host Multi-Tier Backend Applications On Oracle Cloud Infrastructure Functions
F89851-01
November 2023
Copyright © 2023, Oracle and/or its affiliates.