附註:
- 此教學課程需要存取 Oracle Cloud。若要註冊免費帳戶,請參閱開始使用 Oracle Cloud Infrastructure Free Tier 。
- 它使用 Oracle Cloud Infrastructure 憑證、租用戶及區間的範例值。完成實驗室時,請以雲端環境特有的值取代這些值。
在 Oracle Cloud Infrastructure Functions 上代管多層後端應用程式
簡介
Oracle Cloud Infrastructure Functions (OCI Functions) 是一個完全託管的多租用戶,可高度擴展,可隨選函數即服務平台。它是以企業級 Oracle Cloud Infrastructure (OCI) 為基礎,由 Fn Project 開放原始碼引擎提供技術支援。若要專注於撰寫程式碼以滿足業務需求,請使用 OCI Functions。OCI Functions 的無伺服器和彈性架構代表您沒有基礎架構管理或軟體管理可供執行。您無需佈建或維護運算執行處理,也會自動套用作業系統軟體修補程式和升級。OCI Functions 可確保您的應用程式具有高可用性、可擴展、安全和監控性。透過 OCI Functions,您可以在 Java、Python、Node、Go、Ruby 和 C# 中編寫程式碼 (以及用於進階使用案例、自備 Docker 檔案和 Graal VM)。接著您可以部署程式碼、直接呼叫或觸發程式碼以回應事件,並只針對執行期間使用的資源計費。
在 OCI 或任何其他雲端工作時,可能需要在無伺服器架構上代管您的應用程式後端程式碼,而 OCI Functions 可用於此架構。例如,假設您的應用程式有多個由多個團隊開發的後端元件。一個團隊在 Java 中開發其元件,另一個團隊則使用 Python。您可以將這些多個應用程式元件移至 OCI 函數,然後使用 API 端點呼叫它們。
目標
-
從 OCI 主控台建立應用程式。
-
在 Java 和 Python 案例中,於該應用程式中建立多個以多個程式設計語言為基礎的函數。
-
從其他函數呼叫函數,以使用多個程式設計語言開發的多層後端應用程式。
必要條件
-
在 Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) 中具備必要的存取權限。允許建立及呼叫應用程式和函數所需的資源,以及所需的 IAM 原則和動態群組。
-
存取所有必要的元件以檢視其 OCID 和其他相關資訊。
-
存取 OCI Cloud Shell 或從屬端 (例如 putty),讓使用者能夠存取功能來開發程式碼。
作業 1:建立必要的動態群組和原則
-
前往 OCI 主控台並瀏覽至識別與安全、識別、動態群組,然後按一下建立動態群組。

-
輸入詳細資訊,例如動態群組的名稱、描述和比對規則。請仔細新增規則詳細資訊,因為它們將定義將在其中存取區間的資源。

-
儲存「動態群組」的詳細資訊,並等待在 OCI 主控台上使用詳細資訊建立「動態群組」的時間。建立「動態群組」之後,請繼續建立此新建立之「動態群組」的 IAM 原則。
-
瀏覽至識別與安全、識別、原則,然後按一下建立原則。

-
輸入「動態群組」的詳細資訊,例如名稱、描述和區間。請仔細新增原則詳細資訊,因為它們會定義函數可在其中存取之區間的其他資源。


-
儲存原則的詳細資訊,並等待使用 OCI 主控台的詳細資訊建立原則的時間。建立「原則」之後,請繼續建立應用程式和函數。
作業 2:使用多種程式設計語言建立應用程式和函數
-
前往 OCI 主控台並瀏覽至開發人員服務、函數、應用程式,然後按一下建立應用程式。

-
輸入應用程式的詳細資訊,例如名稱、VCN 、子網路以及資源配置。將網路納入考量以選取 VCN 和子網路,讓您的應用程式可以在允許的網路內呼叫。

-
儲存應用程式的詳細資訊,並等待以 OCI 主控台的詳細資訊建立應用程式的時間。建立「應用程式」之後,請往前移動以在其上建立函數。

-
瀏覽至資源,然後按一下應用程式。您將會找到與建立的應用程式及建立函數連線所需的所有命令。您可以從 Cloud Shell 設定或本機設定選取任何選項,為此教學課程選取 Cloud Shell 設定。

-
若要驗證您已連線至 OCI 函數,您應該能夠連線並觸發下列命令。
fn list apps
-
使用多種程式設計語言 (例如 Java 和 Python) 建立一些函數,並根據您的業務需求新增程式碼。
fn init --runtime python getStreamData fn init --runtime java pushObjectStorageFile fn init --runtime java getADWSecret fn init --runtime python pushADWData -
我們在 Java 中建立了四個不同的函數,在 Python 中則是兩個。請手動呼叫程式碼,確定您已部署程式碼並驗證程式碼是否如預期般運作。
cd getStreamData fn -v deploy --app oci-app-demo fn invoke oci-app-demo getStreamDatacd pushObjectStorageFile fn -v deploy --app oci-app-demo fn invoke oci-app-demo pushObjectStorageFilecd getADWSecret fn -v deploy --app oci-app-demo fn invoke oci-app-demo getADWSecretcd pushADWData fn -v deploy --app oci-app-demo fn invoke oci-app-demo pushADWData
此後端應用程式的流程是我們的主要應用程式,將在串流中產生部分資料,資料將由以 Python 撰寫的 getStreamData 函數使用。接著,我們將以檔案形式將資料推送至 OCI Object Storage,並取得 Autonomous Data Warehouse 的密碼。接著我們將資料發送到 Autonomous Data Warehouse,以進行進一步的處理和分析。
在任務 3 中,我們將瞭解如何將 Java 和 Python 型函數呼叫新增至我們的應用程式和函數代碼,以便我們能夠建立流程。
作業 3:新增程式碼以從其他函數呼叫一個函數
您可以使用 OCI SDK 從另一個函數呼叫或呼叫一個函數。程式碼片段範例是以 Java 和 Python 撰寫,可依據您的商業邏輯使用。
-
新增下列 Java 軟體開發套件 (SDK) 程式碼片段。
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(); } } } -
新增下列 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")
相關連結
認可
- 作者 - Lovelesh Saxena (雲端工程架構師)
其他學習資源
瀏覽 docs.oracle.com/learn 的其他實驗室,或前往 Oracle Learning YouTube 頻道存取更多免費學習內容。此外,請造訪 education.oracle.com/learning-explorer 以成為 Oracle Learning Explorer。
如需產品文件,請造訪 Oracle Help Center 。
Host Multi-Tier Backend Applications On Oracle Cloud Infrastructure Functions
F89851-01
November 2023
Copyright © 2023, Oracle and/or its affiliates.