Goreplayを入れた話

エイチームフィナジーアドベントカレンダー8日目は私 @NMura3 が担当します。

## 概要
サービス運用していると、プログラム言語やフレームワーク、OSやライブラリーのバージョンアップがつきまといます。
その際に起きてほしくはないですが、障害が発生してサービス停止する場合があります。
どんなに入念にテストしたり、準備をしても一定数発生してしまうことはありませんか？

そんな時に便利に検証できるのがGoreplayになります。

## Goreplayとは
GoReplayはGoで開発されたOSSのネットワークモニタリングツールです。
https://goreplay.org/

流れてくるリクエストをキャプチャして、他のサーバーに同じリクエストを流すことができます。
つまり、テスト環境やステージング環境に本番にくるリクエストを流して、本番のリクエストでテストが可能になります。

また、リクエスト数も本番と同様になるので、負荷テストも可能です。

![go-replay.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17939/339184fb-f38a-2223-9820-19d3b35ad093.png)


## インストール
GOで開発されているのでインストールは非常に簡単で、パスの通ったディレクトリに実行権限をつけてダウンロードするだけです。

### インストール例
```shell
export GOREPLAY_VERSION=1.3.3
wget -q -O - https://github.com/buger/goreplay/releases/download/${GOREPLAY_VERSION}/gor_${GOREPLAY_VERSION}_x64.tar.gz | tar -xz -C /usr/local/bin
```
注意) バージョンによって微妙にパスが違うので注意してください。

### 実行例

#### ポート(80番)を指定して標準出力に出す
```shell
gor --input-raw ":80" \
    --output-stdout
```

#### ポート(80番)を指定してテスト環境にリクエストを流す
```shell
gor --input-raw ":80" \
    --output-http https://test.example.com
```

#### ポート(80番)を指定してテスト環境に50%のリクエストを流す
```shell
gor --input-raw ":80" \
    --output-http "https://test.example.com|50%"
```

#### ポート(80番)を指定してテスト環境にフィルターしたリクエストを流す
```shell
gor --input-raw ":80" \
    --output-http https://test.example.com
    --http-allow-url /path1 \
    --http-allow-url /path2
```

HTTPサーバーやAPPサーバーにログインできるのであれば、上記コマンドを実行すると即座にリクエストを別環境に流してくれます。
Dockerなどコンテナで運用している場合はCIと組み合わせて実行すると便利です。
AWSのECS、GCPのCloudRunで使用する例をあげます。

## AWS ECS + Goreplay
まずはDockerfileにGoreplayのインストールを記述します。

```shell
# Goreplay
ARG GOREPLAY_VERSION=1.3.3
RUN wget -q -O - https://github.com/buger/goreplay/releases/download/${GOREPLAY_VERSION}/gor_${GOREPLAY_VERSION}_x64.tar.gz | tar -xz -C /usr/local/bin
```

`ENTRYPOINT`や`CMD`で実行するシェル内にGoreplayの起動コマンドを記述します。
その際に環境変数から起動の有無をしておき、環境変数をCIから設定するようにしておくと便利です。
(通常はGoreplayを起動し、リクエストを流したい時に環境変数が設定されるCIのジョブでリリースするようにしておくなど)

```shell
if [ "$GOREPLAY_LISTEN" = "true" ]; then
  gor --input-raw ":80" \
    --output-http https://test.example.com
    --http-allow-url /path1 \
    --http-allow-url /path2 &
fi
```
※ `&`つけて非同期実行しておきます。

ECSの場合はそれほど難しくなく、導入できると思います。

## GCP CloudRun + Goreplay
Goreplayの場合はECSと同様に設定して実行しても起動できません。
下記のようなエラーが出ると思います。

```
PCAP Activate error: Permission Denied
```

パケットキャプチャができないというエラーです。
Goreplayはネットワークキャプチャするので、ネットワークデバイス(eth01とか)へアクセスします。
その際に呼ばれるのが`ioctl`というシステムコールなのですが、これがCloudRunの場合は制限を受けています。
CloudRunはgVisorというサンドボックス環境下で動いており、そこもドキュメントに下記の記述があります。

https://gvisor.dev/docs/user_guide/compatibility/linux/amd64/#ioctl
 > `Only a few ioctls are implemented for backing devices and file systems.
`

これによりCloudRunではGoreplayを使えないと思っていたのですが、10月末にCloudRunあるプレビューリリースが行われました。

https://cloud.google.com/run/docs/about-execution-environments

これによると、CloudRunの実行環境で**第二世代**がリリースされ、その第二世代ではシステムコールの制限を受けないというものです。


### 適用

第二世代についてはまだプレビュー版なので、それで本番環境を動かすことになるのでお気をつけください。
第二世代はCloudSDKを最新にあげて、betaコマンドをインストールするとSDKから使用可能です。
また画面からも設定はできます(私はしたことがないですが。。。)

CloudSDKでdeploy する場合は　gcloud beta インストールをして、`--execution-environment`のオプションをつけると第二世代を使用できます。

```shell
# インストール
gcloud components install --quiet beta

# 第二世代でdeploy
gcloud beta run deploy example_service --execution-environment=gen2
```

## 注意点
Goreplayを使う上で一つ重要なことがあります。
それは本番のリクエストに**個人情報**や**機密情報**があった場合には注意が必要です。

リクエストを流す先(テスト環境)に本番のリクエストが行くので、そのログやDBに個人情報や機密情報が入ってしまいます。
プロダクトやサービスによっては情報流出の原因となるので、そこは十分にご注意ください！！

## まとめ
いかがだったでしょうか？

Goreplayはプログラム言語やフレームワーク、ライブラリーのバージョンアップ時に本番リクエストでテスト可能です。
また、プラットフォームの構成を見直す際に本番のリクエストで負荷テストが可能です。

エイチームフィナジーアドベントカレンダー16日にCloudRunでリリースされた、実行環境第二世代とAlwaysCPUの検証の際にGoreplayを使用した記事を投稿するのでお楽しみに