Nota

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

Prerequisiti

Task 1: creare i gruppi dinamici e i criteri richiesti

  1. Andare alla console OCI e andare a Identità e sicurezza, Identità, Gruppo dinamico, quindi fare clic su Crea gruppo dinamico.

    Crea gruppo dinamico

  2. 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.

    Dettagli gruppo dinamico

  3. 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.

  4. Passare a Identità e sicurezza, Identità, Criteri e fare clic su Crea criterio.

    Crea criterio

  5. 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.

    Dettagli sui criteri

    Criteri creati

  6. 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

  1. Andare a OCI Console e andare a Servizi per sviluppatori, Funzioni, Applicazioni, quindi fare clic su Crea applicazione.

    Crea applicazione

  2. 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.

    Dettagli dell'applicazione

  3. 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.

    Applicazione creata

  4. 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.

    Introduzione alla funzione

  5. Per verificare di essersi connessi a OCI Functions, dovresti essere in grado di connetterti e attivare il comando seguente.

    fn list apps
    

    Lista funzioni

  6. 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
    
  7. 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.

  1. 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();
          }
       }
    }
    
    
  2. 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")
    

Conferme

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.