アクションとして使用するアプリの準備
IBM Cloud® Functions が非推奨になりました。 アクション、トリガー、シーケンスなどの既存の Functions エンティティーは引き続き実行されますが、2023 年 12 月 28 日以降、新しい Functions エンティティーを作成することはできません。 既存の Functions エンティティーは、2024 年 10 月までサポートされます。 その日付にまだ存在する Functions エンティティーはすべて削除されます。 詳しくは、 非推奨の概要 を参照してください。
アプリを持ち込むのか、イベントに応答するスクリプトを特別に作成するのかにかかわらず、コードからアクションを作成するためには、コードがいくつかの要件を満たしている必要があります。
プログラミング言語ごとに固有の実行要件がありますが、ほとんどのプログラミング言語には次の一般的な要件が適用されます。
-
コードのエントリー・ポイントの名前は、デフォルトでは
main
と想定されます。 エントリー・ポイントがmain
ではない場合は、アクションの作成時にカスタム名を指定できるので、その名前をメモしておいてください。 -
アプリの入力パラメーターとアプリの出力結果は、エンティティー間で受け渡し可能な特定の構造になるように形式設定する必要があります。 この構造は、コードの言語によって異なります。 例えば、Python アプリの場合、入力パラメーターはディクショナリーでなければならず、アプリの結果をディクショナリーとして構造化する必要があります。 パラメーターを構造化オブジェクトに入れてアクションに渡すこともできるからです。 例えば JSON では、
name
やplace
のような特定のフィールドの 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 ベースのディストリビューションでコマンドを実行していると想定しています。
-
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" } }
-
以下の
webpack
構成コードをwebpack.config.js
という名前のファイルに保存します。var path = require('path'); module.exports = { entry: './index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, target: 'node' };
-
アプリのコードを準備します。 この例 (
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;
-
すべての依存関係をローカルにインストールします。
npm install
npm run prebuild
ほとんどの
npm
パッケージでは、npm install
を実行すると JavaScript のソースがインストールされますが、中には、プラットフォームに依存するバイナリー・ファイル成果物のインストールとコンパイルを行うパッケージもあります。 この環境は Linux AMD64-based であるため、npm install
は同様のプラットフォームで実行する必要があります。 それ以外の場合には、アクション呼び出しが成功しない可能性があります。 -
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"
-
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
に含まれていないため、アクションの呼び出しが失敗することがあります。 -
-
以下のいずれかのオプションを使用して、生成された成果物
package-lock.json
、node_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 ベースのディストリビューションでコマンドを実行していると想定しています。
-
ルート・ディレクトリーに、
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;
-
すべての依存関係をローカルにインストールします。
npm install <dependency>
ほとんどの
npm
パッケージでは、npm install
を実行すると JavaScript のソースがインストールされますが、中には、プラットフォームに依存するバイナリー・ファイル成果物のインストールとコンパイルを行うパッケージもあります。 この環境は Linux AMD64-based であるため、npm install
は同様のプラットフォームで実行する必要があります。 それ以外の場合には、アクション呼び出しが成功しない可能性があります。 -
すべての依存関係をはじめ、すべてのファイルが含まれているアーカイブを作成します。
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 イメージを作成しなければなりません。
-
以下のコマンドを実行して、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 *"
-
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>))
)
を追加します。
-
以下の内容を含む
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 ) }) }
-
アクションを作成し、メイン・アクションを
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
を使用してエントリー・ポイントを指定してください。 -
アクションを呼び出します。
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 ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。
-
デスクトップに
test
ディレクトリーを作成します。 -
以下のコードを
__main__.py
というファイルとしてtest
ディレクトリーに保存します。from helper import helper def main(args): return helper(args)
-
以下のコードを
helper.py
というファイルとしてtest
ディレクトリーに保存します。 このコードはname
パラメーターを受け入れて、挨拶を返します。name
を指定しないと、返されるname
はstranger
になります。def helper(dict): if 'name' in dict: name = dict['name'] else: name = "stranger" greeting = "Hello from helper.py, " + name + "!" return {"greeting": greeting}
-
アプリを圧縮ファイル形式でパッケージ化するには、
cd
ディレクトリーへのtest
を実行し、以下のコマンドを実行します。 この例では、アーカイブはstranger.zip
です。zip -r stranger.zip __main__.py helper.py
-
この圧縮ファイルを使用して、
hello
というアクションを作成できます。<file_path>
を、圧縮ファイルのファイル・パスに置き換えます。ibmcloud fn action create hello <file_path>/test/stranger.zip --kind python:3.11
-
アクションをテストします。
ibmcloud fn action invoke hello --result
出力例
{ "greeting": "Hello from helper.py, stranger!" }
-
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
アプリをパッケージ化するには、以下のようにします。
-
仮想環境の作成に使用できるディレクトリーを作成します。 この例では、
jokes
ディレクトリーをデスクトップに作成します。jokes
ディレクトリーを作成したら、そのディレクトリーへのcd
を実行します。cd desktop; mkdir jokes; cd jokes
-
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
-
jokes
ディレクトリーから、virtualenv
仮想環境をアクティブにします。source virtualenv/bin/activate
-
仮想環境内の Python バージョンが、後でアクションを作成するときに
--kind
オプションで指定したバージョンと一致していることを確認します (例えば、python:3.11
)。実際のバージョンを確認するには、python --version
-
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
-
virtualenv
仮想環境を停止します。(virtualenv) $ deactivate
-
以下のコードをコピーして、
__main__.py
ディレクトリー内のjokes
というファイルに保存します。import pyjokes def joke(params): return {"joke": pyjokes.get_joke()}
-
jokes
ディレクトリーから、virtualenv
フォルダーと__main__.py
ファイルのアーカイブを作成します。 それらのファイルを.zip
ファイルのトップレベルに置いてください。zip -r jokes.zip virtualenv __main__.py
出力例
... adding: virtualenv (stored 0%) adding: __main__.py (deflated 18%) ...
-
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
-
アクションを呼び出して、動作していることを確認します。 コマンド・ラインで結果を返すために、
--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 ベースのディストリビューションでコマンドを実行していると想定しています。
以下のステップを実行して、アプリをパッケージします。
-
仮想環境の作成に使用できるディレクトリーを作成します。 この例では、
test
ディレクトリーをデスクトップに作成します。test
ディレクトリーを作成したら、そのディレクトリーへのcd
を実行します。cd desktop; mkdir test; cd test
-
test
ディレクトリー内のファイルに、インストールするpip
モジュールとバージョンを含む requirements.txt を作成します。touch requirements.txt
-
vim を使用して
requirements.txt
ファイルを編集します。 インストールするpip
モジュールの名前とバージョンを入力します。 この例では、pyjokes
が使用されるモジュールです。vim requirements.txt
requirements.txt の例
pyjokes
-
ESC
を押し、:wq
でrequirements.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
-
仮想環境を作成し、追加の 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
-
以下のコードを
__main__.py
としてtest
ディレクトリーに保存します。 圧縮ファイルでアクションを作成する場合は、エントリー・ポイントを含むソース・ファイルを__main__.py
という名前にする必要があります。import pyjokes def joke(params): return {"joke": pyjokes.get_joke()}
-
このコードをアクションとしてデプロイするには、
virtualenv
フォルダーと__main__.py
ファイルの圧縮ファイルを作成する必要があります。場合によっては、 Cloud Functionsで許可されている アクション制限 で説明されているように、結果の圧縮ファイルが最大
codeSize
より大きくなることがあります。 圧縮ファイルのサイズを小さくするために、virtualenv
フォルダー全体を選択するのではなく、必要な依存関係だけを選択してください。 必要なパッケージは、site-packages
フォルダー内のvirtualenv
ディレクトリーにあります。activate_this.py
フォルダーのbin
ディレクトリーにあるvirtualenv
ファイルも圧縮ファイルに含める必要があります。zip -r pyjoke.zip virtualenv __main__.py
-
pyjoke.zip
ファイルを使用して、pyjoke
というアクションを作成します。 使用する--kind
が、圧縮アクション・ファイルの作成に使用したランタイム・イメージに対応していることを確認します。 対応していないと、呼び出し中にアクションの実行が失敗します。ibmcloud fn action create pyjoke <file_path>/pyjoke.zip --kind python:3.11
-
アクションを呼び出して、
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 イメージにインストールし、アクションの作成時にアプリ・コードと一緒にデプロイすることは可能です。
その後、実行時にパッケージをインポートできます。
この例では、matplotlib
や seaborn
などの大きな Python パッケージをインストールして、seaborn
で結合プロットの PNG ファイルを生成する Cloud Functions Web アクションをビルドします。
開始前に
- Python ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。
- 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。
パブリック Docker イメージだけがサポートされます。
以下の手順を実行して、アプリをカスタム Docker イメージにパッケージ化します。
-
Dockerfile の作成に使用できるディレクトリーを作成します。 この例では、
functions
ディレクトリーをデスクトップに作成します。functions
ディレクトリーを作成したら、そのディレクトリーへのcd
を実行します。cd desktop; mkdir functions; cd functions
-
functions
ディレクトリーに Dockerfile を作成します。touch Dockerfile
-
vim を使用して
Dockerfile
ファイルを編集します。 インストールするpip
モジュールの名前とバージョンを入力します。 この例では、いくつかの追加の Python モジュールがインストールされます。vim Dockerfile
-
Dockerfile
に以下のテキストを貼り付けるか、入力します。FROM ibmfunctions/action-python-v3.9:1.0.0 RUN pip install \ --upgrade pip \ matplotlib \ seaborn \ pandas \ statsmodels
-
ESC
を押し、:wq
を使用し、Enter
を押して、Dockerfile を保存して閉じます。 -
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>
-
そのイメージによって、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 ... ...
-
イメージを Docker Hub にプッシュします。
docker push <dockerhub_username>/<repo_name>:<tag_name>
イメージをプッシュする前に、Docker Hub にログインしてください。
-
以下のコードを
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'} }
-
作成したカスタム Docker イメージを使用して
seaborn
という Web アクションを作成します。そのイメージには、結合プロットを実行するのに必要な Python 依存関係が含まれています。
ibmcloud fn action create seaborn --docker <dockerhub_username>/<repo_name>:<tag_name> seaborn.py --web true
出力例
ok: created action seaborn
- アクションを呼び出してテストします。 アクションを呼び出すと、生成された結合プロットを表す base64 の文字列が返されます。
ibmcloud fn action invoke seaborn --result
出力例
<base64_string>,
"headers": {
"Content-Type": "image/png"
},
"isBase64Encoded": "true",
"statusCode": 200
}
- このアクションは 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
- 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 Hubで ibmfunctions
Docker 基本イメージのリストを確認できます。
Cloud Functions では、アプリ・コードが、codeSize
アクションの制限に記述されている の最大値までに制限されています。
-
デスクトップに
test
ディレクトリーを作成し、そのディレクトリーへのcd
を実行します。cd desktop; mkdir test; cd test
-
test
ディレクトリーに Dockerfile を作成し、vim
で開きます。touch Dockerfile; vim Dockerfile
-
i
キーを押して Dockerfile を編集します。 -
Dockerfile で
FROM
引数を使用して Cloud Functions 基本イメージを指定します。 -
RUN
引数の後に依存関係のインストール・コマンドを指定して、パッケージと依存関係をインストールします。 -
ESC
を押し、:wq
を使用し、Enter
を押して、Dockerfile を保存して閉じます。Python 依存関係をインストールする Dockerfile の例
以下の例では、
ibmfunctions/action-python-v3.7
を基本イメージとして使用し、Python モジュールmatplotlib
、pandas
、statsmodels
をインストールします。FROM ibmfunctions/action-python-v3.7 RUN pip install \ --upgrade pip \ matplotlib \ pandas \ statsmodels
-
カスタム Docker イメージをビルドします。
docker build -t <dockerhub_username>/<repo_name>:<tag_name>
-
イメージを 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 を使用するアクションを作成するには、以下の手順に従います。
- デプロイしようとしている関数を作成します。
- (
optional
) 複数のファイルがある場合は、それらのファイルを圧縮ファイルとしてパッケージ化します。そうでない場合はこのステップをスキップします (以下の例を参照してください) - (
optional
) Docker イメージ (docker run -i openwhisk/action-golang-v1.21:nightly -compile ...
) を使用してgo/zip
ファイルをコンパイルします。このステップは、実行可能ファイルを含む圧縮ファイルを返します。 ibmcloud cli
を使用してアクションを作成します。
これらの手順は、以下の各例で使用されます。
単純な Golang アクションの作成
Go 関数が含まれるファイルを作成して、Go で単純なアクションを作成できます。
-
関数が含まれる 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 }
-
(
optional
) 最初に、圧縮フォーマットで保管される実行可能ファイルに関数をプリコンパイルしようとしている場合は、以下のようにします。docker run -i openwhisk/action-golang-v1.21:nightly -compile main <main.go >main-bin.zip
<
および>
は、bash 入出力リダイレクトであり、コマンドの一部です。生成された圧縮ファイル (
main-bin.zip
) をaction create
コマンドでファイルとして指定します。 -
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
-
以下の例で示されているように、次のサンプル・ファイルを作成します。
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
-
ソース・コード・ファイルを、
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 を生成しなければならない場合があります。 -
(
Optional
) コードをプリコンパイルしようとしている場合は、-compile
を使用して、Docker ランタイム・イメージを指定して圧縮ソース・コードをコンパイルできます圧縮フォーマットで保管され、GO ランタイム自体を使用する実行可能ファイルに関数をコンパイルします。
docker run -i openwhisk/action-golang-v1.21:nightly -compile main <src.zip >main-bin.zip
<
および>
は、bash 入出力リダイレクトであり、コマンドの一部です。 -
アクションを作成します。 ランタイムは
--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
-
関数を作成します。
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
-
ソース・コードを、
src.zip
と呼ばれる圧縮ファイルに圧縮します。zip -r src.zip main.go go.mod
この例では、
main.go
ファイルとgo.mod
ファイルをsrc.zip
に圧縮します。コードをプリコンパイルする場合は、
go mod tidy
を実行し、それを zip に追加することで、go sum を生成しなければならない場合があります。 -
コードをプリコンパイルしようとしている場合は、圧縮済みソース・コード (
src.zip
) を使用し、-compile
コマンドを使用して Docker ランタイム・イメージを指定して圧縮ソース・コードをコンパイルします。-
圧縮フォーマットで保管される実行可能ファイル (
main-bin.zip
) に関数をコンパイルします。docker run -i openwhisk/action-golang-v1.21:nightly -compile main <src.zip >main-bin.zip
<
および>
は、bash 入出力リダイレクトであり、コマンドの一部です。 -
この圧縮ファイル (
main-bin.zip
) をaction create
コマンドでファイルとして指定します。 圧縮ファイルを使用する場合は、ランタイムkind
を指定する必要があります (例:--kind=go:1.19
)。
-
-
アクションを作成します。 ランタイムは
--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
例えば、以下のコード例をパッケージ化します。
-
コード例を作成します。
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"; } ?>
-
コード例を圧縮します。
zip -r helloPHP.zip index.php helper.php
-
アクションを作成します。
ibmcloud fn action create packagePHP helloPHP.zip --kind=php:7.4
Composer モジュールのパッケージ化
追加のコンポーザー・モジュールをアクションにパッケージ化できます。
始めに、PHP ランタイムに組み込まれているパッケージを参照し、アプリの依存関係がランタイムに既に組み込まれているかどうかを調べます。 依存関係が組み込まれていない場合は、アプリと一緒にパッケージ化する必要があります。 以下の手順は、AMD64 ベースのアーキテクチャーのプロセッサー上にある Linux ベースのディストリビューションでコマンドを実行していると想定しています。
-
ルート・ディレクトリーに、
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" } }
-
すべての依存関係をローカルにインストールします。
composer install
ほとんどの
php
パッケージは PHP ソースをcomposer install
にインストールしますが、一部のパッケージはプラットフォーム依存のバイナリー・ファイル成果物もインストールしてコンパイルします。 この環境は Linux AMD64-based であるため、php install
は同様のプラットフォームで実行する必要があります。 それ以外の場合には、アクション呼び出しが成功しない可能性があります。 -
すべての依存関係をはじめ、すべてのファイルが含まれているアーカイブを作成します。
zip -r action.zip *
Windows ユーザー Windows エクスプローラー・アクションを使用して圧縮ファイルを作成すると、誤ったファイル構造になります。Cloud Functions アーカイブ・アクションでは、アーカイブのルートに
index.php
とcomposer.json
がなければなりませんが、Windows エクスプローラーはそれをネストされたフォルダー内に配置します。 代わりに、zip
コマンドを使用してください。 -
関数の作成
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 アクションを作成するには、以下のステップを実行します。
-
以下のコードを
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; } }
-
gson-2.9.0.jar
をダウンロードします。 -
gson-2.9.0.jar
をClASSPATH
に追加します。 この例では、Desktop
ディレクトリーのtest
フォルダーに保存されているgson-2.9.0.jar
を使用します。export CLASSPATH=$CLASSPATH:/Users/Desktop/test/gson-2.9.0.jar
-
JDK の
bin
フォルダーをCLASSPATH
に追加します。 この例では、openjdk-8
を使用します。export CLASSPATH=$CLASSPATH:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin
-
JDK の
bin
フォルダーとgson-2.9.0.jar
がCLASSPATH
にあることを確認します。echo $CLASSPATH
出力例
/Desktop/test/gson-2.9.0.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin
-
Hello.java
ファイルが保管されているフォルダーにナビゲートします。 この例では、Hello.java
フォルダーにDesktop/test
ファイルが保存されます。cd Desktop/test
-
Hello.java
ファイルをコンパイルしてクラス・ファイルにします。javac Hello.java
-
クラス・ファイルを
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 コードの画像を生成する機能を提供します。
-
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) } } }
-
gradle jar
コマンドを実行します。ディレクトリーbuild/libs/
に .jar アーカイブが生成されます。
詳しくは、 Gradle の資料「 依存関係の宣言」を参照してください。
Docker での Java ランタイムを使用した Java コードのパッケージ化
Java ランタイム内に.jar
ファイルを作成することにより、Docker を使用してコードをパッケージ化します。
始める前に、Docker をローカルにインストールしておく必要があります。
すべてが Java ランタイムによって提供されるため、Java をローカルにインストールする必要はありません。
Docker を使用して Java アクションを作成するには、以下のステップを実行します。
-
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; } }
-
Hello.java
ファイルが含まれているフォルダーにナビゲートし、Docker Java ランタイム・コンテナーを実行します。docker run --rm -it --entrypoint "/bin/bash" -v $PWD:/tmp openwhisk/java8action:nightly
最新のランタイム・バージョンまたは特定のタグには、
nightly
タグを使用します。 -
コンテナーをセットアップします。
-
ホスト・システムからマウントされたアクション・コードが含まれている
/tmp
フォルダーにナビゲートします。cd /tmp
-
curl
をインストールして、依存関係をダウンロードします。apt update && apt install curl -y
-
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
-
パスをエクスポートし、
gson
を追加します。export CLASSPATH=$CLASSPATH:$PWD/gson-2.9.0.jar export CLASSPATH=$CLASSPATH:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin
-
-
コードのコンパイル
- Java コードをクラスにコンパイルします。
javac Hello.java
- Java クラスをデプロイ可能な
.jar
ファイルにパッケージ化します。jar cvf Hello.jar Hello.class
- Java コードをクラスにコンパイルします。
-
ランタイム・コンテナーを終了します。
exit
-
hello-java
という名前のアクションを作成します。ibmcloud fn action create hello-java Hello.jar --main Hello
-
アクションの呼び出し
ibmcloud fn action invoke hello-java -b
Docker 内での Maven を使用した Java コードのパッケージ化
-
Maven プロジェクトの作成
-
Maven プロジェクトが含まれているフォルダーにナビゲートし、Docker Java ランタイム・コンテナーを実行します。
docker run --rm -it --entrypoint "/bin/bash" -v $PWD:/tmp openwhisk/java8action:nightly
このコマンドは、Java ランタイム・コンテナーを実行し、コンテナー内の現行ディレクトリーを
/tmp
にマップします。最新のランタイム・バージョンまたは特定のタグには、
nightly
タグを使用します。 -
コンテナーをセットアップします。
ホスト・システムからマウントされたアクション・コードが含まれている
/tmp
フォルダーにナビゲートします。cd /tmp
-
curl
とunzip
をインストールして Maven をインストールします。apt update && apt install curl unzip -y
-
ダウンロード
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
-
Maven の抽出
unzip apache-maven-3.8.5-bin.zip
-
Maven をパスに追加
export PATH=$PATH:/apache-maven-3.8.5/bin
-
Maven インストールのテスト
mvn -v
-
アクション・コードを Maven でパッケージ化します
mvn package
-
ランタイム・コンテナーを終了します。
exit
この時点で、現行ディレクトリーには、アクション .jar
ファイルを含む traget
ディレクトリーが含まれています。
- 作成アクションが呼び出されました。
ibmcloud fn action create <actionname> <Jar name>.jar --main <package name and class name seperated by dots>
メイン名は com.package.example.Hello
のようなものです。
- アクションの呼び出し
ibmcloud fn action invoke <actionname> -b