この記事はKeployのバージョンv2.0.0-alpha53 を前提に執筆しております。
KeployはeBPFを利用して取得できるWebアプリケーションの通信に関するトレース情報を元に、テストとそのテストの実行時に利用するスタブサーバーを生成することができるツールとなります。
公式サイトのトップには以下のようなスローガンが掲げられています。
2 minutes to 90% test coverage!
テストに苦労した経験のある方は興味を惹かれるのではないでしょうか。
現在まだアルファ段階のプロジェクトですが、GitHubスター数は2683(2024/01/04現在)、CNCF Landscape にも掲載されているなど、一定の注目を集め始めているOSSです。
開発主体はプロダクトと同名のKeployというインド発のスタートアップで、去年GoogleによるインドのAIスタートアップ支援プログラムにも選定されたようです。
Keployの機能と特徴について理解するには、例を見るのがわかりやすいと思います。
以下では簡単なアプリケーションにテストを作成して実行する様子を示します。
使用したコードは以下で公開しています。
https://github.com/epli2/keploy-minimal-example
今回は例として以下のようなWeb APIを提供するnode.jsアプリケーションについて見ていきます。dummyjson.comからGETで取得してきたレスポンスをそのまま返却するアプリケーションです。
importexpressfrom"express";const app=express();app.get("/products/:productId",async(req, res)=>{const productId= req.params.productId;const product=await(awaitfetch(`https://dummyjson.com/products/${productId}`)).json(); res.send(product);});app.listen(3000);このアプリケーションをコンテナに詰めて実行し、それをテスト対象として考えましょう。
以下のDockerfileはマルチステージビルドのnodejsイメージを作成するシンプルなパターンに対し、Keployのドキュメント に従って証明書のインストール処理を追加しています。
この証明書のインストールはKeployを利用するに当たってアプリケーション側で必要となる唯一の変更です。
FROM node:20.10-alpine3.19as builderWORKDIR /appCOPY package.json package-lock.json ./RUN npm ci### アプリケーションが行うTLS通信をKeployで読み取れるように証明書をインストールしておく必要がある### 証明書とインストール用スクリプトのダウンロードRUN apk add curlRUN curl -o ca.crt https://raw.githubusercontent.com/keploy/keploy/main/pkg/proxy/asset/ca.crtRUN curl -o setup_ca.sh https://raw.githubusercontent.com/keploy/keploy/main/pkg/proxy/asset/setup_ca.shRUN chmod +x setup_ca.sh###FROM node:20.10-alpine3.19WORKDIR /app### 証明書とインストール用スクリプトのコピーCOPY--from=builder /app/ca.crt .COPY--from=builder /app/setup_ca.sh .RUN apk add bash###COPY--from=builder /app/node_modules ./node_modulesCOPY index.mjs .EXPOSE 3000## 証明書インストール用スクリプトとアプリケーションを実行CMD ["/bin/bash","-c","source ./setup_ca.sh && node /app/index.mjs"]テストの作成は非常に簡単です。
Keployを噛ませてdocker runして
keploy record-c"docker run --name keploy-minimal-example -p 3000:3000 --network keploy-network keploy-minimal-example"--containerName"keploy-minimal-example"curl等で叩いてあげるだけで
curl localhost:3000/products/1以下のように、Keployで実行できるテストケース(test-1.yaml)とスタブの定義(mocks.yaml)が生成されます。
🐰 Keploy: 2024-01-02T13:34:29Z INFO yaml/yaml.go:219 🟠 Keploy has captured test cases for the user's application. {"path": "/files/keploy/test-set-0/tests", "testcase name": "test-1"}% tree keploykeploy└── test-set-0 ├── mocks.yaml └── tests └── test-1.yaml他のテストケースを作るには、そのようにリクエストするだけです。
curl localhost:3000/products/2もう一つのテストケース(test-2.yaml)が作成されました
% tree keploykeploy└── test-set-0 ├── mocks.yaml └── tests ├── test-1.yaml └── test-2.yamlなんとテスト作成の手順はこれだけです。一行もコードを書いていないのに、テストケースとスタブが完成してしまいました。
完成したテストケースとスタブを実行して、アプリケーションをテストしてみましょう。
テスト作成の際と同様に、コマンドは以下の一行を実行するだけです。これだけでKeployはアプリケーションからの外部への通信を自動的にスタブに差し替えてくれるため、アプリケーション側でのコードや設定変更が必要ありません。
keploytest-c"docker run --name keploy-minimal-example -p 3000:3000 --network keploy-network keploy-minimal-example"--containerName"keploy-minimal-example"--delay5実行結果は以下のようになりました。
% keploy test -c "docker run --name keploy-minimal-example -p 3000:3000 --network keploy-network keploy-minimal-example" --containerName "keploy-minimal-example" --delay 52024/01/03 16:30:22 must use ASL logging (which requires CGO) if running as rootlatest: Pulling from keploy/keployDigest: sha256:642b403fc6cc691679c78b5c6803fa01e07d5f36583b6fb6b4e49d677b8aa7f8Status: Image is up to date for ghcr.io/keploy/keploy:latest ▓██▓▄ ▓▓▓▓██▓█▓▄ ████████▓▒ ▀▓▓███▄ ▄▄ ▄ ▌ ▄▌▌▓▓████▄ ██ ▓█▀ ▄▌▀▄ ▓▓▌▄ ▓█ ▄▌▓▓▌▄ ▌▌ ▓ ▓█████████▌▓▓ ██▓█▄ ▓█▄▓▓ ▐█▌ ██ ▓█ █▌ ██ █▌ █▓ ▓▓▓▓▀▀▀▀▓▓▓▓▓▓▌ ██ █▓ ▓▌▄▄ ▐█▓▄▓█▀ █▓█ ▀█▄▄█▀ █▓█ ▓▌ ▐█▌ █▌ ▓ version: 2.0.0-alpha53🐰 Keploy: 2024-01-03T07:30:23Z WARN cmd/test.go:216 Delay is set to 5 seconds, incase your app takes more time to start use --delay to set custom delay🐰 Keploy: 2024-01-03T07:30:23Z INFO cmd/test.go:218 Example usage: keploy test -c "docker run -p 8080:8080 --network myNetworkName myApplicationImageName" --delay 6🐰 Keploy: 2024-01-03T07:30:23Z WARN cmd/test.go:225 buildDelay is set to 30s, incase your docker container takes more time to build use --buildDelay to set custom delay🐰 Keploy: 2024-01-03T07:30:23Z INFO cmd/test.go:226 Example usage:keploy test -c "docker-compose up --build" --buildDelay 35s🐰 Keploy: 2024-01-03T07:30:23Z INFO cmd/test.go:250 {"keploy test and mock path": "/files/keploy", "keploy testReport path": "/files/keploy/testReports"}🐰 Keploy: 2024-01-03T07:30:26Z INFO hooks/loader.go:786 keploy initialized and probes added to the kernel.🐰 Keploy: 2024-01-03T07:30:26Z INFO proxy/proxy.go:437 Keploy has hijacked the DNS resolution mechanism, your application may misbehave in keploy test mode if you have provided wrong domain name in your application code.🐰 Keploy: 2024-01-03T07:30:26Z INFO proxy/proxy.go:451 Proxy started at port:16789🐰 Keploy: 2024-01-03T07:30:26Z INFO test/test.go:346 running user application for {"test-set": "test-set-0"}🐰 Keploy: 2024-01-03T07:30:26Z INFO proxy/proxy.go:608 starting DNS server at addr :16789🐰 Keploy: 2024-01-03T07:30:26Z INFO hooks/launch.go:557 trying to inject network:keploy-network to the keploy container🐰 Keploy: 2024-01-03T07:30:26Z INFO hooks/launch.go:595 Successfully injected network to the keploy container {"Keploy container": "keploy-v2", "appNetwork": "keploy-network"}Java is not installed on the systemNODE_EXTRA_CA_CERTS is set to: /tmp/ca.crtREQUESTS_CA_BUNDLE is set to: /tmp/ca.crtSetup successful🐰 Keploy: 2024-01-03T07:30:26Z INFO hooks/launch.go:438 container & network found and processed successfully {"time": 1704267026933290180}🐰 Keploy: 2024-01-03T07:30:26Z INFO test/test.go:396 {"no of test cases": 2, "test-set": "test-set-0"}🐰 Keploy: 2024-01-03T07:30:31Z INFO pkg/util.go:65 starting test for of {"test case": "test-1", "test set": "test-set-0"}Testrun passed for testcase with id: "test-1"--------------------------------------------------------------------🐰 Keploy: 2024-01-03T07:30:32Z INFO test/test.go:435 result {"testcase id": "test-1", "testset id": "test-set-0", "passed": "true"}🐰 Keploy: 2024-01-03T07:30:32Z INFO pkg/util.go:65 starting test for of {"test case": "test-2", "test set": "test-set-0"}Testrun passed for testcase with id: "test-2"--------------------------------------------------------------------🐰 Keploy: 2024-01-03T07:30:32Z INFO test/test.go:435 result {"testcase id": "test-2", "testset id": "test-set-0", "passed": "true"}🐰 Keploy: 2024-01-03T07:30:32Z INFO test/test.go:515 test report for test-set-0: {"name: ": "report-5", "path: ": "/files/keploy/report-5"} <=========================================> TESTRUN SUMMARY. For testrun with id: "test-set-0" Total tests: 2 Total test passed: 2 Total test failed: 0 <=========================================> 🐰 Keploy: 2024-01-03T07:30:32Z INFO hooks/loader.go:365 keploy has initiated the shutdown of the user application.🐰 Keploy: 2024-01-03T07:30:42Z WARN hooks/launch.go:534 userApplication has exited with exit code: 137🐰 Keploy: 2024-01-03T07:30:42Z INFO test/test.go:353 keploy terminated user application🐰 Keploy: 2024-01-03T07:30:42Z INFO test/test.go:253 test run completed {"passed overall": true}🐰 Keploy: 2024-01-03T07:30:42Z INFO hooks/loader.go:421 Exiting keploy program gracefully.🐰 Keploy: 2024-01-03T07:30:43Z INFO hooks/loader.go:471 eBPF resources released successfully...🐰 Keploy: 2024-01-03T07:30:43Z INFO proxy/proxy.go:1023 Dns server stopped🐰 Keploy: 2024-01-03T07:30:43Z INFO proxy/proxy.go:1025 proxy stopped...アプリケーション起動後、作成したふたつのテストが成功し、シャットダウンして終了していることがわかります。
ここまでの例だけでも、以下のことがわかります。
さらに、例では紹介しきれていない以下の特徴や機能も持っています。
これらの特徴や機能を総合して考えると、冒頭で紹介したスローガンである2 minutes to 90% test coverage!も大袈裟な話ではないのかもしれないと思いました。
Keployをバインドしたアプリケーションをデプロイし、既存の手動テストシナリオを実行すればそれだけで自動テストが完成しますし、テスト時には外部通信がすべてスタブ化されるため、テスト自体の安定性も高いと想像できます。
アプリケーション全体の実行が必須となるため、実行オーバーヘッドの関係からユニットテストを完全に置き換えることはないと思いますが、うまく棲み分けることで効率的なテストを実現できそうです。
また、実装言語を問わず使用できるため、システムの開発言語やフレームワークを変更する際のテストなどでは特に強力なツールになるのではないかと思います。
加えて、まだ実現されていない機能としてパフォーマンステストの実行があるのですが、これも実現すれば性能面でのリグレッションテストを容易に実施できそうで、期待したいところです。
Keployを使ってみたくなった方もいるのではないでしょうか。
https://keploy.io/docs/ で各環境へのインストール方法が説明されているので、基本的にはそちらを読んでいただきたいですが、まだアルファバージョンということもあり、いくつかつまづくポイントがあったので、私が試したApple SiliconのMacでの導入手順を書いておきます。
今回私はMac+Colimaで環境構築しましたが、KeployはeBPFを扱うため、おそらくネイティブなLinux環境でが最も利用しやすいと思います。公式Docにも以下のような記述があります。
⚠️ Please note that Keploy v2 is currently in development, with the best experience on Linux. Docker support is experimental and may have some limitations for certain use cases.
公式ドキュメントでは、以下のコマンドを実行するだけとあります。
curl-O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh&&source keploy.sh私のMacではIntel Macから移行ユーテリティで環境をコピーしていた関係でHomebrewがIntel版になっていたため、インストール後うまく動作しませんでした(どういうエラーが出たかは忘れてしまいました)。
Apple Silicon Macをお使いの方は、which brewの結果が/opt/homebrew/bin/brewでない場合はarm版のHomebrewをインストールしてパスを通してからインストールコマンドを実行してください。
(こちらの記事にお世話になりました。https://zenn.dev/omakazu/scraps/b3a4be96741a22)
上記のインストールコマンドを実行すると対話形式で以下のように質問されます。Dockerを使ったインストールができそうに見えます。しかし私の環境ではうまく動作しませんでした。Colimaを選択するのが良さそうです。 (追記: Dockerバージョン4.25.2以降であれば動作可能なようです)Do you want to install keploy with Docker or Colima? (docker/colima):
ドキュメントには以下のようにエイリアスを作るように書かれていますが、この通り設定するとkeployコマンドが途中で終了してしまうなど不安定でした
aliaskeploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --network keploy-network --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/keploy/keploy'私は-tオプションを削って以下のようにし、~/.zshrcに追加しています。
aliaskeploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --network keploy-network --privileged --pid=host -i -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/keploy/keploy'(この問題は後でissue立てておこうと思っています)
③まででKeploy自体のインストールはなんとかこなせるのではないかと思います。
最後に、アプリケーションコンテナの設定でつまづきました。
既知のバグとして、アプリケーションのコンテナが古いDebianの場合keploy testがうまく動作しないというものがあり、私はnode:18.19-bullseyeをベースイメージとして使おうとしてこれを踏みました。バグが修正されるまでは、新しいDebianかalpineなど他のOSをベースイメージにしましょう。
https://github.com/keploy/keploy/issues/645
以上私がつまづいたポイントでした。公式でサポート用のSlackも用意されているようですので、もしご自身でインストールされる際に困ったことがあればそちらで聞いてみるのも良いかもしれません。
Keployの使い方や特徴を見てきました。ツールの魅力が少しでも伝わればよいなと思っています。
昨年末にeBPFについて調べていたときに偶然見つけたOSSでしたが、そのポテンシャルの高さに驚き、日本語での紹介も見当たらなかったため、拙いながらこのように記事にさせていただきました。
Web開発で利用できるeBPFによるツールは近年多く誕生しており、近い将来には新たなスタンダードとなるものも多いのではないかと感じております(個人的には同じくテストツールのhttps://tracetest.io/ にも注目しています。o11yに関するeBPFツールはたくさんありますが、既存のAPM製品と競合するものが多い気がしていて、それらと比べるとKeployやTracetestのような今までできなかったことを実現するツールに惹かれる)。Keployの今後の動向も含め、eBPFによってソフトウェア開発がどのように変わっていくのか継続的に見ていきたいと思います。
バッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。
