# 使用 APM-Integratoin-Testing 建立 Elastic APM 的模擬環境

### 本篇學習重點

* 如何使用 Elastic 官方提供的 APM Integration Testing 工具

## 前言

前面的章節介紹了 Elastic APM，由於 Elastic APM 的運作，會需要有實際的應用程式及服務，讓使用者把 APM Agent 埋進去，同時也要有足夠複雜的情境，才能展示 APM 的相關功能，因此在這邊直接使用 Elastic 官方所提供的一個開放原始碼的專案 - APM Integration Testing，讓我們透過這個專案所建立的情境，快速的架設一組實際的 Elastic APM 解決方案及實用實例，從中學習 Elastic APM 的佈署方式與使用方法。

## 簡介 APM Integration Testing

[APM Integration Testing](https://github.com/elastic/apm-integration-testing) 是一個公開在 GitHub 的開放原始碼的專案，這個專案主要語言是用 Python 撰寫，並且使用 Docker 來運作 Elastic Stack 的各種服務以及 opbeans 這個 Demo 專用的庫存管理系統，讓我們能夠擁有一個 Elastic APM 所需要執行的情境，並且能夠將當中的某些元件替換成真實運作的版本，可以協助開發人員進行 debug，或是協助整合測試 (Integration Test) 所需使用的複雜的環境。

### 包含的角色

以下幾種角色，是 APM Integration Testing 的 Docker Containers 運作起來時，裡面有的角色：

* Elastic Stack
  * Elasticsearch
  * Kibana
  * APM Server
  * Heartbeat
  * Filebeat
  * Metricbeat
  * Packetbeat
* opbeans 庫存管理系統的各種語言版本的實作，並且埋入 APM Agent
  * opbeans-go
  * opbeans-java
  * opbeans-ruby
  * opbeans-dotnet
  * opbeans-node
  * opbeans-python
* 針對 opbeans 庫存管理的系統的 node.js 版本，實作 Real User Monitoring
  * opbeans-rum
* opbeans 所使用到的 Database 或是 Cache 等服務
  * PostgreSQL
  * Redis
* 自動模擬存取流量的 opbeans-load-generator
* 專門製造錯誤情況發生，讓壓測能更擬真的 Dyno

APM Integration Testing 就是以這些角色組成一個讓我們可以進行測試及使用的環境，以下畫面，是使用預設配置所建立的環境當中所包含的角色：

![18-apm-tools-service-map](https://i.imgur.com/bR93Z78.png)

## 安裝 APM Integration Testing

接下來說明安裝 APM Integration Testing 的步驟及要注意的事項。

### 準備環境

在執行 APM Integration Testing 的環境，我們會需要準備：

* Docker
* Docker compose
* Python 3

> 注意：Mac M1 目前實測 build 到 RUM 的部份時，會發生 chrome 相關套件的錯誤，所以請不要用 M1 來執行。

### 執行 APM Integration Testing

要執行 APM Integration Testing，首先我們將整個專案從 GitHub 抓下來：

```
git clone https://github.com/elastic/apm-integration-testing.git
```

裡面有一個 Python 程式 `./scripts/compose.py`，會是主要的執行檔，我們先透過這們程式來安裝一個『完整版』的環境：

```
./scripts/compose.py start --all 7.15.0 --release
```

主要的參數如下：

* `start`：初始化並且啟動整個所有的環境。
* `--all`：完整版的各種服務及元件都會進行安裝
* `7.15.0`：Elastic Stack 的指定版本
* `--release`：使用 release 的版本 (如果不指定的話，會使用 snapshot 的版本)。

其他可選用的參數，因為支援的參數非常非常多，我這邊只舉幾個例子：

* `--with-opbeans-java`：當我們不使用 `--all` 時，可以指定我們要安裝哪些版本的 opbeans 環境。
* `--no-apm-server`：不要啟動 APM Server。
* `--no-kibana` 、 `--no-elasticsearch`：不要啟動 Kibana、Elasticsearch，也可以另外指定外部的 Elasticsearch 或 Kibana。
* `--with-dyno`：啟動 Dyno Mode。

一開始執行時，因為會 build 相關的 Docker image，會跑蠻久的，以下是執行的 gif 畫面。

![apm-int-testing-compose](https://i.imgur.com/RLk2eyJ.gif)

### Docker-Compose

當執行完 `start` 之後，會在執行的目錄底下，建立一個 `docker-compose.yml` 的檔案，並且實際執行的運作，就是透過 `docker-compose` 運作起來。

因此我們後續可以使用 `docker-compose stop` 、 `docker-compose up` 等指令來停止或啟動，也可以直接去修改 `docker-compose.yml` 裡面的一些配置。

## 查看 APM Integration Testing 所建立的環境

當安裝及佈署完成之後，我們可以直接從 Kibana 查看，這邊注意預設是有開啟 `X-Pack Security`，並且預設的密碼會是 `changeme`：

![18-kibana-login](https://i.imgur.com/OY9Qmik.jpg)

登入之後，我們就可以在 Observability 的畫面，查看由 APM Integration Testing 這個環境及裡面的流量產生工具，所產生出來的各種服務存取的資訊，我們就有許多 APM 的資料可以來查看 APM 所提供的功能。

以下是使用 gif 檔來錄製操作的畫面：

![18-apm-int-testing-kibana-overview](https://i.imgur.com/7zaYv6s.gif)

## 壓測時的好幫手 - Dyno Mode

APM Dyno 是一個能幫我們在 opbeans 的這些運作的 demo 環境之中，建立出一些情境，這些情境是能協助我們進行壓測時，能模擬出更接近真實情境的環境，

例如：

* 容器裡的 CPU 能力
* 容器裡的 Memory 數量
* 網路的 latency
* 網路頻寬
* 網路不穩的狀況
* 產生壓測請求的 worker 數量
* 產生一定比例的 Error rate

這些功能有透過 UI 的方式讓我們能直接進行調整，並且可以針對某一台 Container 進行指定。

![18-apm-dyno](https://i.imgur.com/YD4u2lp.png)

不過 Dyno mode 只有提供 `opbeans-python` 版本能使用，並不是所有的 opbeans 版本都支援。

> 注意：官方文件寫的指令 `--dyno` 實際使用時發現是寫錯的，是要帶入 `--with-dyno` 才是正確的。

## 使用雲端主機服務 AWS 或 GCP

文件中有特別提到，如果使用的是 AWS、GCP 這種雲端主機服務時，要用 APM Integration Testing 的這個工具，可以透過 port forwarding 的方式來轉接。

例如以下在 `~/.ssh/config` 定義 `gcptunnel` 的這台主機：

```
Host gcptunnel
    HostName <my.gcp.host.ip>
    IdentityFile ~/.ssh/google_compute_engine           <--- yours may differ
    User jamie                                          <--- yours probably differs
    Compression yes
    ExitOnForwardFailure no
    LocalForward 3000 127.0.0.1:3000
    LocalForward 3001 127.0.0.1:3001
    LocalForward 3002 127.0.0.1:3002
    LocalForward 3003 127.0.0.1:3003
    LocalForward 3004 127.0.0.1:80
    LocalForward 5601 127.0.0.1:5601
    LocalForward 8000 127.0.0.1:8000
    LocalForward 9200 127.0.0.1:9200
    LocalForward 9222 127.0.0.1:9222
```

並使用 `ssh gcptunnel` 來執行。

## 參考資料

1. [GitHub: APM Integration Testing](https://github.com/elastic/apm-integration-testing)
