Remarques :

Héberger des applications back-end à plusieurs niveaux sur Oracle Cloud Infrastructure Functions

Introduction

Oracle Cloud Infrastructure Functions (OCI Functions) est une plate-forme Functions-as-a-Service entièrement gérée, colocative, hautement évolutive et à la demande. Elle repose sur Oracle Cloud Infrastructure (OCI) de niveau entreprise et sur le moteur open source du projet Fn. Utilisez OCI Functions lorsque vous voulez écrire du code pour répondre aux besoins de votre entreprise. L'architecture sans serveur et élastique d'OCI Functions signifie qu'aucune administration d'infrastructure ou de logiciel n'est nécessaire. Vous ne provisionnez ni ne gérez d'instances de calcul, et les mises à niveau et les patches logiciels de système d'exploitation sont appliqués automatiquement. OCI Functions garantit simplement que votre application est hautement disponible, évolutive, sécurisée et surveillée. Avec OCI Functions, vous pouvez écrire du code en Java, Python, Node, Go, Ruby et C# (et, pour des cas d'utilisation avancés, utilisez votre propre fichier Docker et machine virtuelle Graal). Vous pouvez ensuite déployer votre code, l'appeler directement ou le déclencher en réponse à des événements, et payer uniquement les ressources consommées pendant l'exécution.

Tout en travaillant dans OCI ou tout autre cloud, il peut être nécessaire d'héberger le code back-end de vos applications sur une architecture sans serveur et OCI Functions peut être utilisé pour cela. Par exemple, supposons que votre application comporte plusieurs composants back-end qui sont développés par plusieurs équipes. Une équipe développe ses composants en Java tandis qu'une autre utilise Python. Vous pouvez déplacer ces composants d'application vers OCI Functions, puis les appeler à l'aide d'adresses d'API.

Objectifs

Prérequis

Tâche 1 : créer les groupes dynamiques et les stratégies requis

  1. Accédez à la console OCI et accédez à Identité et sécurité, Identité, Groupe dynamique, puis cliquez sur Créer un groupe dynamique.

    Créer un groupe dynamique

  2. Entrez des détails tels que Nom, Description et Règles de correspondance pour votre groupe dynamique. Ajoutez soigneusement les détails des règles car elles définiront la ressource qui obtiendra l'accès dans quel compartiment.

    Détails du groupe dynamique

  3. Enregistrez les détails du groupe dynamique et attendez que le groupe soit créé avec les détails sur la console OCI. Une fois le groupe dynamique créé, poursuivez la création des stratégies IAM pour ce groupe dynamique nouvellement créé.

  4. Accédez à Identité et sécurité, Identité, Stratégies et cliquez sur Créer une stratégie.

    Créer une stratégie

  5. Entrez des détails tels que le nom, la description et les compartiments de votre groupe dynamique. Ajoutez soigneusement les détails de stratégie car ils définiront l'autre ressource à laquelle votre fonction peut accéder dans quel compartiment.

    Détails de la stratégie

    Stratégie créée

  6. Enregistrez les détails des stratégies et attendez qu'ils soient créés avec les détails sur la console OCI. Une fois la stratégie créée, avancez pour créer l'application et la fonction.

Tâche 2 : créer une application et des fonctions avec plusieurs langages de programmation

  1. Accédez à la console OCI et à Services de développeur, à Fonctions, à Applications, puis cliquez sur Créer une application.

    Créer une application

  2. Entrez des détails tels que Nom, VCN, Sous-réseau et Forme pour votre application. Sélectionnez le VCN et le sous-réseau en tenant compte de la mise en réseau car ils rendront votre application disponible pour être appelée dans les réseaux autorisés.

    Détails d'une application

  3. Enregistrez les détails de l'application et attendez que l'application soit créée avec les détails sur la console OCI. Une fois l'application créée, avancez pour créer les fonctions qui s'y rapportent.

    Application créée

  4. Accédez à Ressources et cliquez sur Applications. Vous trouverez toutes les commandes dont vous avez besoin pour vous connecter à l'application créée et créer une fonction. Vous pouvez sélectionner n'importe quelle option dans Configuration de Cloud Shell ou Configuration locale, puis sélectionnez Configuration de Cloud Shell pour ce tutoriel.

    Introduction à la fonction

  5. Pour vérifier que vous êtes connecté à OCI Functions, vous devez pouvoir vous connecter et déclencher la commande suivante.

    fn list apps
    

    Liste de fonctions

  6. Créez quelques fonctions dans plusieurs langages de programmation tels que Java et Python et ajoutez le code en fonction de vos besoins.

    fn init --runtime python getStreamData
    fn init --runtime java pushObjectStorageFile
    fn init --runtime java getADWSecret
    fn init --runtime python pushADWData
    
  7. Nous avons créé quatre fonctions différentes, deux en Java et deux en Python. Assurez-vous d'avoir déployé le code et de vérifier qu'il fonctionne comme prévu en l'appelant manuellement.

    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
    

Le flux de cette application back-end est notre application principale qui produira des données en streaming et les données seront consommées par la fonction getStreamData écrite en Python. Nous propagerons ensuite les données vers OCI Object Storage en tant que fichier et obtiendrons le mot de passe secret pour Autonomous Data Warehouse. Nous transmettrons ensuite les données à Autonomous Data Warehouse pour poursuivre les traitements et les analyses.

Dans la tâche 3, nous allons voir comment ajouter un appel de fonction basé sur Java et Python dans notre code d'application et de fonction afin de pouvoir créer un flux.

Tâche 3 : ajouter du code pour appeler une fonction à partir d'une autre fonction

Vous pouvez appeler ou appeler une fonction à partir d'une autre fonction à l'aide des kits SDK OCI. Les exemples de fragments de code sont écrits en Java et Python et peuvent être utilisés conformément à votre logique métier.

  1. Ajoutez le fragment de code suivant pour le kit SDK 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. Ajoutez le fragment de code suivant pour le kit 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")
    

Remerciements

Ressources de formation supplémentaires

Parcourez d'autres ateliers sur docs.oracle.com/learn ou accédez à davantage de contenus de formation gratuits sur le canal Oracle Learning YouTube. De plus, rendez-vous sur education.oracle.com/learning-explorer pour devenir un explorateur Oracle Learning.

Pour obtenir de la documentation sur le produit, visitez Oracle Help Center.