IBM Cloud Docs
アクションとして使用するアプリの準備

アクションとして使用するアプリの準備

IBM Cloud® Functions が非推奨になりました。 アクション、トリガー、シーケンスなどの既存の Functions エンティティーは引き続き実行されますが、2023 年 12 月 28 日以降、新しい Functions エンティティーを作成することはできません。 既存の Functions エンティティーは、2024 年 10 月までサポートされます。 その日付にまだ存在する Functions エンティティーはすべて削除されます。 詳しくは、 非推奨の概要 を参照してください。

アプリを持ち込むのか、イベントに応答するスクリプトを特別に作成するのかにかかわらず、コードからアクションを作成するためには、コードがいくつかの要件を満たしている必要があります。

プログラミング言語ごとに固有の実行要件がありますが、ほとんどのプログラミング言語には次の一般的な要件が適用されます。

  • コードのエントリー・ポイントの名前は、デフォルトでは main と想定されます。 エントリー・ポイントが main ではない場合は、アクションの作成時にカスタム名を指定できるので、その名前をメモしておいてください。

  • アプリの入力パラメーターとアプリの出力結果は、エンティティー間で受け渡し可能な特定の構造になるように形式設定する必要があります。 この構造は、コードの言語によって異なります。 例えば、Python アプリの場合、入力パラメーターはディクショナリーでなければならず、アプリの結果をディクショナリーとして構造化する必要があります。 パラメーターを構造化オブジェクトに入れてアクションに渡すこともできるからです。 例えば JSON では、nameplace のような特定のフィールドの JSON 値が設定された入力パラメーターを予期するようにコードを構造化することもできます。

    JSON 入力の例

    {"name": "Dorothy", "place": "Kansas"}
    

    JavaScript の例

    function main(params) {
        return {payload:  'Hello, ' + params.person.name + ' from ' + params.person.place};
    }
    
  • アプリに複数のファイルが含まれている場合は、アクションで使用するためにそれらのファイルをまとめて 1 つのファイルにする必要があります。 コードを書き直して 1 つファイルにするか、ファイルや依存関係をパッケージ化して単一のアーカイブ・ファイルにします。 使用するランタイムがサポートされていない場合は、アプリを Docker イメージとしてパッケージ化します。

    コードのコンパイルは必須ではありませんが、ランタイムで可能であれば、コードを事前にコンパイルしておくとパフォーマンスが向上する可能性があります。

JavaScript アプリを準備する

アクションを作成する前に、JavaScript コードの準備を整えます。 コードの構造が適切であることを確認してから、コードをパッケージ化する必要があるかどうかを判断します。

JavaScript コードを構造化する

  • エントリー・ポイントの関数の名前は main と想定されます。 コードの関数が main でない場合は、その名前をメモし、アクションの作成時に指定してください。
  • 複数の入力パラメーターを 1 つの JSON オブジェクトとして渡します。
  • 成功したアクティベーションの結果も JSON オブジェクトですが、アクションが同期非同期かによって異なる方法で返されます。

    function main() {
        return {payload: 'Hello world'};
    }

複数の関数を使用する例

    function main() {
        return { payload: helper() }
    }

    function helper() {
        return new Date();
    }

同期動作の JavaScript コードを構造化する

main 関数が return ステートメントを実行せずに終了するか、promise 以外の値を返す return ステートメントを実行して終了する場合、その JavaScript のアクティベーションは同期的です。

同期コードの例

// each path results in a synchronous activation
function main(params) {
    if (params.payload == 0) {
        return;
    } else if (params.payload == 1) {
        return {payload: 'Hello, World!'};
    } else if (params.payload == 2) {
        return {error: 'payload must be 0 or 1'};
    }
}

非同期動作の JavaScript コードを構造化する

callback 関数では return の後も JavaScript 関数の実行を継続できます。 main 関数が promise を返して終了する場合、JavaScript のアクティベーションは非同期的です。 この場合は、promise が履行または拒否されるまで、システムはそのアクションをまだ実行中であると見なします。 非同期実行の JavaScript 関数では、アクションの中で promise を返すことで、main 関数が戻った後にアクティベーションの結果を返すことができます。

まずは、新規の promise オブジェクトをインスタンス化して、コールバック関数を渡します。 コールバックは、resolve と reject という 2 つの引数を使用します。これらはどちらも関数です。 すべての非同期コードが、そのコールバックに入っていきます。 アクション・ハンドラーの名前は、オブジェクト (またはオブジェクトの Promise) の受け入れおよび戻りの標準的なシグニチャーに準拠していれば、どのような名前でもかまいません。

次の例では、resolve 関数を呼び出して promise を完了させていることがわかります。

function main(args) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve({ done: true });
        }, 2000);
        })
}

次の例は、reject 関数を呼び出して promise を拒否していることがわかります。

function main(args) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            reject({ done: true });
        }, 2000);
        })
}

例の実行内容を詳しく説明します。

  • main 関数が promise を返します。 promise は、アクティベーションがまだ実行されていないけれども後で実行されるということを示すものです。
  • JavaScript 関数 setTimeout() が、2 秒間待機してから promise のコールバック関数を呼び出します。このコールバック関数が非同期コードを表しています。
  • promise のコールバックは、resolve 引数と reject 引数を受け入れます。この 2 つはどちらも関数です。
    • resolve() の呼び出しは、promise を履行し、アクティベーションが正常に実行されたことを示します。
    • reject() の呼び出しは、promise を拒否し、アクティベーションが正常に実行されなかったことを通知するために使用できます。

同期動作と非同期動作を含む JavaScript コードを構造化する

次の例に示すように、入力によって同期的にも非同期的にもなるアクションにすることができます。

function main(params) {
    if (params.payload) {
        // asynchronous activation
        return new Promise(function(resolve, reject) {
          setTimeout(function() {
            resolve({ done: true });
          }, 2000);
        })
        }  else {
        // synchronous activation
        return {done: true};
        }
}

例: JavaScript による外部 API 呼び出し

次の例では、毎日、宇宙のユニークな画像を掲載している NASA Astronomy Picture of the Day (APOD) サービスの外部 API を呼び出しています。

let rp = require('request-promise')

function main(params) {
    const options = {
        uri: "https://api.nasa.gov/planetary/apod?api_key=NNKOjkoul8n1CH18TWA9gwngW1s1SmjESPjNoUFo",
        json: true
    }
    return rp(options)
    .then(res => {
        return { response: res }
    })
}

NASA APOD API への呼び出しが行われ、JSON 結果からフィールドが抽出されます。

次は、アクションを作成し、呼び出してテストします。 以下のサンプル・オブジェクトが返されます。

{
    "copyright": "Eric Houck",
    "date": "2018-03-28",
    "explanation": "Does an alignment like this occur only once in a blue moon? ...",
    "hdurl": "https://apod.nasa.gov/apod/image/1803/MoonTree_Houck_1799.jpg",
    "media_type": "image",
    "service_version": "v1",
    "title": "Blue Moon Tree",
    "url": "https://apod.nasa.gov/apod/image/1803/MoonTree_Houck_960.jpg"
}

JavaScript コードを webpack モジュールと一緒にパッケージ化する

始めに、JavaScript ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

  1. package.json ファイルを作成します。 webpack を開発のための依存関係として追加します。

    {
    "name": "my-action",
    "main": "dist/bundle.js",
    "scripts": {
        "prebuild": "NODE_ENV=development npm install",
        "build": "webpack --config webpack.config.js ",
        "deploy": "ibmcloud fn action update my-action dist/bundle.js --kind nodejs:20",
        "clean": "rm -rf node_modules package-lock.json dist"
    },
    "dependencies": {
        "left-pad": "1.1.3"
    },
    "devDependencies": {
        "webpack": "^5.72.0",
        "webpack-cli": "^4.9.2"
    }
    }
    
  2. 以下の webpack 構成コードを webpack.config.js という名前のファイルに保存します。

    var path = require('path');
    module.exports = {
        entry: './index.js',
        output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
        },
        target: 'node'
    };
    
  3. アプリのコードを準備します。 この例 (index.js という名前のファイルとして保存可能) では、変数 global.main がアプリの main 関数として設定されています。

    function myAction(args) {
        const leftPad = require("left-pad")
        const lines = args.lines || [];
        return { padded: lines.map(l => leftPad(l, 30, ".")) }
    }
    
    global.main = myAction;
    
  4. すべての依存関係をローカルにインストールします。

    npm install
    
    npm run prebuild
    

    ほとんどの npm パッケージでは、npm install を実行すると JavaScript のソースがインストールされますが、中には、プラットフォームに依存するバイナリー・ファイル成果物のインストールとコンパイルを行うパッケージもあります。 この環境は Linux AMD64-based であるため、npm installは同様のプラットフォームで実行する必要があります。 それ以外の場合には、アクション呼び出しが成功しない可能性があります。

  5. webpackバンドルをローカルにビルドします。

    npm run build
    

    ファイル dist/bundle.js が作成され、アクションのソース・コードとしてデプロイされます。

    互換性の問題を回避するために、ランタイムを使用して webpack をビルドできます。 ソース・ディレクトリーで以下のコマンドを使用して、コンテナー内でステップ 4 と 5 を実行します。

    docker run --rm -it --entrypoint "/bin/bash" -v $PWD:/nodejsAction ibmfunctions/action-nodejs-v20:1.0.0 -c "npm run prebuild && npm run build"
    
  6. npm スクリプトまたは ibmcloud fn action update CLI を使用して、アクションを作成します。

    • 以下の npm スクリプトを実行します。

      npm run deploy
      
    • または、以下の IBM Cloud CLI コマンドを実行します。

      ibmcloud fn action update my-action dist/bundle.js --kind nodejs:20
      

    webpack でビルドされたバンドル・ファイルでは、JavaScript の依存関係のみがサポートされています。 バンドルに他の依存関係がある場合、こうした依存関係はファイル bundle.js に含まれていないため、アクションの呼び出しが失敗することがあります。

  7. 以下のいずれかのオプションを使用して、生成された成果物package-lock.jsonnode_modulesおよびdistをクリーンアップできます。

    npm run clean
    

    または

    docker run --rm -it --entrypoint "/bin/bash" -v $PWD:/nodejsAction ibmfunctions/action-nodejs-v20:1.0.0 -c "npm run clean"
    

JavaScript コードを NPM ファイルとしてパッケージ化する

単一の JavaScript ソース・ファイルにすべてのアクション・コードを記述する代わりに、圧縮ファイル形式の npm パッケージとしてコードをパッケージ化することもできます。

始めに、JavaScript ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

  1. ルート・ディレクトリーに、package.jsonファイルとmy-action.jsファイルを作成します。

    package.json

    {
        "name": "my-action",
        "main": "my-action.js",
        "dependencies" : {
        "left-pad" : "1.1.3"
        }
    }
    

    my-action.js

    function myAction(args) {
        const leftPad = require("left-pad")
        const lines = args.lines || [];
        return { padded: lines.map(l => leftPad(l, 30, ".")) }
    }
    
    exports.main = myAction;
    
  2. すべての依存関係をローカルにインストールします。

    npm install <dependency>
    

    ほとんどの npm パッケージでは、npm install を実行すると JavaScript のソースがインストールされますが、中には、プラットフォームに依存するバイナリー・ファイル成果物のインストールとコンパイルを行うパッケージもあります。 この環境は Linux AMD64-based であるため、npm installは同様のプラットフォームで実行する必要があります。 それ以外の場合には、アクション呼び出しが成功しない可能性があります。

  3. すべての依存関係をはじめ、すべてのファイルが含まれているアーカイブを作成します。

    zip -r action.zip *
    

    Windows ユーザー Windows エクスプローラー・アクションを使用して圧縮ファイルを作成すると、誤ったファイル構造になります。Cloud Functions アーカイブ・アクションでは、アーカイブのルートにpackage.jsonがなければなりませんが、Windows Explorer によってネストされたフォルダー内に配置されます。 代わりに、zip コマンドを使用してください。

ネイティブ依存関係を持つ NPM ライブラリー

Node.js ライブラリーは、npm installコマンドを使用してローカル・ランタイム用にインストール時にコンパイルされるネイティブ・モジュールに依存することができます。IBM Cloud ランタイムは、Linux AMD64 プラットフォームに基づいています。このプラットフォームでは、ネイティブ・モジュールがそのプラットフォーム用にコンパイルされている必要があります。 Linux AMD64 ベースのオペレーティング・システムを使用していない場合、nodejs runtime Docker コンテナーを使用して依存関係をインストールできます。

Cloud Functions の zip アクションは 48MB に制限されています。 zip アクションがこの制限値を超える場合、アクション用のカスタム Docker イメージを作成しなければなりません。

  1. 以下のコマンドを実行して、Node.js モジュールを取り出し、ネイティブ依存関係をコンパイルし、zip されたアクション・コード (node_modulesディレクトリーを含む) を作成します。

    docker run --rm -it --entrypoint "/bin/bash" -v $PWD:/nodejsAction ibmfunctions/action-nodejs-v20:1.0.0 -c "npm install && zip action.zip -r *"
    
  2. Cloud Functions CLI を使用してアクションを作成します。

    ibmcloud fn action create my-action action.zip --kind nodejs:20
    

アクションでの ES6 モジュールの使用

新しい ES6 モジュールをアクションで使用する場合は、新しいモジュールをインポートするためのラッパー関数を作成する必要があります。 このラッパーは、インポートするモジュールのグローバル変数と、promise としてモジュールをインポートする関数で構成されています。

さらにロードするには、promise チェーニングを使用して追加の ES6 モジュールをロードします。 変数名 (let module_name) とインポート・コードを追加して、別の ES6 モジュール (.then( () => return import('other_module').then( module => module_name = module.<obj_to_load>))) を追加します。

  1. 以下の内容を含む my-action.js ファイルを作成します。

        let uuidv5;
    
        function main(params) {
            const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
    
            console.log( "uuidv5 =  " + uuidv5)
    
            const triggerID = uuidv5('Hello, World!', MY_NAMESPACE);
            console.log("----> uuid module successfully loaded and trigger calculated  = ", triggerID)
    
            return { message: 'Hello World with id = ' + triggerID };
        }
    
    
        function main_wrapper(params) {
    
            return import('uuid').then(module => uuidv5 = module.v5)
            //.then( () =>   return import('xxxxx').then( module => global_var_yy = module.<obj_to_load>))
            .then( () => {
                return main( params )
            })
        }
    
  2. アクションを作成し、メイン・アクションを main_wrapper に設定します。

    ibmcloud fn action create my-action my-action.js --main main_wrapper
    

    Cloud Functions UI を使用してアクションを作成する場合は、 main_wrapper 関数の名前を main に変更し、 main 関数の名前を他の名前に変更する必要があります。これは、UI の入力関数が常に main であるためです。

    zip アクションを作成する場合は、前のガイドに従って、 exports.main = main_wrapper を使用してエントリー・ポイントを指定してください。

  3. アクションを呼び出します。

    ibmcloud fn action invoke my-action
    

Cloud Functions でデプロイメントするために Python アプリをパッケージ化する方法

Python コードを構造化する

Python アプリは、ディクショナリーを取り込み、ディクショナリーを生成する必要があります。 エントリー・ポイントのメソッドの名前は main と想定されます。 コードの関数が main でない場合は、その名前をメモし、アクションの作成時に指定してください。

def main(args):
	name = args.get("name", "stranger")
	greeting = "Hello " + name + "!"
	print(greeting)
	return {"greeting": greeting}

複数の Python ファイルをアーカイブ内でパッケージ化する

このメソッドを使用する場合

アプリで複数の Python ファイルを使用しているが、基本 Python ランタイムに含まれているパッケージ以外の依存関係やパッケージは必要ないという状況。 Python ファイルが含まれている圧縮ファイルを作成し、アクションの作成時にその圧縮ファイルをデプロイできます。

コマンド例

ibmcloud fn action create <action_name> <compressed_python_files.zip> --kind python:3.11

詳しくは、複数の Python ファイルを圧縮ファイル形式でパッケージ化するを参照してください。

Python コードをローカル仮想環境と一緒に圧縮ファイル形式でパッケージ化する

このメソッドを使用する場合

基本 Cloud FunctionsPython ランタイムに含まれていない依存関係がアプリに必要な場合は、その依存関係を virtualenv フォルダーにインストールし、圧縮ファイルとして圧縮して Cloud Functions にデプロイできます。 codeSizeアクションの制限 に記述されているように、圧縮ファイルは の最大値未満でなければなりません。

コマンド例

ibmcloud fn action create <action_name> <compressed_python_virtualenv.zip> --kind python:3.11

詳しくは、Python コードをローカル仮想環境と一緒に圧縮ファイル形式でパッケージ化するを参照してください。

Python コードを Docker ローカル仮想環境と一緒に圧縮ファイル形式でパッケージ化する

このメソッドを使用する場合

基本 Cloud FunctionsPython ランタイムに含まれていない依存関係がアプリに必要な場合は、Cloud Functions Python ランタイム・イメージ内の Python 環境を使用して、その依存関係を virtualenv フォルダーにインストールできます。 その後、そのフォルダーを圧縮ファイルとして圧縮して Cloud Functions にデプロイできます。 codeSizeアクションの制限に記述されているように、圧縮ファイルは の最大値未満でなければなりません。

コマンド例

圧縮ファイルを使用してアクションを作成します。 <file_path>を、圧縮ファイルのファイル・パスに置き換えます。

ibmcloud fn action create <action_name> <compressed_python_virtualenv.zip> --kind python:3.11

詳しくは、Python コードを Docker 仮想環境と一緒に圧縮ファイル形式でパッケージ化するを参照してください。

カスタム Docker イメージで大きな Python 依存関係をパッケージ化する

このメソッドを使用する場合

基本 Cloud Functions Python ランタイムに含まれていない依存関係がアプリに必要な状況です。 Dockerfile で基本 Cloud Functions イメージを指定できます。また、Docker イメージのビルド時にインストールする依存関係を指定することもできます。 そして、Cloud Functions にアプリをデプロイするときに、そのカスタム Docker イメージを指定します。 ただし、サポートされるのはパブリック Docker イメージだけです。

コマンド例

ibmcloud fn action create <action_name> <app_code.py> --docker <dockerhub_username>/<repo_name>:<tag_name>

codeSizeアクションの制限に記述されているように、アプリ・コードが の最大値を超えている場合は、この方法と複数の Python ファイルを圧縮ファイル形式でパッケージ化する方法を組み合わせてください。

詳しくは、カスタム Docker イメージで大きな Python 依存関係をパッケージ化するを参照してください。

カスタム Docker イメージ内にアプリをパッケージ化する

このメソッドを使用する場合

基本 Cloud Functions Python ランタイムに含まれていない依存関係がアプリに必要であり、アプリ・コードが .zip ファイルに圧縮しても、codeSizeアクションの制限に記述されている の最大値より大きいという状況です。 その場合は、それらの依存関係をカスタム Docker イメージにインストールし、Docker スケルトンの action/exec フォルダーにアプリ・コードを含めることができます。 そして、Cloud Functions にアプリをデプロイするときに、そのカスタム Docker イメージを指定します。 デプロイメント時にアプリ・コードを指定する必要はありません。 ただし、サポートされるのはパブリック Docker イメージだけです。

コマンド例

ibmcloud fn action create <action_name> --docker <dockerhub_username>/<repo_name>:<tag_name>

Python コードをパッケージ化する

以下の各セクションで、Cloud Functions でデプロイメントするために Python アプリをパッケージ化する方法を示すチュートリアルを提供します。

開始前に

Cloud Functions でデプロイメントするために Python アプリをパッケージ化する方法を確認してください。

複数の Python ファイルを圧縮ファイル形式でパッケージ化する

Python コードと依存関係モジュールを圧縮ファイル形式でパッケージ化します。 次の例では、エントリー・ポイントを含むソース・ファイルが __main__.py で、ヘルパー・モジュールが helper.py というファイル内にあります。

始めに、Python ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。

  1. デスクトップに test ディレクトリーを作成します。

  2. 以下のコードを __main__.py というファイルとして test ディレクトリーに保存します。

    from helper import helper
    def main(args):
    return helper(args)
    
  3. 以下のコードを helper.py というファイルとして test ディレクトリーに保存します。 このコードは name パラメーターを受け入れて、挨拶を返します。 name を指定しないと、返される namestranger になります。

    def helper(dict):
        if 'name' in dict:
          name = dict['name']
        else:
          name = "stranger"
        greeting = "Hello from helper.py, " + name + "!"
        return {"greeting": greeting}
    
  4. アプリを圧縮ファイル形式でパッケージ化するには、cd ディレクトリーへの test を実行し、以下のコマンドを実行します。 この例では、アーカイブは stranger.zip です。

    zip -r stranger.zip __main__.py helper.py
    
  5. この圧縮ファイルを使用して、hello というアクションを作成できます。 <file_path>を、圧縮ファイルのファイル・パスに置き換えます。

    ibmcloud fn action create hello <file_path>/test/stranger.zip --kind python:3.11
    
  6. アクションをテストします。

    ibmcloud fn action invoke hello --result
    

    出力例

    {
    "greeting": "Hello from helper.py, stranger!"
    }
    
  7. name パラメーターを指定してアクションをもう一度テストします。 <your_name>パラメーターをご使用の名前に置き換えます。

    ibmcloud fn action invoke hello --result --param name <your_name>
    

    出力例

    {
    "greeting": "Hello from helper.py, <your_name>!"
    }
    

Python コードをローカル仮想環境と一緒に圧縮ファイル形式でパッケージ化する

Python の依存関係は、仮想環境 virtualenv を使用してパッケージ化できます。 仮想環境では、 pipを使用してインストールできる追加パッケージをリンクできます。

ローカル Python 環境をセットアップする場合、作成される圧縮アクション・ファイルに大きな影響があります。 構成によっては (デフォルト以外のインストール・パスや混合 Python インストール済み環境など)、圧縮アクション・ファイルが実行中に失敗する可能性があります。

ローカル環境上でこれらの依存関係を最小化するには、Python コードを Docker 仮想環境と一緒に圧縮ファイルとしてパッケージ化する方法を使用します。 この方法では、圧縮アクション・ファイルを作成しますが、Cloud Functions Python ランタイム・イメージ自体の内部の Python 環境も活用するので、生成したアクション圧縮ファイルとその後の実行環境の両方が完全に一致します。

開始前に

  • 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

  • Python ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。

  • 圧縮アクション・ファイルを作成するためにローカルにインストールされた Python バージョン (例えば、 Python 3.11.x) が、後でアクションを作成するために選択された Cloud Functions の種類 (--kind python:3.11) と一致していることを確認します。

  • virtualenv Python パッケージをインストールします。

    pip install virtualenv
    

アプリをパッケージ化するには、以下のようにします。

  1. 仮想環境の作成に使用できるディレクトリーを作成します。 この例では、jokes ディレクトリーをデスクトップに作成します。 jokes ディレクトリーを作成したら、そのディレクトリーへの cd を実行します。

    cd desktop; mkdir jokes; cd jokes
    
  2. jokes ディレクトリーから、virtualenv という仮想環境を作成します。

    仮想環境の名前は virtualenv でなければなりません。

    virtualenv virtualenv
    

    出力例

    created virtual environment CPython3.9.10.final.0-64 in 398ms
        creator CPython3Posix(dest=/action/Projects/python/virtualenv, clear=False, no_vcs_ignore=False, global=False)
        seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/root/.local/share/virtualenv)
            added seed packages: pip==21.2.4, setuptools==58.0.4, wheel==0.37.0
        activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
    
  3. jokes ディレクトリーから、virtualenv 仮想環境をアクティブにします。

    source virtualenv/bin/activate
    
  4. 仮想環境内の Python バージョンが、後でアクションを作成するときに--kindオプションで指定したバージョンと一致していることを確認します (例えば、python:3.11)。実際のバージョンを確認するには、

    python --version
    
  5. pyjokes モジュールをインストールします。

    (virtualenv) $ pip install pyjokes
    

    出力例

        Collecting pyjokes
            Using cached pyjokes-0.6.0-py2.py3-none-any.whl (26 kB)
        Installing collected packages: pyjokes
        Successfully installed pyjokes-0.6.0
    
  6. virtualenv 仮想環境を停止します。

    (virtualenv) $ deactivate
    
  7. 以下のコードをコピーして、__main__.py ディレクトリー内の jokes というファイルに保存します。

    import pyjokes
    
    def joke(params):
        return {"joke": pyjokes.get_joke()}
    
  8. jokes ディレクトリーから、virtualenv フォルダーと __main__.py ファイルのアーカイブを作成します。 それらのファイルを .zip ファイルのトップレベルに置いてください。

    zip -r jokes.zip virtualenv __main__.py
    

    出力例

    ...
    adding: virtualenv (stored 0%)
    adding: __main__.py (deflated 18%)
    ...
    
  9. jokes ファイルを使用して、jokes.zip というアクションを作成します。 エントリー・ポイントを jokes として指定する必要もあります。 ランタイムの --kind フラグも指定する必要があります。

    ibmcloud fn action create jokes </path/to/file/>jokes.zip --kind python:3.11 --main joke
    

    出力例

    ok: created action jokes
    
  10. アクションを呼び出して、動作していることを確認します。 コマンド・ラインで結果を返すために、--result フラグを指定します。

ibmcloud fn action invoke jokes --result

出力例

{
"joke": "A QA engineer walks into a bar. Runs into a bar. Crawls into a bar. Dances into a bar. Tiptoes into a bar. Rams a bar. Jumps into a bar."
}

この方法を使用すると、他の Python パッケージを使用して Cloud Functions アクションの機能を拡張できます。

Python コードを Docker ローカル仮想環境と一緒にアーカイブとしてパッケージ化する

Python の依存関係は、仮想環境 virtualenv を使用してパッケージ化できます。 仮想環境を使用すると、 pipを使用してインストールできる追加のパッケージをリンクできます。

必須の Python パッケージをさらに追加しようとしている場合は、この方法をお勧めします。 この方法では、生成される圧縮アクション・ファイルと、後でアクションの実行に使用される Python ランタイムとの間に互換性が確保されます。

開始前に

  • Python ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。
  • 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

以下のステップを実行して、アプリをパッケージします。

  1. 仮想環境の作成に使用できるディレクトリーを作成します。 この例では、test ディレクトリーをデスクトップに作成します。 test ディレクトリーを作成したら、そのディレクトリーへの cd を実行します。

    cd desktop; mkdir test; cd test
    
  2. testディレクトリー内のファイルに、インストールするpipモジュールとバージョンを含む requirements.txt 外部リンク・アイコンを作成します。

    touch requirements.txt
    
  3. vim を使用して requirements.txt ファイルを編集します。 インストールする pip モジュールの名前とバージョンを入力します。 この例では、pyjokesが使用されるモジュールです。

    vim requirements.txt
    

    requirements.txt の例

    pyjokes
    
  4. ESC を押し、:wqrequirements.txt ファイルを保存して閉じます。

    virtualenv を最小サイズに抑えるために、requirements.txt には、選択したランタイム環境に含まれていないモジュールのみを追加してください。 Python ランタイムに含まれているパッケージについて詳しくは、Python ランタイムのリファレンスを参照してください。

    • python:3.11の場合は、Docker イメージibmfunctions/action-python-v3.11を使用します。
    • python:3.9の場合は、Docker イメージibmfunctions/action-python-v3.9を使用します。
    • python:3.7の場合は、Docker イメージibmfunctions/action-python-v3.7を使用します。
    • python:3.6の場合は、Docker イメージibmfunctions/action-python-v3.6を使用します。

    docker pull ibmfunctions/action-python-v3.9:1.0.0
    

    出力例

    Using default tag: latest
    latest: Pulling from ibmfunctions/action-python-v3.9:1.0.0
    
  5. 仮想環境を作成し、追加の Python パッケージをインストールします。

    test ディレクトリーに virtualenv フォルダーを作成するには、仮想環境ディレクトリーの名前を virtualenv にする必要があります。

    docker run --rm -v "$PWD:/tmp" --entrypoint "/bin/bash" ibmfunctions/action-python-v3.9:1.0.0 -c "cd /tmp && virtualenv virtualenv && source virtualenv/bin/activate && pip install -r requirements.txt"
    

    このコマンドは、選択されたランタイム・イメージに基づいてコンテナー (docker run) をインスタンス化し、現行作業ディレクトリー ($PWD) を/tmpとしてコンテナー (-v "$PWD:/tmp") にマウントします。コンテナー内で、/tmpディレクトリーcd /tmpに変更し、virtualenv (virtualenv virtualenv && source virtualenv/bin/activate) を作成してアクティブ化し、pip installを実行して選択したパッケージを追加します。 コマンドが完了すると、コンテナーは削除されます (--rm)。作成されたvirtualenvのディレクトリー構造、および最後にインストールされたパッケージは、現行ディレクトリー内のフォルダーvirtualenvにあります。

    出力例

    created virtual environment CPython3.9.10.final.0-64 in 3291ms
        creator CPython3Posix(dest=/tmp/virtualenv, clear=False, no_vcs_ignore=False, global=False)
        seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/root/.local/share/virtualenv)
            added seed packages: pip==21.3.1, setuptools==60.2.0, wheel==0.37.1
        activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
    Collecting pyjokes
        Downloading pyjokes-0.6.0-py2.py3-none-any.whl (26 kB)
    Installing collected packages: pyjokes
    Successfully installed pyjokes-0.6.0
    
  6. 以下のコードを __main__.py として test ディレクトリーに保存します。 圧縮ファイルでアクションを作成する場合は、エントリー・ポイントを含むソース・ファイルを __main__.py という名前にする必要があります。

    import pyjokes
    
    def joke(params):
        return {"joke": pyjokes.get_joke()}
    
  7. このコードをアクションとしてデプロイするには、 virtualenv フォルダーと __main__.py ファイルの圧縮ファイルを作成する必要があります。

    場合によっては、 Cloud Functionsで許可されている アクション制限 で説明されているように、結果の圧縮ファイルが最大 codeSize より大きくなることがあります。 圧縮ファイルのサイズを小さくするために、virtualenv フォルダー全体を選択するのではなく、必要な依存関係だけを選択してください。 必要なパッケージは、site-packages フォルダー内の virtualenv ディレクトリーにあります。 activate_this.py フォルダーの bin ディレクトリーにある virtualenv ファイルも圧縮ファイルに含める必要があります。

    zip -r pyjoke.zip virtualenv __main__.py
    
  8. pyjoke.zipファイルを使用して、pyjokeというアクションを作成します。 使用する --kind が、圧縮アクション・ファイルの作成に使用したランタイム・イメージに対応していることを確認します。 対応していないと、呼び出し中にアクションの実行が失敗します。

    ibmcloud fn action create pyjoke <file_path>/pyjoke.zip --kind python:3.11
    
  9. アクションを呼び出して、pyjokeモジュールが動作していることをテストします。

    ibmcloud fn action invoke pyjoke --result
    

    出力例

    {
        "joke": "A QA engineer walks into a bar. Runs into a bar. Crawls into a bar. Dances into a bar. Tiptoes into a bar. Rams a bar. Jumps into a bar."
    }
    

カスタム Docker イメージで大きな Python 依存関係をパッケージ化する

Cloud Functions にはアプリ・コードに関するサイズ制限があります。codeSizeアクションの制限に記述されている の最大値を参照してください。 ただし、大きなパッケージと依存関係をカスタム Docker イメージにインストールし、アクションの作成時にアプリ・コードと一緒にデプロイすることは可能です。 その後、実行時にパッケージをインポートできます。

この例では、matplotlibseaborn などの大きな Python パッケージをインストールして、seaborn で結合プロットの PNG ファイルを生成する Cloud Functions Web アクションをビルドします。

開始前に

  • Python ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。
  • 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

パブリック Docker イメージだけがサポートされます。

以下の手順を実行して、アプリをカスタム Docker イメージにパッケージ化します。

  1. Dockerfile の作成に使用できるディレクトリーを作成します。 この例では、functions ディレクトリーをデスクトップに作成します。 functions ディレクトリーを作成したら、そのディレクトリーへの cd を実行します。

    cd desktop; mkdir functions; cd functions
    
  2. functionsディレクトリーに Dockerfile 外部リンク・アイコンを作成します。

    touch Dockerfile
    
  3. vim を使用して Dockerfile ファイルを編集します。 インストールする pip モジュールの名前とバージョンを入力します。 この例では、いくつかの追加の Python モジュールがインストールされます。

    vim Dockerfile
    
  4. Dockerfile に以下のテキストを貼り付けるか、入力します。

    FROM ibmfunctions/action-python-v3.9:1.0.0
    
    RUN pip install \
        --upgrade pip \
        matplotlib \
        seaborn \
        pandas \
        statsmodels
    
  5. ESC を押し、:wq を使用し、Enter を押して、Dockerfile を保存して閉じます。

  6. functions ディレクトリーから docker build を実行して、Dockerfile で Docker イメージをビルドできます。

    docker build -t <dockerhub_username>/<repo_name>:<tag_name> .
    

    docker build コマンドを次のフォーマットで実行することもできます。

    docker build . -t <dockerhub_username>/<repo_name>:<tag_name>
    
  7. そのイメージによって、Dockerfile で指定した依存関係がビルドされ、インストールされます。

        [+] Building 0.1s (6/6) FINISHED
        => [internal] load build definition from Dockerfile.ml                                                                                                                    0.0s
        => => transferring dockerfile: 40B                                                                                                                                        0.0s
        => [internal] load .dockerignore                                                                                                                                          0.0s
        => => transferring context: 2B                                                                                                                                            0.0s
        => [internal] load metadata for docker.io/ibmfunctions/action-python-v3.9:1.0.0                                                                                           0.0s
        => [1/2] FROM docker.io/ibmfunctions/action-python-v3.9:1.0.0                                                                                                             0.0s
        => CACHED [2/2] RUN pip install     --upgrade pip     matplotlib     seaborn     pandas     statsmodels                                                                   0.0s
        => exporting to image                                                                                                                                                     0.0s
        => => exporting layers                                                                                                                                                    0.0s
        => => writing image sha256:4a0d140e65fc379d8c25d18fce9aedd580203f768f43da011149993cd57565d4                                                                               0.0s
        => => naming to docker.io/docker-username/repo-name:tag
        ...
        ...
    
  8. イメージを Docker Hub にプッシュします。

    docker push <dockerhub_username>/<repo_name>:<tag_name>
    

    イメージをプッシュする前に、Docker Hub にログインしてください。

  9. 以下のコードを seaborn.py として functions ディレクトリーに保存します。 このコードは、ランダム・データを使用して seaborn 内に結合プロットを生成します。 その後、Cloud Functions で Web アクションを作成して、Cloud Functions エンドポイントにそのプロットを返せます。

    # import modules
    import base64
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    # optional: set seaborn style
    sns.set(style="dark")
    def main(args):
        #generate a jointplot from random data.
        x, y = np.random.randn(2, 300)
        g = (sns.jointplot(x,y, kind="hex", color="#9b59b6")
                .set_axis_labels("x", "y"))
        # save the plot as a .png so that it can be base64 encoded/decoded.
        plt.savefig('output.png')
        # open, read, and encode the image.
        image = base64.b64encode(open("output.png", "rb").read())
        # decode the image into a string.
        data = image.decode('utf-8')
        # return the string as a JSON web request.
        return {
            'body': data,
            'statusCode': 200,
            'isBase64Encoded': 'true',
            'headers': {'Content-Type': 'image/png'}
        }
    
  10. 作成したカスタム Docker イメージを使用して seaborn という Web アクションを作成します。そのイメージには、結合プロットを実行するのに必要な Python 依存関係が含まれています。

ibmcloud fn action create seaborn --docker <dockerhub_username>/<repo_name>:<tag_name> seaborn.py --web true

出力例

ok: created action seaborn
  1. アクションを呼び出してテストします。 アクションを呼び出すと、生成された結合プロットを表す base64 の文字列が返されます。
ibmcloud fn action invoke seaborn --result

出力例

<base64_string>,
    "headers": {
        "Content-Type": "image/png"
    },
    "isBase64Encoded": "true",
    "statusCode": 200
}
  1. このアクションは Web アクションであるため、action get コマンドを使用して URL を返せます。
ibmcloud fn action get seaborn --url

出力例

ok: got action seaborn
https://us-south.functions.cloud.ibm.com/api/v1/web/<namespace_ID>/default/seaborn
  1. URL をコピーしてブラウザーに貼り付け、生成された結合プロットを表示します。 ページを最新表示すると、アクションが呼び出され、新しいプロットが生成されます。

このカスタム Docker イメージをビルドする方法を使用すれば、大きな依存関係を、アプリと一緒にパッケージ化するのではなくインストールすることができます。

アプリを Docker イメージとして準備する

Cloud Functions では、任意の言語でアプリを作成して Docker イメージとしてパッケージ化できます。

使用できるイメージは、パブリック・レジストリーにあるイメージだけです (Docker Hub で公開されているイメージなど)。 プライベート・レジストリーはサポートされません。 考えられるいくつかの回避策について詳しくは、 Large Applications on OpenWhisk および Large(Java)Applications on Apache OpenWhiskを参照してください。

開始前に

  • ユーザーは Docker Hub アカウントを持っている必要があります。 Docker Hubで無料の Docker ID とアカウントをセットアップできます。
  • Dockerをインストールします
  • Docker ランタイムの要件を確認します
  • 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

アクションのカスタム Docker イメージの作成

Dockerfile では、FROM 命令を使用して Cloud Functions 基本ランタイム・イメージを指定できます。 RUN 命令を使用して、Docker イメージにインストールする依存関係とパッケージを指定できます。 Dockerfile の作成について詳しくは、 Dockerfile リファレンスを参照してください。

Docker Hubibmfunctions Docker 基本イメージのリストを確認できます。

Cloud Functions では、アプリ・コードが、codeSizeアクションの制限に記述されている の最大値までに制限されています。

  1. デスクトップに test ディレクトリーを作成し、そのディレクトリーへの cd を実行します。

    cd desktop; mkdir test; cd test
    
  2. test ディレクトリーに Dockerfile を作成し、vim で開きます。

    touch Dockerfile; vim Dockerfile
    
  3. i キーを押して Dockerfile を編集します。

  4. Dockerfile で FROM 引数を使用して Cloud Functions 基本イメージを指定します。

  5. RUN 引数の後に依存関係のインストール・コマンドを指定して、パッケージと依存関係をインストールします。

  6. ESC を押し、:wq を使用し、Enter を押して、Dockerfile を保存して閉じます。

    Python 依存関係をインストールする Dockerfile の例

    以下の例では、ibmfunctions/action-python-v3.7 を基本イメージとして使用し、Python モジュール matplotlibpandasstatsmodels をインストールします。

    FROM ibmfunctions/action-python-v3.7
    
    RUN pip install \
        --upgrade pip \
        matplotlib \
        pandas \
        statsmodels
    
  7. カスタム Docker イメージをビルドします。

    docker build -t <dockerhub_username>/<repo_name>:<tag_name>
    
  8. イメージを Docker Hub にプッシュします。

    docker push <dockerhub_username>/<repo_name>:<tag_name>
    

    イメージをプッシュする前に、Docker Hub にログインしてください。

カスタム Docker イメージによるアクションのデプロイ

Cloud Functions アクションを作成するときに、アプリ・ファイルとパブリック Docker イメージを組み合わせて、カスタム・ランタイム環境を作成できます。 そのアクションは、Docker イメージを使用して呼び出します。

action create コマンドを実行し、--docker フラグを含めて、アプリで使用する Docker イメージを指定します。

ibmcloud fn action create <action_name> --docker <dockerhub_username>/<image_name> <app_file>

Docker イメージと一緒に圧縮ファイルをデプロイして、アクションを作成することもできます。 前のコマンドを使用して、<app_file>を圧縮ファイルに置き換えることができます。 この方法を使用して、大きなアプリ・ファイルをデプロイしたり、大きな依存関係を組み込んだりできます。

Cloud Functions アクションと一緒にカスタム Docker イメージをデプロイする例については、カスタム Docker イメージで大きな Python 依存関係をパッケージ化するを参照してください。

Go アプリを準備する

Golang を使用してアクションを作成できます。

クイック・テストや開発のためには、1 つのファイルを使用します。 実動アプリの場合は、パフォーマンスの向上のために、Go アクションを実行可能ファイルとしてプリコンパイルします。 複数のソース・ファイルから成り、サード・パーティーのライブラリーが含まれるアクションをデプロイするには、これらのアクションを圧縮ファイルとしてパッケージ化し、このファイルをデプロイします。 圧縮ファイルをデプロイする場合は、kindパラメーター (--kind=go:1.21) を使用してランタイムを指定します。

GOOS=LinuxおよびGOARCH=amd64を使用してクロス・コンパイルすることにより、任意の Go プラットフォームで圧縮ファイルを作成できますが、ランタイム・コンテナー・イメージ (docker run -i openwhisk/action-golang-v1.21:nightly ...) に組み込まれているプリコンパイル・フィーチャーを使用してください。複数のソース・ファイルまたは ベンダー・ライブラリーをパッケージ化できます。

以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。 コマンドを実行するためには、ibmcloud cli をインストールしなければなりません。 一部の例では、 Dockerも必要になることに注意してください。

Go アプリを構造化する

Go コードを構造化する場合、エントリー・ポイントのパッケージの予期される名前は main です。 コード内のパッケージがmainでない場合は、アクションの作成時に指定する名前 (--name <your name>) をメモします。パッケージもパブリック (大文字で始まる) でなければなりません。

以下の例では、Go で単純な Hello World アクションを作成します。

    package main

    import "fmt"

    // Main is the function implementing the action
    func Main(params map[string]interface{}) map[string]interface{} {
        // parse the input JSON
        name, ok := params["name"].(string)
        if !ok {
            name = "World"
        }
        msg := make(map[string]interface{})
        msg["body"] = "Hello " + name + "!"
        // can optionally log to stdout (or stderr)
        fmt.Println("hello Go action")
        // return the output JSON
        return msg
    }

Go で作成されたアクションは、ソース・コードとしてデプロイするか、圧縮フォーマットでプリコンパイル済みの実行可能ファイルとしてデプロイすることができます。 アクションに必要なソース・ファイルが 1 つのみの場合、プリコンパイルせずにアクションを作成すると、 IBM Cloud コンソール の「関数」アクション・ウィンドウでその内容を直接編集できます。

Go を使用するアクションを作成するには、以下の手順に従います。

  1. デプロイしようとしている関数を作成します。
  2. (optional) 複数のファイルがある場合は、それらのファイルを圧縮ファイルとしてパッケージ化します。そうでない場合はこのステップをスキップします (以下の例を参照してください)
  3. (optional) Docker イメージ (docker run -i openwhisk/action-golang-v1.21:nightly -compile ...) を使用してgo/zipファイルをコンパイルします。このステップは、実行可能ファイルを含む圧縮ファイルを返します。
  4. ibmcloud cli を使用してアクションを作成します。

これらの手順は、以下の各例で使用されます。

単純な Golang アクションの作成

Go 関数が含まれるファイルを作成して、Go で単純なアクションを作成できます。

  1. 関数が含まれる GO ファイルを作成します。 デフォルトの項目名は Main です。 この名前は、ibmcloud fn action create <action_name> <action_file> --main <function_name>コマンドで--mainパラメーターを使用して指定した場合は、別のパブリック関数名 (Uppercase first character)に変更できます。例えば、関数の名前がHelloの場合は、--main helloになります。

    main.go

    package main
    
    import "fmt"
    
    // Main is the function implementing the action
        func Main(params map[string]interface{}) map[string]interface{} {
          // parse the input JSON
            name, ok := params["name"].(string)
            if !ok {
                name = "World"
          }
            msg := make(map[string]interface{})
            msg["body"] = "Hello " + name + "!"
            // can optionally log to stdout (or stderr)
            fmt.Println("hello Go action")
            // return the output JSON
            return msg
        }
    
  2. (optional) 最初に、圧縮フォーマットで保管される実行可能ファイルに関数をプリコンパイルしようとしている場合は、以下のようにします。

    docker run -i openwhisk/action-golang-v1.21:nightly -compile main <main.go >main-bin.zip
    

    <および>は、bash 入出力リダイレクトであり、コマンドの一部です。

    生成された圧縮ファイル (main-bin.zip) を action create コマンドでファイルとして指定します。

  3. Cloud Functions 管理対象go:1.21ランタイムを使用してアクションを作成します。 アクションの名前がmainでない場合は、--name <your action name>を使用して関数名を指定します。

    ソース・コード (main.go) を使用する場合

    ibmcloud fn action create simple-action main.go
    

    プリコンパイル済みの圧縮ファイル (main-bin.zip) を使用する場合

    ibmcloud fn action create simple-action main-bin.zip
    

    あるいは、ランタイム・イメージを固定されたランタイム・イメージ・バージョンにピン留めしようとしている場合は、--docker タグを使用します。

    ibmcloud fn action create simple-action main.go --docker openwhisk/action-golang-v1.21:nightly
    

    アクションを固定されたランタイムにピン留めすると、変更したりセキュリティー修正を受け取ったりできなくなります。

複数のパッケージから成る Golang アクションの作成

複数の Go パッケージが含まれるアクションを作成できます。 各パッケージに go.mod ファイルが含まれていなければなりません。

.
├── go.mod
├── hello
│   ├── go.mod
│   └── hello.go
└── main.go
  1. 以下の例で示されているように、次のサンプル・ファイルを作成します。

    main.go

    package main
    
    import (
        "fmt"
        "hello"
    )
    
    func Main(args map[string]interface{}) map[string]interface{} {
        fmt.Println("Main")
        return hello.Hello(args)
    }
    

    go.mod

    module action
    
    go 1.21
    
    replace hello => ./hello
    
    require hello v0.0.0
    
    

    hello/hello.go

    package hello
    
    import (
        "fmt"
    )
    
    func Hello(args map[string]interface{}) map[string]interface{} {
        msg := make(map[string]interface{})
        greetings := "world"
        name, ok := args["name"].(string)
        if ok {
            greetings = name
        }
        msg["msg"] = "Hello, " + greetings
        fmt.Printf("Hello, %s\n", greetings)
        return msg
    }
    

    hello/go.mod

    module hello
    
    go 1.19
    
  2. ソース・コード・ファイルを、src.zip と呼ばれる圧縮ファイルに圧縮します。

    zip -r src.zip main.go go.mod hello/hello.go hello/go.mod
    

    このコマンドは main.go go.mod hello/hello.go hello/go.mod ファイルを src.zip に圧縮します。 zip コマンドの詳細については、man zip を使用してください。

    コードをプリコンパイルする場合は、 go mod tidy を実行し、それを zip に追加することで、go sum を生成しなければならない場合があります。

  3. (Optional) コードをプリコンパイルしようとしている場合は、-compile を使用して、Docker ランタイム・イメージを指定して圧縮ソース・コードをコンパイルできます

    圧縮フォーマットで保管され、GO ランタイム自体を使用する実行可能ファイルに関数をコンパイルします。

    docker run -i openwhisk/action-golang-v1.21:nightly -compile main <src.zip >main-bin.zip
    

    <および>は、bash 入出力リダイレクトであり、コマンドの一部です。

  4. アクションを作成します。 ランタイムは--kind=go:1.21として指定する必要があることに注意してください。

    src.zip を使用する場合

    ibmcloud fn action create multiple-packag-action src.zip --kind=go:1.21
    

    プリコンパイル済みコード (main-bin.zip) を使用する場合

    ibmcloud fn action create multiple-packag-action main-bin.zip --kind=go:1.21
    

    あるいは、ランタイム・イメージを固定されたランタイム・イメージ・バージョンにピン留めしようとしている場合は、--docker タグを使用します。

    ibmcloud fn action create multiple-packag-action src.zip --docker openwhisk/action-golang-v1.21:nightly
    

    アクションを固定されたランタイムにピン留めすると、そのランタイムは変更したりセキュリティー修正を受け取ったりできなくなります。

外部ライブラリーと Go モジュールを併用したアクションの作成

サード・パーティーのライブラリーと Go モジュールを併用してアクションを作成できます。 Go モジュールについて詳しくは、 Go モジュールの資料を参照してください。

アクションをプリコンパイルしていない場合は、ライブラリーはアクション実行時間にダウンロードされます。 アクションをプリコンパイルしている場合は、ライブラリーはバイナリー内に既にパッケージ化されているので、アクション実行時間中にダウンロードする必要はありません。

.
├── go.mod
└── main.go
  1. 関数を作成します。

    main.go

    package main
    
    import (
        "github.com/rs/zerolog"
        "github.com/rs/zerolog/log"
    )
    
    func init() {
        zerolog.TimeFieldFormat = ""
    }
    
    // Main function for the action
    func Main(obj map[string]interface{}) map[string]interface{} {
        name, ok := obj["name"].(string)
        if !ok {
            name = "world"
        }
        log.Debug().Str("name", name).Msg("Hello")
        msg := make(map[string]interface{})
        msg["module-main"] = "Hello, " + name + "!"
        return msg
    }
    

    go.mod

    module action
    
    go 1.21
    
    require github.com/rs/zerolog v1.19.0
    
  2. ソース・コードを、src.zip と呼ばれる圧縮ファイルに圧縮します。

    zip -r src.zip main.go go.mod
    

    この例では、main.go ファイルと go.mod ファイルを src.zip に圧縮します。

    コードをプリコンパイルする場合は、 go mod tidy を実行し、それを zip に追加することで、go sum を生成しなければならない場合があります。

  3. コードをプリコンパイルしようとしている場合は、圧縮済みソース・コード (src.zip) を使用し、-compile コマンドを使用して Docker ランタイム・イメージを指定して圧縮ソース・コードをコンパイルします。

    1. 圧縮フォーマットで保管される実行可能ファイル (main-bin.zip) に関数をコンパイルします。

      docker run -i openwhisk/action-golang-v1.21:nightly -compile main <src.zip >main-bin.zip
      

      <および>は、bash 入出力リダイレクトであり、コマンドの一部です。

    2. この圧縮ファイル (main-bin.zip) を action create コマンドでファイルとして指定します。 圧縮ファイルを使用する場合は、ランタイム kind を指定する必要があります (例: --kind=go:1.19)。

  4. アクションを作成します。 ランタイムは--kind=go:1.21で指定する必要があります。

    src.zip を使用する場合

    ibmcloud fn action create module-action src.zip --kind=go:1.21
    

    プリコンパイル済みコード (main-bin.zip) を使用する場合

    ibmcloud fn action create module-action main-bin.zip --kind=go:1.21
    

    あるいは、ランタイム・イメージを固定されたランタイム・イメージ・バージョンにピン留めしようとしている場合は、--docker タグを使用します。

    ibmcloud fn action create module-action src.zip --docker openwhisk/action-golang-v1.21:nightly
    

    アクションを固定されたランタイムにピン留めすると、そのランタイムは変更したりセキュリティー修正を受け取ったりできなくなります。

PHP アプリを準備する

アクションを作成する前に、PHP コードの準備を整えます。

PHP コードを構造化する

コードを構造化する場合、エントリー・ポイントの関数の予期される名前は main です。 コードの関数が main でない場合は、その名前をメモし、アクションの作成時に指定してください。 PHP アクションは常に連想配列を取り込み、連想配列を返します。

<?php
function main(array $args) : array
{
    $name = $args["name"] ?? "stranger";
    $greeting = "Hello $name!";
    echo $greeting;
    return ["greeting" => $greeting];
}
?>

PHP コードをパッケージ化する

PHP ファイルや依存関係パッケージを圧縮ファイル形式でパッケージ化できます。

始めに、PHP ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。

アプリをパッケージするには、次のコマンドを実行します。

zip -r <archive_name>.zip <file_1>.php <file_2>.php

例えば、以下のコード例をパッケージ化します。

  1. コード例を作成します。

    index.php

    <?php
        include 'helper.php';
        function main(array $args) : array
        {
            $name = $args["name"] ?? "stranger";
            $help = help($name);
            return ["help" => $help];
        }
        ?>
    

    helper.php

        <?php
        function help($name) {
            return "Hello " . $name . " the answer to life the universe and everything is 42";
        }
        ?>
    
  2. コード例を圧縮します。

    zip -r helloPHP.zip index.php helper.php
    
  3. アクションを作成します。

    ibmcloud fn action create packagePHP helloPHP.zip --kind=php:7.4
    

Composer モジュールのパッケージ化

追加のコンポーザー・モジュールをアクションにパッケージ化できます。

始めに、PHP ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。

  1. ルート・ディレクトリーに、index.phpファイルとcomposer.jsonファイルを作成します。

    index.php

    <?php
    use Mpociot\ChuckNorrisJokes\JokeFactory;
    
    function main(array $args) : array
    {
        $jokes = new JokeFactory();
        $joke = $jokes->getRandomJoke();
        return ["joke" => $joke];
    }
    ?>
    

    composer.json

    {
        "require": {
            "mpociot/chuck-norris-jokes": "^1.0"
        }
    }
    
    
  2. すべての依存関係をローカルにインストールします。

    composer install
    

    ほとんどのphpパッケージは PHP ソースをcomposer installにインストールしますが、一部のパッケージはプラットフォーム依存のバイナリー・ファイル成果物もインストールしてコンパイルします。 この環境は Linux AMD64-based であるため、php installは同様のプラットフォームで実行する必要があります。 それ以外の場合には、アクション呼び出しが成功しない可能性があります。

  3. すべての依存関係をはじめ、すべてのファイルが含まれているアーカイブを作成します。

    zip -r action.zip *
    

    Windows ユーザー Windows エクスプローラー・アクションを使用して圧縮ファイルを作成すると、誤ったファイル構造になります。Cloud Functions アーカイブ・アクションでは、アーカイブのルートにindex.phpcomposer.jsonがなければなりませんが、Windows エクスプローラーはそれをネストされたフォルダー内に配置します。 代わりに、zip コマンドを使用してください。

  4. 関数の作成

    ibmcloud fn action create chuckJoke action.zip --kind=php:7.4
    

Java アプリを準備する

アクションを作成する前に、Java コードの準備を整えます。

Java コードを構造化する

Java アクションは、mainというメソッドを持つ Java プログラムです。mainには、以下のシグニチャーが必要です。

public static com.google.gson.JsonObject main(com.google.gson.JsonObject);
  • --main を使用して、メイン・クラスの名前を指定する必要があります。 適格なメイン・クラスは、静的 main メソッドを実装するクラスです。 クラスがデフォルト・パッケージ内にない場合は、完全修飾 Java クラス名を使用してください (例: --main com.example.MyMain)。
  • アクションの完全修飾メソッド名 (例えば、--main com.example.MyMain#methodName) を指定することによって、Java アクションのメソッド名をカスタマイズできます。

Java コードをパッケージ化する

.jar ファイルを作成して、コードをパッケージ化します。

開始前に

JDK 8 がローカルにインストールされている必要があります。 この例では、 google-gson-2.9.0.jarを使用します。

JDK 8 以外の JDK バージョンで作業している場合は、--release 8 コマンドでコードをコンパイルするときに javac を指定する必要があります。

Java アクションを作成するには、以下のステップを実行します。

  1. 以下のコードを Hello.java という名前のファイルに保存します。

    import com.google.gson.JsonObject;
    public class Hello {
        public static JsonObject main(JsonObject args) {
            String name = "stranger";
            if (args.has("name"))
                name = args.getAsJsonPrimitive("name").getAsString();
            JsonObject response = new JsonObject();
            response.addProperty("greeting", "Hello, " + name + "!");
            return response;
        }
    }
    
  2. gson-2.9.0.jarをダウンロードします。

  3. gson-2.9.0.jarClASSPATHに追加します。 この例では、Desktopディレクトリーのtestフォルダーに保存されているgson-2.9.0.jarを使用します。

    export CLASSPATH=$CLASSPATH:/Users/Desktop/test/gson-2.9.0.jar
    
  4. JDK の bin フォルダーを CLASSPATHに追加します。 この例では、openjdk-8 を使用します。

    export CLASSPATH=$CLASSPATH:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin
    
  5. JDK のbinフォルダーとgson-2.9.0.jarCLASSPATHにあることを確認します。

    echo $CLASSPATH
    

    出力例

    /Desktop/test/gson-2.9.0.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin
    
  6. Hello.java ファイルが保管されているフォルダーにナビゲートします。 この例では、Hello.java フォルダーに Desktop/test ファイルが保存されます。

    cd Desktop/test
    
  7. Hello.java ファイルをコンパイルしてクラス・ファイルにします。

    javac Hello.java
    
  8. クラス・ファイルを hello.jar という名前の .jar ファイルに圧縮します。

    jar cvf hello.jar Hello.class
    

hello.jar を使用してアクションを作成できます。 作成したクラス・ファイルはデフォルト名 main を使用しないため、アクションの作成時に --main フラグを Hello に設定する必要があります。 --main フラグは、ご使用の Java classと一致する必要があります。 詳しくは、アクションの作成を参照してください。

Java コードを更新する場合は、これらのステップを繰り返して、コードを新しい .jar ファイルに再コンパイルする必要があります。

Gradle を使用した Java コードをパッケージ化する

コマンド行からコンパイルする代わりに、 Gradle などのビルド・ツールを使用して、Maven Central などのリポジトリーからライブラリーを取り出すことができます。 Gradle を使用して取り出し、コードとすべての依存関係を含む最終的な .jar アーカイブをビルドできます。

以下の例では、Gradle を使用して、ライブラリー com.google.zxing を利用する Java アクションをビルドしています。このライブラリーは、QR コードの画像を生成する機能を提供します。

  1. build.gradle という名前のファイルを作成して、依存関係を指定します。

    apply plugin: 'java'
    
    version = '1.0'
    
    repositories {
        mavenCentral()
    }
    
    configurations {
        provided
        compile.extendsFrom provided
    }
    
    dependencies {
        provided 'com.google.code.gson:gson:2.9.0'
        compile 'com.google.zxing:core:3.3.0'
        compile 'com.google.zxing:javase:3.3.0'
    }
    
    jar {
        dependsOn configurations.runtime
    
    from {
            (configurations.runtime - configurations.provided).collect {
                it.isDirectory() ? it : zipTree(it)
            }
        }
    }
    
  2. gradle jar コマンドを実行します。ディレクトリー build/libs/ に .jar アーカイブが生成されます。

詳しくは、 Gradle の資料「 依存関係の宣言」を参照してください。

Docker での Java ランタイムを使用した Java コードのパッケージ化

Java ランタイム内に.jarファイルを作成することにより、Docker を使用してコードをパッケージ化します。

始める前に、Docker をローカルにインストールしておく必要があります。

すべてが Java ランタイムによって提供されるため、Java をローカルにインストールする必要はありません。

Docker を使用して Java アクションを作成するには、以下のステップを実行します。

  1. Hello.javaファイルの作成

    import com.google.gson.JsonObject;
    
    public class Hello {
        public static JsonObject main(JsonObject args) {
            String name = "stranger";
            if (args.has("name"))
                name = args.getAsJsonPrimitive("name").getAsString();
            JsonObject response = new JsonObject();
            response.addProperty("greeting", "Hello, " + name + "!");
            return response;
        }
    }
    
  2. Hello.javaファイルが含まれているフォルダーにナビゲートし、Docker Java ランタイム・コンテナーを実行します。

    docker run --rm -it  --entrypoint "/bin/bash" -v $PWD:/tmp openwhisk/java8action:nightly
    

    最新のランタイム・バージョンまたは特定のタグには、nightlyタグを使用します。

  3. コンテナーをセットアップします。

    1. ホスト・システムからマウントされたアクション・コードが含まれている/tmpフォルダーにナビゲートします。

      cd /tmp
      
    2. curl をインストールして、依存関係をダウンロードします。

      apt update && apt install curl -y
      
    3. gson依存関係をダウンロードします。

      curl -L -o gson-2.9.0.jar https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.5/gson-2.9.0.jar
      
    4. パスをエクスポートし、gsonを追加します。

      export CLASSPATH=$CLASSPATH:$PWD/gson-2.9.0.jar
      export CLASSPATH=$CLASSPATH:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin
      
  4. コードのコンパイル

    1. Java コードをクラスにコンパイルします。
      javac Hello.java
      
    2. Java クラスをデプロイ可能な.jarファイルにパッケージ化します。
      jar cvf Hello.jar Hello.class
      
  5. ランタイム・コンテナーを終了します。

    exit
    
  6. hello-javaという名前のアクションを作成します。

    ibmcloud fn action create hello-java Hello.jar --main Hello
    
  7. アクションの呼び出し

    ibmcloud fn action invoke hello-java -b
    

Docker 内での Maven を使用した Java コードのパッケージ化

  1. Maven プロジェクトの作成

  2. Maven プロジェクトが含まれているフォルダーにナビゲートし、Docker Java ランタイム・コンテナーを実行します。

    docker run --rm -it  --entrypoint "/bin/bash" -v $PWD:/tmp openwhisk/java8action:nightly
    

    このコマンドは、Java ランタイム・コンテナーを実行し、コンテナー内の現行ディレクトリーを/tmpにマップします。

    最新のランタイム・バージョンまたは特定のタグには、nightlyタグを使用します。

  3. コンテナーをセットアップします。

    ホスト・システムからマウントされたアクション・コードが含まれている/tmpフォルダーにナビゲートします。

    cd /tmp
    
  4. curlunzipをインストールして Maven をインストールします。

    apt update && apt install curl unzip -y
    
  5. ダウンロード Maven

    curl -L -o apache-maven-3.8.5-bin.zip https://dlcdn.apache.org/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.zip
    
  6. Maven の抽出

    unzip apache-maven-3.8.5-bin.zip
    
  7. Maven をパスに追加

    export PATH=$PATH:/apache-maven-3.8.5/bin
    
  8. Maven インストールのテスト

    mvn -v
    
  9. アクション・コードを Maven でパッケージ化します

    mvn package
    
  10. ランタイム・コンテナーを終了します。

exit

この時点で、現行ディレクトリーには、アクション .jar ファイルを含む traget ディレクトリーが含まれています。

  1. 作成アクションが呼び出されました。
ibmcloud fn action create <actionname> <Jar name>.jar --main <package name and class name seperated by dots>

メイン名は com.package.example.Hello のようなものです。

  1. アクションの呼び出し
ibmcloud fn action invoke <actionname> -b