注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。

コンテナ

このページでは、Compute Module で使用する Docker の基本について説明します。詳しい説明については、Docker ドキュメント ↗を参照してください。

Docker をはじめる

イメージをビルドして公開するには、まず Docker をインストールする必要があります。Docker ドキュメント ↗の公式手順に沿って進めてください。

Docker が実行されていることを確認するには、docker info コマンドを実行できます。Cannot connect to the Docker daemon と表示された場合は、トラブルシューティングガイド ↗を参照して問題を解決してください。

Docker とは?

Docker は、アプリケーションをパッケージ化してデプロイするためのツールです。Docker を使用すると、配布が容易になり、ランタイム環境間での実行の一貫性と、分離によるセキュリティを確保できます。これは、コンテナ化と呼ばれるプロセスによって実現されます。このプロセスでは、アプリケーションの実行に必要なものをすべてパッケージ化し、どこにデプロイしても一貫して実行されるようにします。Docker のコンテナ化には、イメージとコンテナという2つの基本要素があります。

  • イメージ: アプリケーションの実行に必要なすべてのコード、依存関係などを含む不変のファイルです。つまり、イメージは実行すべき内容を記述するだけのものであり、コンテナを作成するためのテンプレートです。
  • コンテナ: イメージの実行中の単一インスタンスです。コンテナは、アプリケーションが実際に実行される、稼働中の軽量で分離された環境です。

イメージを作成する

Docker でイメージを作成する際は、アプリケーションを依存関係、ライブラリ、設定ファイルとともに、単一の移植可能な単位にパッケージ化します。パッケージ化の手順は Dockerfile に定義します。

Dockerfile

Dockerfile は、アプリケーションの設定と実行の方法を指示するコマンドを順番に記述したテキストドキュメントです。次のリストは、Compute Module 用のイメージを作成する際に必要となる主なコマンドの概要です。詳しいガイドについては、Dockerfile リファレンスドキュメント ↗を参照してください。

  • FROM: ベースイメージを宣言します。ベースイメージは、イメージの設定を構築する土台となるレイヤーです。ベースイメージは、最小限のもの(オペレーティングシステムのみ)から、より多くの要素を含むもの(Python などの既存ソフトウェアを含むもの)までさまざまです。FROM は Dockerfile の最初のステートメントである必要があります。--platform linux/amd64 フラグを追加して、対象プラットフォームを指定することもできます。
  • WORKDIR: 作業ディレクトリを設定します。作業ディレクトリは、コマンドが実行されるイメージ内の基準となる場所です。
  • RUN: イメージのビルド中にシェルコマンドを実行します。シェルコマンドは通常、依存関係のインストール、コードのコンパイル、ファイルシステム操作の実行に使用します。
  • COPY: コンピューターからイメージにファイルをコピーします。
  • USER: コンテナのユーザーを設定します。ユーザーは root 以外で、数値で指定する必要があります。
  • ENTRYPOINT: コンテナの起動時に実行されるデフォルトのコマンドを設定します。このコマンドは、コンテナが実際に行う処理を指定します。
  • EXPOSE: コンテナがリッスンするポートを記述します。公開するすべてのポートは、8945と8946を除く1024から65535の範囲内である必要があります。
  • ENV: 環境変数を設定します。これらの変数は、コンテナの設定や、実行中にコンテナが読み取る実行時情報の指定に使用できます。

Compute Module 用イメージの要件

  • イメージは、数値で指定した root 以外のユーザーとして実行する必要があります。
  • イメージは、linux/amd64 プラットフォーム向けにビルドする必要があります。
  • ダイジェスト、または latest _以外_の任意のタグを使用する必要があります。
  • 公開するすべてのポートは、8945と8946を除く1024から65535の範囲内である必要があります。

Compute Module でイメージを使用する

Compute Module に対応するイメージを用意したら、次の手順に従って Foundry にアップロードできます。詳しい手順については、アーティファクトの公開に関するドキュメントを参照してください。

  • アーティファクトリポジトリを作成します。
  • 公開に移動し、Docker を選択します。
  • 表示される手順に従って、イメージをリポジトリにプッシュします。

イメージをビルドする:例

Compute Module としてデプロイするアプリケーションがあり、その構成は次のとおりです。

プロジェクト構成

myapplication
├── Dockerfile
├── requirements.txt
└── src
    └── application.py

次の手順で、Dockerfile を1行ずつ作成できます。

  1. ベースイメージを指定します。
FROM python:3.12
  1. 現在のディレクトリを設定します。
WORKDIR /app
  1. 必要な依存関係をインストールします。
COPY ./requirements.txt /app
RUN pip install --no-cache-dir -r requirements.txt
  1. コンテナの実行に使用する、root 以外のユーザーを数値で指定します。
RUN adduser --uid 5001 user
USER 5001
  1. アプリケーションコードをコピーします。Docker イメージのレイヤーキャッシュを活用するため、これは依存関係とは別に行います。
COPY ./src/application.py /app
  1. 起動時にアプリケーションを実行するようにコンテナを設定します。
ENTRYPOINT ["python", "application.py"]

Dockerfile は次のようになります。

FROM python:3.12
WORKDIR /app
COPY ./requirements.txt /app
RUN pip install --no-cache-dir -r requirements.txt
RUN adduser --uid 5001 user
USER 5001
COPY ./src/application.py /app
ENTRYPOINT ["python", "application.py"]

これで、次のコマンドを実行して、Dockerfile から 0.0.0 タグの付いた myimage という名前のイメージをビルドできます。

docker build . -t myimage:0.0.0 --platform linux/amd64

ログ

ログ記録はコンテナ単位で設定でき、コンテナごとに有効または無効にできます。このきめ細かな制御により、リソース使用量を最適化し、最も関連性の高いログデータに集中できます。特定のコンテナのログ設定にアクセスするには、コンテナセクションでそのコンテナの行を選択します。サイドパネルが開き、ログ設定を調整できます。

ログ形式とソースのオプションを表示するコンテナのログ設定パネル。

ログ形式

SLS 形式

SLS 形式は、一貫性があり、容易にパースできるログを提供する構造化ログ形式です。SLS ログ記録は、ログエントリごとに追加のメタデータを含められるように設計されています。

以下は、SLS 形式でログを記録する例です。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package myproject; import com.palantir.interactive.module.api.SafeArg; import com.palantir.interactive.module.api.UnsafeArg; import com.palantir.interactive.module.tasks.deployedapps.DeployedAppRuntime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; final class DeployedApp { private static final Logger log = LoggerFactory.getLogger(DeployedApp.class); public static void main(String[] _args) { DeployedAppRuntime.builder() .addQueryRunner(DeployedApp::hello, String.class, String.class, "hello") .buildAndStart(); } static String hello(String name) { // エラー用の SLS 形式 log.error("This is an SLS error log with unsafe parameter", UnsafeArg.of("name", name)); // これは SLS 形式ではありません。そのため、SLS 形式が選択されている場合はログに記録されません。 System.out.println("This message will not be logged iff SLS format"); // 情報用の SLS 形式 log.info("This is an SLS info log with safe parameter", SafeArg.of("name", name)); return "Hello, " + name + "!"; } private DeployedApp() {} }

ログ記録では、以下のスタイルと制約に従っていることに注目してください。

  • 機密性がある可能性のあるデータには UnsafeArg を、機密性のないデータには SafeArg を使用します。
  • Standard System.out.println() 文は SLS 形式では記録されません。

以下は、SLS 形式のログエントリを JSON で表した例です。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 { "type": "service.1", "level": "INFO", "time": "2024-01-15T12:00:00.000Z", "origin": "com.example.MyClass", "thread": "main", "message": "Processing request", "params": { "requestId": "abc-123" }, "uid": "unique-log-id", "sid": "session-id" }

Python SDK のログ記録

Python Compute Modules SDK を使用している場合は、組み込みのログユーティリティを使用できます。get_logger 関数は SLS 形式に設定されたロガーを返し、set_internal_log_level は SDK 内部ログの詳細度を制御します。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import logging from dataclasses import dataclass from compute_modules.annotations import function from compute_modules.logging import get_logger, set_internal_log_level set_internal_log_level(logging.INFO) logger = get_logger(__name__) logger.setLevel(logging.INFO) @dataclass class AddPayload: x: int y: int @function def add(context, event: AddPayload) -> int: try: logger.info("Received add request") result = event.x + event.y return result except Exception as e: logger.error("There was an error") raise e

以下のログレベルを利用できます。詳細度の高い順に記載しています。

  • DEBUG:トラブルシューティングのための詳細な診断情報。
  • INFO:通常の動作に関する一般的な情報メッセージ。
  • WARNING:予期しない事象が発生した、または近い将来に発生する可能性があることを示すメッセージ。
  • ERROR:特定の操作を完了できなかった重大な問題。
  • CRITICAL:アプリケーションの実行を継続できない可能性があることを示す深刻なエラー。

プレーンテキスト形式

プレーンテキスト形式では、特定の構造を持たず、人が読めるログが生成されます。プレーンテキストのログはそのまま読むのが容易ですが、プログラムでパースするのは難しい場合があります。

プレーンテキストを設定すると、出力が SLS ログのメッセージフィールドに挿入されます。これにより、読みやすさを維持しながら、既存の SLS ベースのツールとの互換性を確保できます。

プレーンテキストのログ記録をデフォルトとして使用すると、プレーンテキストと SLS の両方のログが記録され、SLS ログはメッセージフィールドに JSON 形式で表示されます。

コンテナログのソース

コンテナログは、2つの主要なソースから収集できます。ログを効果的に収集するために、ソースごとに固有の要件と設定があります。

標準出力

標準出力(stdout)ソースは、コンテナの標準出力ストリームから直接ログを収集します。このログ記録方法を有効にするには、コンテナが以下の要件を満たしていることを確認してください。

  • /bin/sh にシェル実行可能ファイルがあること
  • シェルコマンド set と tee をサポートしていること

標準エラーの包含: オプションで標準エラー(stderr)をログに含めることができます。true に設定すると、stdout と stderr が同期され、単一のストリームにマージされます。

ログファイル

ログファイルソースは、コンテナ内の特定のファイルからログを収集します。設定パラメーターは2個あります。

  • ディレクトリパス: ログファイルが配置されているベースディレクトリ。
  • ファイルパスパターン: 収集するログファイルに一致させるためのパターン。このパラメーターは、柔軟にファイルを照合できるように、一般的なワイルドカードをサポートしています。各パターンには、指定したディレクトリパスを含める必要があります。

例: /var/log/foo/ 内のすべての .log ファイルと、特定のファイル /var/log/bar.txt からログを収集するには、directoryPath を /var/log に、filePathPatterns を /var/log/foo/*.log と /var/log/bar.txt に設定します。

ログファイルを使用する場合、Compute Module の起動時に、指定したディレクトリパスが空である必要があります。

環境変数

Docker の環境変数は、Dockerfile やコンテナイメージを変更せずに Docker コンテナやアプリケーションの動作をカスタマイズできる、名前付きの動的な値です。環境変数は、次のようなさまざまな目的に使用できます。

  • パラメーターの設定: CPU セットや CPU シェアなど、Docker イメージのパラメーターを設定します。
  • 動作の定義: アプリケーションやスクリプトの動作を定義します。
  • 資格情報の保存: APIキーやデータベースの資格情報など、機密情報を安全に保存します。
  • 再利用可能な設定の作成: 環境変数と補間を使用して再利用可能な設定を作成し、Docker 化されたアプリケーションの管理とデプロイを容易にします。
  • デフォルト値のオーバーライド: コンテナの実行時に、Dockerfile で指定されたデフォルトの設定値をオーバーライドします。

例

production と test の2つのコードパスがあり、test はリクエストに関する追加のメタデータを返す場合があるとします。コードを変更して再デプロイしなくても、コードが読み取って異なるパスを実行するために使用できる production 環境変数を作成できます。

Copied!
1 2 3 4 5 6 7 # app.py import os if os.environ["production"] == "true": ... else: ...

予約済み環境変数のリファレンス

一部の環境変数名は予約されています。予約済み環境変数には、Compute Module を作成する際に重要な情報が含まれている場合があるため、上書きできません。以下の予約済み環境変数の一覧を確認してください。

CLIENT_ID string

  • 存在する場合、これはこの Compute Module に関連付けられたサードパーティアプリケーションのクライアントIDです。関数実行モードの場合、およびアプリケーション権限を使用する場合に存在します。サードパーティアプリケーションのサービスユーザーから Foundry スコープのトークンを取得するために使用します。
  • サンプル値: 038120ac-ac39-4d91-be0e-55afabbb0912
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # app.py import requests import os token_response = requests.post("https://{FOUNDRY_URL}/multipass/api/oauth2/token", data={ "grant_type": "client_credentials", "client_id": os.environ["CLIENT_ID"], "client_secret": os.environ["CLIENT_SECRET"], "scope": "compass:edit" }, headers={ "Content-Type": "application/x-www-form-urlencoded", } ) access_token = token_response.json()["access_token"]

CLIENT_SECRET string

  • 存在する場合、これはこの Compute Module に関連付けられたサードパーティアプリケーションのクライアントシークレットです。関数実行モードの場合、およびアプリケーション権限を使用する場合に存在します。サードパーティアプリケーションのサービスユーザーから Foundry スコープのトークンを取得するために使用します。
  • サンプル値: 038120ac-ac39-4d91-be0e-55afabbb0912
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # app.py import requests import os token_response = requests.post("https://{FOUNDRY_URL}/multipass/api/oauth2/token", data={ "grant_type": "client_credentials", "client_id": os.environ["CLIENT_ID"], "client_secret": os.environ["CLIENT_SECRET"], "scope": "compass:edit" }, headers={ "Content-Type": "application/x-www-form-urlencoded", } ) access_token = token_response.json()["access_token"]

RUNTIME_HOST host

  • Compute Module サービスへの接続に使用するホストです。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: localhost
Copied!
1 2 3 # app.py import os runtime_host = os.environ["RUNTIME_HOST"]

RUNTIME_PORT port

  • Compute Module サービスへの接続に使用するポートです。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: 8945
Copied!
1 2 3 # app.py import os runtime_port = os.environ["RUNTIME_PORT"]

RUNTIME_API hostname

  • Compute Module サービスへの接続に使用する API パスです。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: localhost:8945
Copied!
1 2 3 # app.py import os runtime_api = os.environ["RUNTIME_API"]

GET_JOB_PATH uri path

  • Compute Module サービスからジョブを取得するために使用するパスです。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: /interactive-module/api/internal-query/job
Copied!
1 2 3 # app.py import os get_job_path = os.environ["GET_JOB_PATH"]

GET_JOB_URI uri

  • Compute Module サービスからジョブを取得するための完全修飾 URI です。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: https://localhost:8945/interactive-module/api/internal-query/job
Copied!
1 2 3 # app.py import os get_job_uri = os.environ["GET_JOB_URI"]

POST_RESULT_PATH uri path

  • Compute Module サービスから結果を送信するために使用するパスです。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: /interactive-module/api/internal-query/results
Copied!
1 2 3 # app.py import os post_result_path = os.environ["POST_RESULT_PATH"]

POST_RESULT_URI uri

  • Compute Module サービスに結果を送信するための完全修飾 URI です。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: https://localhost:8945/interactive-module/api/internal-query/results
Copied!
1 2 3 # app.py import os post_result_uri = os.environ["POST_RESULT_URI"]

POST_SCHEMA_URI uri

  • Compute Module サービスにスキーマを送信するための完全修飾 URI です。カスタムクライアントを作成する際に、URI を構成するために使用します。
  • サンプル値: https://localhost:8945/interactive-module/api/internal-query/schemas
Copied!
1 2 3 # app.py import os post_schema_uri = os.environ["POST_SCHEMA_URI"]

MAX_CONCURRENT_TASKS integer

  • ある時点でレプリカに送信できるタスクの最大数です。フロントエンドで設定します。レプリカの実行中に値を変更しても、その変更は反映されません。
  • 使用例: カスタムクライアントを構築する際に、初期スレッドプールを設定します。
  • サンプル値: 1
Copied!
1 2 3 # app.py import os max_concurrent_tasks = os.environ["MAX_CONCURRENT_TASKS"]

SOURCE_CREDENTIALS file path

  • 外部ソースを1つ以上設定した場合にのみ利用可能です。JSON ファイルへのパスで、このファイルのトップレベルのキーは設定済みの外部ソースのAPI名すべて、値は対応するシークレットのマップです。
  • サンプル値: /opt/source-credentials/SOURCE_CREDENTIALS
Copied!
1 2 3 4 5 6 7 8 9 # app.py import json import os with open(os.environ['SOURCE_CREDENTIALS'], 'r') as f: credentials = json.load(f) # 特定のシークレットにアクセスします secret = credentials["<Source API Name>"]["<Secret Name>"]

SOURCE_CONFIGURATIONS_PATH file path

  • 外部ソースを1つ以上設定した場合にのみ利用可能です。JSON ファイルへのパスで、このファイルのトップレベルのキーは設定済みの外部ソースのAPI名すべて、値は対応するシークレットのマップです。このファイルには、設定済みソースに関する追加のメタデータが含まれる場合があります。
  • サンプル値: /opt/source-credentials/SOURCE_CONFIGURATIONS_PATH
Copied!
1 2 3 4 5 6 7 8 9 10 # app.py import json import os with open(os.environ['SOURCE_CONFIGURATIONS_PATH'], 'r') as f: credentials = json.load(f) # 特定のシークレットにアクセスします secrets = credentials["secrets"] url = credentials["httpConnectionConfig"]["url"]

DEFAULT_CA_PATH file path

  • マウントされた CA PEM ファイルへのパスです。Compute Module サービスに接続する際は、この証明書を使用する必要があります。カスタムクライアントを構築する場合にのみ関係します。
  • サンプル値: /etc/ssl/rubix-ca/ca.pem
Copied!
1 2 3 # app.py import os default_ca_path = os.environ["DEFAULT_CA_PATH"]

BUILD2_TOKEN file path

  • パイプライン実行モードでのみ利用可能です。入力および出力リソースをスコープとするトークンを含むファイルです。API ゲートウェイを呼び出す際に使用します。
  • サンプル値: /opt/build2-token/BUILD2_TOKEN
Copied!
1 2 3 # app.py import os build_2_token = os.environ["BUILD2_TOKEN"]

COMPUTE_SESSION_ID string

  • コンテナが実行されているレプリカの一意の識別子です。Compute Module の各レプリカには異なるセッションIDが割り当てられます。
  • サンプル値: ses-7f3a9c2e-4b8d-4e1f-a5c6-9d2e8f4a3b1c
Copied!
1 2 3 # app.py import os session_id = os.environ["COMPUTE_SESSION_ID"]

FOUNDRY_COMPUTE_MODULE_RID rid

  • Compute Module のリソース識別子 (RID) です。
  • サンプル値: ri.foundry.main.deployed-app.3d460200-8861-4e2f-a70c-1be19cd79ae5
Copied!
1 2 3 # app.py import os compute_module_rid = os.environ["FOUNDRY_COMPUTE_MODULE_RID"]

MODULE_AUTH_TOKEN file path

  • 内部の Compute Module サービスとの通信に使用する認証トークンを含むファイルへのパスです。Compute Module サービスのエンドポイントにリクエストを送信する際は、このトークンをヘッダーとして含める必要があります。カスタムクライアントを構築する場合にのみ関係します。
  • サンプル値: /opt/module-auth-token/MODULE_AUTH_TOKEN
Copied!
1 2 3 4 # app.py import os with open(os.environ["MODULE_AUTH_TOKEN"], "r") as f: module_auth_token = f.read()

FOUNDRY_ONTOLOGY_RID rid

  • Marketplace を通じてインストールされた Compute Module で利用可能です。Marketplace のインストールプロジェクトのオントロジーのリソース識別子 (RID) です。オントロジー SDK クライアントを初期化する際にこれを使用して、Compute Module が正しい対象オントロジーを参照するようにします。詳細については、オントロジー SDK の統合のドキュメントを確認してください。
  • サンプル値: ri.ontology.main.ontology.a1b2c3d4-e5f6-7890-abcd-ef1234567890
Copied!
1 2 3 # app.py import os ontology_rid = os.environ["FOUNDRY_ONTOLOGY_RID"]