ノート:
- このチュートリアルでは、Oracle Cloudへのアクセスが必要です。無料アカウントにサインアップするには、Oracle Cloud Infrastructure Free Tierの開始を参照してください。
- Oracle Cloud Infrastructureの資格証明、テナンシおよびコンパートメントに例の値を使用します。演習を完了するときは、これらの値をクラウド環境に固有の値に置き換えます。
Oracle Cloud Infrastructure Functionsでの複数層バックエンド・アプリケーションのホスト
イントロダクション
Oracle Cloud Infrastructure Functions (OCI Functions)は、完全に管理された、マルチテナントでスケーラビリティが高いオンデマンドのFunctions-as-a-Serviceプラットフォームです。エンタープライズグレードの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 Functionsに移動し、APIエンドポイントを使用してコールできます。
目的
-
OCIコンソールからアプリケーションを作成します。
-
このアプリケーションでは、JavaおよびPythonの場合、複数のプログラミング言語に基づく複数の関数を作成します。
-
他の関数から関数を呼び出して、複数のプログラミング言語を使用して開発されたマルチレイヤー・バックエンド・アプリケーションの目的に対応します。
前提条件
-
Oracle Cloud Infrastructure Identity and Access Management (OCI IAM)で許可される必要なアクセス権限があります。必要なリソースは、アプリケーションおよびファンクション、必要なIAMポリシーおよび動的グループを作成および起動できます。
-
必要なすべてのコンポーネントにアクセスして、OCIDsおよびその他の関連情報を表示します。
-
どのユーザーがファンクションにアクセスしてコードを開発できるかを使用して、OCI Cloud Shellまたはputtyなどのクライアントにアクセスします。
タスク1: 必要な動的グループおよびポリシーの作成
-
OCIコンソールに移動し、「アイデンティティとセキュリティ」、「アイデンティティ」、「動的グループ」に移動して、「動的グループの作成」をクリックします。
-
動的グループの「名前」、「説明」、「一致ルール」などの詳細を入力します。どのリソースがどのコンパートメントでアクセスを取得するかを定義するため、ルールの詳細を慎重に追加します。
-
動的グループの詳細を保存し、OCIコンソールの詳細とともに動的グループが作成されるまでお待ちください。動的グループが作成されたら、この新しく作成された動的グループのIAMポリシーを作成して進みます。
-
「アイデンティティとセキュリティ」、「アイデンティティ」、「ポリシー」にナビゲートし、「ポリシーの作成」をクリックします。
-
動的グループの「名前」、「摘要」、「コンパートメント」などの詳細を入力します。ポリシー詳細は、ファンクションがどのコンパートメントでアクセスできる他のリソースを定義するため、慎重に追加してください。
-
ポリシーの詳細を保存し、OCIコンソールでポリシーが作成されるまでお待ちください。ポリシーが作成されたら、先に進んでアプリケーションおよびファンクションを作成します。
タスク2: 複数のプログラミング言語を使用したアプリケーションおよびファンクションの作成
-
OCIコンソールに移動し、「開発者サービス」、「ファンクション」、「アプリケーション」に移動して、「アプリケーションの作成」をクリックします。
-
アプリケーションの名前、VCN、サブネット、シェイプなどの詳細を入力します。許可されたネットワーク内でアプリケーションを起動できるようにするため、ネットワーキングを考慮してVCNおよびサブネットを選択します。
-
アプリケーションの詳細を保存し、OCIコンソールの詳細とともにアプリケーションが作成されるまでお待ちください。アプリケーションが作成されたら、先に進んでファンクションを作成します。
-
「リソース」にナビゲートし、「アプリケーション」をクリックします。作成されたアプリケーションに接続してファンクションを作成するために必要なすべてのコマンドが表示されます。「Cloud Shell設定」または「ローカル設定」から任意のオプションを選択し、このチュートリアルで「Cloud Shell設定」を選択します。
-
OCI Functionsに接続したことを確認するには、次のコマンドを接続してトリガーできる必要があります。
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
-
4つの異なる関数(Javaでは2つ、Pythonでは2つ)を作成しました。コードをデプロイし、コードが想定どおりに動作していることを確認するには、手動で呼び出します。
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
このバックエンド・アプリケーションのフローは、ストリーミングでデータを生成するプライマリ・アプリケーションであり、データはPythonで記述されたgetStreamData
関数によって消費されます。次に、データをファイルとしてOCI Object Storageにプッシュし、Autonomous Data Warehouseのシークレット・パスワードを取得します。その後、データをAutonomous Data Warehouseにプッシュして、さらなる処理と分析を行います。
タスク3では、フローを作成できるように、JavaおよびPythonベースの関数呼出しをアプリケーションおよび関数コードに追加する方法を確認します。
タスク3: 別の関数から関数を呼び出すコードの追加
OCI SDKを使用して、1つのファンクションをコールまたは別のファンクションから呼び出すことができます。スニペットの例は、JavaおよびPythonで記述され、ビジネス・ロジックに従って使用できます。
-
Java Software Development Kit (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.