Nota
- Questa esercitazione richiede l'accesso a Oracle Cloud. Per iscriverti a un account gratuito, consulta Inizia a utilizzare Oracle Cloud Infrastructure Free Tier.
- Utilizza valori di esempio per le credenziali, la tenancy e i compartimenti di Oracle Cloud Infrastructure. Al termine del laboratorio, sostituisci questi valori con quelli specifici del tuo ambiente cloud.
Ospita applicazioni backend di più livelli su Oracle Cloud Infrastructure Functions
Introduzione
Oracle Cloud Infrastructure Functions (OCI Functions) è una piattaforma completamente gestita, multi-tenant, altamente scalabile, on-demand e Functions-as-a-Service. Si basa su Oracle Cloud Infrastructure (OCI) di livello aziendale e si basa sul motore open source di Fn Project. Utilizza OCI Functions quando vuoi concentrarti sulla scrittura di codice per soddisfare le esigenze aziendali. L'architettura serverless ed elastica di OCI Functions significa che non c'è amministrazione dell'infrastruttura o amministrazione del software da eseguire. Non esegui il provisioning o la gestione delle istanze di computazione e le patch e gli upgrade del software del sistema operativo vengono applicati automaticamente. OCI Functions garantisce semplicemente che la tua applicazione sia altamente disponibile, scalabile, sicura e monitorata. Con OCI Functions, puoi scrivere codice in Java, Python, Node, Go, Ruby e C# (e per casi d'uso avanzati, porta il tuo file Docker e la tua VM Graal). Puoi quindi distribuire il codice, chiamarlo direttamente o attivarlo in risposta agli eventi e ricevere la fatturazione solo per le risorse utilizzate durante l'esecuzione.
Mentre lavori in OCI o in qualsiasi altro cloud, può essere necessario ospitare il codice backend delle tue applicazioni su un'architettura serverless e per questo è possibile utilizzare le funzioni OCI. Si supponga, ad esempio, che l'applicazione disponga di più componenti backend sviluppati da più team. Un team sviluppa i propri componenti in Java mentre un altro utilizza Python. Puoi spostare questi più componenti dell'applicazione in OCI Functions e quindi chiamarli utilizzando gli endpoint API.
Obiettivi
-
Creare un'applicazione da OCI Console.
-
Crea più funzioni in quell'applicazione basate su più linguaggi di programmazione, nel nostro caso Java e Python.
-
Richiama la funzione da altre funzioni per servire lo scopo dell'applicazione backend multilivello sviluppata utilizzando più linguaggi di programmazione.
Prerequisiti
-
Disporre delle autorizzazioni di accesso necessarie consentite in Oracle Cloud Infrastructure Identity and Access Management (OCI IAM). Le risorse necessarie sono autorizzate a creare e richiamare applicazioni e funzioni, nonché i criteri IAM e i gruppi dinamici necessari.
-
Accedi a tutti i componenti necessari per visualizzare i relativi OCID e altre informazioni pertinenti.
-
Accesso a OCI Cloud Shell o client come putty utilizzando il quale l'utente può accedere alle funzioni per sviluppare il codice.
Task 1: creare i gruppi dinamici e i criteri richiesti
-
Andare alla console OCI e andare a Identità e sicurezza, Identità, Gruppo dinamico, quindi fare clic su Crea gruppo dinamico.
-
Immettere dettagli quali Nome, Descrizione e Regole di corrispondenza per il gruppo dinamico. Aggiungere attentamente i dettagli delle regole in quanto definiranno la risorsa che otterrà l'accesso in quale compartimento.
-
Salvare i dettagli per il gruppo dinamico e attendere la creazione del gruppo dinamico con i dettagli sulla console OCI. Una volta creato il gruppo dinamico, procedere con la creazione dei criteri IAM per il gruppo dinamico appena creato.
-
Passare a Identità e sicurezza, Identità, Criteri e fare clic su Crea criterio.
-
Immettere dettagli quali Nome, Descrizione e Compartimenti per il gruppo dinamico. Aggiungere attentamente i dettagli dei criteri in quanto definiranno l'altra risorsa a cui la funzione può accedere in quale compartimento.
-
Salvare i dettagli per i criteri e attendere che i criteri vengano creati con i dettagli su OCI Console. Una volta creato il criterio, procedere per creare l'applicazione e la funzione.
Task 2: Creare applicazioni e funzioni con più linguaggi di programmazione
-
Andare a OCI Console e andare a Servizi per sviluppatori, Funzioni, Applicazioni, quindi fare clic su Crea applicazione.
-
Immettere dettagli quali Nome, VCN, Subnet e Forma per l'applicazione. Selezionare la VCN e la subnet tenendo conto della rete in quanto renderanno l'applicazione disponibile per essere richiamata all'interno delle reti consentite.
-
Salvare i dettagli per l'applicazione e attendere la creazione dell'applicazione con i dettagli sulla console OCI. Una volta creata l'applicazione, procedere per creare le funzioni su di essa.
-
Passare a Risorse e fare clic su Applicazioni. Troverete tutti i comandi necessari per connettersi con l'applicazione creata e creare la funzione. È possibile selezionare qualsiasi opzione da Impostazione Cloud Shell o Impostazione locale, selezionare Impostazione Cloud Shell per questa esercitazione.
-
Per verificare di essersi connessi a OCI Functions, dovresti essere in grado di connetterti e attivare il comando seguente.
fn list apps
-
Crea un paio di funzioni in più linguaggi di programmazione come Java e Python e aggiungi il codice in base alle tue esigenze aziendali.
fn init --runtime python getStreamData fn init --runtime java pushObjectStorageFile fn init --runtime java getADWSecret fn init --runtime python pushADWData
-
Abbiamo creato quattro diverse funzioni, due in Java e due in Python. Assicurarsi di aver distribuito il codice e di aver verificato che funzioni come previsto richiamandolo manualmente.
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
Il flusso di questa applicazione backend è la nostra applicazione primaria che produrrà alcuni dati in streaming e i dati verranno utilizzati dalla funzione getStreamData
scritta in Python. Successivamente, invieremo i dati allo storage degli oggetti OCI come file e otterremo la password segreta per Autonomous Data Warehouse. Successivamente, invieremo i dati ad Autonomous Data Warehouse per ulteriori elaborazioni e analisi.
Nel Task 3, vedremo come possiamo aggiungere l'invocazione di funzioni basate su Java e Python nel nostro codice applicazione e funzione in modo da poter creare un flusso.
Task 3: Aggiungi codice per richiamare una funzione da un'altra funzione
Puoi chiamare o richiamare una funzione da un'altra funzione utilizzando gli SDK OCI. Gli snippet di esempio sono scritti in Java e Python e possono essere utilizzati in base alla logica aziendale.
-
Aggiungere il seguente frammento di codice per il kit SDK (Software Development Kit) Java.
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(); } } }
-
Aggiungere il seguente snippet di codice per l'SDK Python.
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")
Collegamenti correlati
Conferme
- Autore - Lovelesh Saxena (architetto di cloud engineering)
Altre risorse di apprendimento
Esplora altri laboratori su docs.oracle.com/learn o accedi a più contenuti gratuiti sulla formazione su Oracle Learning YouTube channel. Inoltre, visita education.oracle.com/learning-explorer per diventare Oracle Learning Explorer.
Per la documentazione del prodotto, visitare Oracle Help Center.
Host Multi-Tier Backend Applications On Oracle Cloud Infrastructure Functions
F89851-01
November 2023
Copyright © 2023, Oracle and/or its affiliates.