この記事は、AWS Containers Advent Calendar 2023 の 19 日目 (12/19) のエントリーです。
PHP のフレームワーク Laravel で、ADOT (AWS Distro for OpenTelemetry) を利用した trace の送信を試した備忘録です。
正直、設定の書き方がわかっていないので、正しい書き方などのツッコミをお待ちしております。
AWS Distro for OpenTelemetry とは、OpenTelemetry プロジェクトの AWS がサポートするディストリビューションです。
各言語ごとの対応状況は以下にあります。
https://opentelemetry.io/docs/instrumentation/#status-and-releases
PHP が trace に対応しているため、PHP Laravel を利用して trace の送信を試してみます。
基本的にはこちらの手順を参考にして trace を AWS X-Ray に送信します。
Laravel プロジェクト作成
Composer を使ってパッケージ/ライブラリ管理を行うため、まず Composer をインストールします。
インストール手順は こちら にありますが、Mac だと brew でインストール することができます。
$ brew install composer
こちらの手順 に沿って、Laravel のプロジェクトを作成します。
$ composer create-project laravel/laravel example-app
Laravel を起動します。
$ cd example-app
$ php artisan serve
http://localhost:8000 にアクセスすると初期画面が表示されます。
OpenTelemetry の自動計装
Automatic Instrumentation を使ってみます。
Automatic Instrumentation を利用するには、PHP 8.0 以上と、OpenTelemetry の PHP 拡張モジュール が必要です。
拡張モジュールは pecl、 pickle 、 php-extension-installer が利用可能です。
それぞれの方法での インストール方法はこちら にあります。今回は pecl でのインストールを行ってみます。
pecl は PHP 拡張モジュールのリポジトリで、 pear パッケージシステムを経由して使用可能です。
まずソースからビルドするために必要なものを設定します。
$ brew install gcc make autoconf
pecl で OpenTelemetry の PHP 拡張モジュールをビルド、インストールします。
$ pecl install opentelemetry
ここでいくつかエラーがでました。
Build process completed successfully
Installing '/usr/local/Cellar/php/8.3.0/pecl/20230831/opentelemetry.so'
Warning: mkdir(): File exists in System.php on line 294
PHP Warning: mkdir(): File exists in /usr/local/Cellar/php/8.3.0/share/php/pear/System.php on line 294
Warning: mkdir(): File exists in /usr/local/Cellar/php/8.3.0/share/php/pear/System.php on line 294
ERROR: failed to mkdir /usr/local/Cellar/php/8.3.0/pecl/20230831
/usr/local/Cellar/php/8.3.0/pecl/20230831
が無いようです。
確認してみると、/usr/local/Cellar/php/8.3.0/pecl
は /usr/local/lib/php/pecl
のシンボリックリンクになっていましたが、pecl
というディレクトリが作られていませんでした。
$ cd /usr/local/lib/php/
$ ll
total 0
lrwxr-xr-x@ 1 kajihiro admin 39 12 17 00:32 20230831 -> ../../Cellar/php/8.3.0/lib/php/20230831
lrwxr-xr-x@ 1 kajihiro admin 36 12 17 00:32 build -> ../../Cellar/php/8.3.0/lib/php/build
原因までは調べていませんが、pecl
ディレクトリを作成し、20230831
ディレクトリの中身をコピーしたところ正常にインストールが行われました。
php.ini に拡張モジュールを設定し、確認します
extension=opentelemetry.so
$ php -m | grep opentelemetry
opentelemetry
これで OpenTelemetry の PHP 拡張モジュールが設定されました。
しかし、 2023年12月時点では、Automatic Instrumentation は trace に対応していないようです・・・
https://opentelemetry.io/docs/instrumentation/php/automatic/
Installing the OpenTelemetry extension by itself will not generate traces. You must also install the SDK and one or more instrumentation packages for the frameworks and libraries that you are using, or alternatively write your own.
なので、trace を送る設定を手動で入れていきます。
OpenTelemetry の手動計装
手動での trace の設定は こちらの手順 で進めていきます。
PHP 用 OpenTelemetry SDK を使用するには、psr/http-client-implementation と psr/http-factory-implementation の依存関係を満たすパッケージが必要です。ここでは、両方を提供する Guzzle を使用します。
PSR (PHP Standards Recommendations) とは、PHP-FIG (PHP Framework Interop Group) が策定している PHP のコーディング規約です。
必要なパッケージをインストールしていきます。
$ composer require guzzlehttp/guzzle
$ composer require \
open-telemetry/sdk \
open-telemetry/exporter-otlp
こちらの手順 を見ながら trace の計装をしていきます。
require __DIR__.'/../vendor/autoload.php';
use OpenTelemetry\API\Globals;
$tracerProvider = Globals::tracerProvider();
$tracer = $tracerProvider->getTracer(
env('OTEL_SERVICE_NAME'),
'1.0.0', //version
env('OTEL_EXPORTER_OTLP_ENDPOINT'), //schema url
);
$span = $tracer->spanBuilder(env('OTEL_SERVICE_NAME'))->startSpan();
//do some work
$span->end();
※設定値を環境変数から読み込むようにしています。
が、ここでエラーが発生しています。
Use of unknown class: 'OpenTelemetry\\API\\Globals'
どうやら必要なパッケージが足りないようなので追加をします。
$ composer require open-telemetry/api
Laravel 起動
関連するコンポーネントと一緒に Laravel を起動し、HTTP でリクエストを受けるために docker compose を利用して構築を行います。この際に trace を送るための otel-collector コンテナも一緒に起動します。
ファイル構成は以下のようになっています。
php
├── nginx
│ ├── Dockerfile
│ └── conf.d
│ ├── default.conf
│ └── default.conf.template
└── phpfpm
├── Dockerfile
├── example-app
└── php.ini
FROM nginx:alpine
ADD ./conf.d /etc/nginx/conf.d
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
後に記載しますが、envsubst を使って環境変数から設定を持ってくるようにしています。
server {
listen 8080;
charset utf-8;
root /var/www/html/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass ${LARAVEL_HOST}:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
nginx のビルドの際に環境変数から値を取得して default.conf を生成するようにしています。
version: '3'
services:
nginx-php:
build:
context: ./php/nginx
dockerfile: ./Dockerfile
volumes:
- ./php/phpfpm/example-app:/var/www/html
ports:
- 8080:8080
depends_on:
- phpfpm
environment:
LARAVEL_HOST: phpfpm
command: sh -c "envsubst '$$LARAVEL_HOST' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
phpfpm:
build:
context: ./php/phpfpm
dockerfile: ./Dockerfile
volumes:
- ./php/phpfpm/example-app:/var/www/html
ports:
- 9000:9000
environment:
OTEL_PHP_AUTOLOAD_ENABLED: true
OTEL_SERVICE_NAME: "local-laravel-app"
OTEL_TRACES_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT: 'http://otel-collector:4318'
OTEL_PROPAGATORS: baggage,tracecontext
otel-collector:
image: public.ecr.aws/aws-observability/aws-otel-collector:latest
command: [ "--config=/etc/otel-agent-config.yaml" ]
environment:
- AWS_PROFILE=default
- AWS_REGION=us-east-1
volumes:
- ./otel-config.yaml:/etc/otel-agent-config.yaml
- ~/.aws/credentials:/root/.aws/credentials:ro
- ~/.aws/config:/root/.aws/config:ro
ports:
- 4317:4317
- 4318:4318
otel-collector が AWS X-ray の API を実行できるように credential 情報を渡しています。こちらはローカルで実行する場合の設定なので、ローカル PC に保存されている credential 情報をコンテナの volume に渡して利用しています。
environment:
- AWS_PROFILE=default
- AWS_REGION=us-east-1
volumes:
- ./otel-config.yaml:/etc/otel-agent-config.yaml
- ~/.aws/credentials:/root/.aws/credentials:ro
- ~/.aws/config:/root/.aws/config:ro
コンテナを起動します。
コンテナ開発用のオープンソースクライアント「Finch」を利用しています。
$ finch compose -f docker-compose.yaml up -d
localhost で起動している nginx にアクセスします。
Trace データの確認
AWS X-ray に trace が送られているか確認します。
無事 trace データが送られていました。
まとめ
ローカルの Laravel から OpenTelemetry を利用して trace を送る手順を試してみました。
本番環境で動かす場合 (Amazon EKS や Amazon ECS で動かす場合) は、credential や環境変数の情報を適宜 AWS Systems Manager Session Manager や AWS Secrets Manager に保存・利用してください。