Remarques :
- Ce tutoriel nécessite un accès à Oracle Cloud. Pour vous inscrire à un compte gratuit, reportez-vous à Introduction au niveau gratuit d'Oracle Cloud Infrastructure.
- Il utilise des exemples de valeur pour les informations d'identification, la location et les compartiments Oracle Cloud Infrastructure. A la fin de l'exercice, remplacez ces valeurs par des valeurs propres à votre environnement cloud.
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
-
Créez une application à partir de la console OCI.
-
Créez plusieurs fonctions dans cette application qui sont basées sur plusieurs langages de programmation, dans notre cas Java et Python.
-
Appelez une fonction à partir d'autres fonctions pour servir l'objectif d'une application back-end multicouche développée à l'aide de plusieurs langages de programmation.
Prérequis
-
Disposez des droits d'accès requis autorisés dans Oracle Cloud Infrastructure Identity and Access Management (OCI IAM). Les ressources requises sont autorisées à créer et appeler des applications et des fonctions, ainsi que les stratégies IAM et les groupes dynamiques requis.
-
Accès à tous les composants requis pour visualiser leurs OCID et d'autres informations pertinentes.
-
Accès à OCI Cloud Shell ou au client comme putty à l'aide duquel l'utilisateur peut accéder aux fonctions pour développer le code.
Tâche 1 : créer les groupes dynamiques et les stratégies requis
-
Accédez à la console OCI et accédez à Identité et sécurité, Identité, Groupe dynamique, puis cliquez sur Créer un groupe dynamique.
-
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.
-
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éé.
-
Accédez à Identité et sécurité, Identité, Stratégies et cliquez sur Créer une stratégie.
-
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.
-
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
-
Accédez à la console OCI et à Services de développeur, à Fonctions, à Applications, puis cliquez sur Créer une application.
-
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.
-
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.
-
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.
-
Pour vérifier que vous êtes connecté à OCI Functions, vous devez pouvoir vous connecter et déclencher la commande suivante.
fn list apps
-
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
-
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.
-
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(); } } }
-
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")
Liens connexes
Remerciements
- Auteur - Lovelesh Saxena (Architecte Cloud Engineering)
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.
Host Multi-Tier Backend Applications On Oracle Cloud Infrastructure Functions
F89851-01
November 2023
Copyright © 2023, Oracle and/or its affiliates.