Observação:
- Este tutorial requer acesso ao Oracle Cloud. Para se inscrever em uma conta gratuita, consulte Conceitos básicos do Oracle Cloud Infrastructure Free Tier.
- Ele usa valores de exemplo para credenciais, tenancy e compartimentos do Oracle Cloud Infrastructure. Ao concluir seu laboratório, substitua esses valores por valores específicos do seu ambiente de nuvem.
Hospede Aplicativos de Backend de Várias Camadas no Oracle Cloud Infrastructure Functions
Introdução
O Oracle Cloud Infrastructure Functions (OCI Functions) é uma plataforma Functions-as-a-Service totalmente gerenciada, multi-tenant, altamente escalável, sob demanda. Ela foi criada no OCI (Oracle Cloud Infrastructure) de nível empresarial e desenvolvida pelo mecanismo de código-fonte aberto Fn Project. Use o OCI Functions quando quiser se concentrar na gravação de código para atender às necessidades do negócio. A arquitetura sem servidor e elástica do OCI Functions significa que não há administração de infraestrutura ou administração de software para você executar. Você não provisiona nem mantém instâncias de computação, e patches e atualizações de software do sistema operacional são aplicados automaticamente. O OCI Functions simplesmente garante que seu aplicativo esteja altamente disponível, escalável, seguro e monitorado. Com o OCI Functions, você pode escrever código em Java, Python, Node, Go, Ruby e C# (e para casos de uso avançados, trazer seu próprio arquivo Docker e Graal VM). Em seguida, você poderá implantar o código, chamá-lo diretamente ou acioná-lo em resposta a eventos e será faturado somente pelos recursos consumidos durante a execução.
Enquanto trabalha na OCI ou em qualquer outra nuvem, pode haver um requisito para hospedar o código de backend de seus aplicativos em uma arquitetura sem servidor e o OCI Functions pode ser usado para ele. Por exemplo, vamos supor que seu aplicativo tenha vários componentes de backend desenvolvidos por várias equipes. Uma equipe desenvolve seus componentes em Java, enquanto outra usa Python. Você pode mover esses vários componentes de aplicativo para o OCI Functions e chamá-los usando pontos finais de API.
Objetivos
-
Crie um aplicativo na Console do OCI.
-
Crie várias funções nesse aplicativo que são baseadas em várias linguagens de programação, no nosso caso Java e Python.
-
Chame a função de outras funções para atender ao propósito do aplicativo de backend multicamadas desenvolvido usando várias linguagens de programação.
Pré-requisitos
-
Ter permissões de acesso necessárias permitidas no Oracle Cloud Infrastructure Identity and Access Management (OCI IAM). Os recursos necessários têm permissão para criar e chamar aplicativos e funções, bem como políticas de IAM e Grupos Dinâmicos necessários.
-
Acesso a todos os componentes necessários para exibir seus OCIDs e outras informações relevantes.
-
Acesso ao OCI Cloud Shell ou putty do cliente usando qual usuário pode acessar as funções para desenvolver o código.
Tarefa 1: Criar Grupos Dinâmicos e Políticas obrigatórios
-
Vá para a Console do OCI, navegue até Identidade e Segurança, Identidade, Grupo Dinâmico e clique em Criar Grupo Dinâmico.
-
Informe detalhes como Nome, Descrição e Regras de Correspondência para seu Grupo Dinâmico. Adicione detalhes de regras com cuidado, pois elas definirão qual recurso obterá o acesso em qual compartimento.
-
Salve os detalhes do Grupo Dinâmico e aguarde o momento em que o Grupo Dinâmico for criado com os detalhes na console do OCI. Depois que o Grupo Dinâmico for criado, avance com a criação das políticas de IAM para esse Grupo Dinâmico recém-criado.
-
Navegue até Identidade e Segurança, Identidade, Políticas e clique em Criar Política.
-
Informe detalhes como Nome, Descrição e Compartimentos para seu Grupo Dinâmico. Adicione detalhes da política com cuidado, pois eles definirão qual outro recurso sua função pode acessar em qual compartimento.
-
Salve os detalhes das Políticas e aguarde o momento em que elas são criadas com os detalhes na console do OCI. Depois que a Política for criada, avance para criar o aplicativo e a função.
Tarefa 2: Criar Aplicativo e Funções com várias linguagens de programação
-
Vá para a Console do OCI, navegue até Developer Services, Functions, Applications e clique em Create application.
-
Informe detalhes como Nome, VCN, Sub-rede e Forma do seu aplicativo. Selecione a VCN e a Sub-rede levando em consideração a rede, pois eles disponibilizarão seu aplicativo para ser chamado nas redes permitidas.
-
Salve os detalhes do Aplicativo e aguarde o momento em que o Aplicativo é criado com os detalhes na console do OCI. Depois que o Aplicativo for criado, avance para criar as funções nele.
-
Navegue até Recursos e clique em Aplicativos. Você encontrará todos os comandos necessários para se conectar ao aplicativo criado e criar a função. Você pode selecionar qualquer opção em Configuração do Cloud Shell ou Configuração Local; selecione Configuração do Cloud Shell para este tutorial.
-
Para verificar se você se conectou ao OCI Functions, poderá conectar e acionar o comando a seguir.
fn list apps
-
Crie algumas funções em várias linguagens de programação, como Java e Python, e adicione o código de acordo com seus requisitos de negócios.
fn init --runtime python getStreamData fn init --runtime java pushObjectStorageFile fn init --runtime java getADWSecret fn init --runtime python pushADWData
-
Criamos quatro funções diferentes, duas em Java e duas em Python. Certifique-se de implantar o código e verificar se ele está funcionando conforme esperado, chamando-o 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
O fluxo desse aplicativo de backend é nosso aplicativo principal que produzirá alguns dados no streaming e os dados serão consumidos pela função getStreamData
gravada em Python. Em seguida, enviaremos os dados para o OCI Object Storage como um arquivo e obteremos a senha secreta do Autonomous Data Warehouse. Em seguida, enviaremos os dados para o Autonomous Data Warehouse para processamento e análise adicionais.
Na Tarefa 3, veremos como podemos adicionar a chamada de função baseada em Java e Python em nosso aplicativo e código de função para que possamos criar um fluxo.
Tarefa 3: Adicionar código para chamar uma função de outra
Você pode chamar ou chamar uma função de outra função usando SDKs do OCI. Os exemplos de snippets são escritos em Java e Python e podem ser usados de acordo com sua lógica de negócios.
-
Adicione o trecho de código a seguir para o SDK (Java Software Development Kit).
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(); } } }
-
Adicione o trecho de código a seguir para o Python SDK.
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")
Links Relacionados
Agradecimentos
- Autor - Lovelesh Saxena (Arquiteto de Engenharia em Nuvem)
Mais Recursos de Aprendizagem
Explore outros laboratórios em docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal Oracle Learning YouTube. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.
Para obter a documentação do produto, visite o Oracle Help Center.
Host Multi-Tier Backend Applications On Oracle Cloud Infrastructure Functions
F89851-01
November 2023
Copyright © 2023, Oracle and/or its affiliates.