OCI APMでOKE上のコンテナアプリケーションをトレーシングしてみよう

# はじめに
Oracle Cloud Infrastructure(以下、OCI)には、分散トレーシングを提供するOCI APMというマネージドサービスがあります。
本記事では、OKEにサンプルアプリケーションをデプロイしてOCI APMからトレーシングをしてみたいと思います。

# 分散トレーシングとは
Cloud Nativeな文脈では、Observabilityの一つの要素になり、各アプリケーション間のトランザクションや通信の状況を把握するための営みになります。
例えば、大量のサービスが連携しているマイクロサービス下でパフォーマンスの低下などが発生した場合にどのアプリケーション部分が原因になっているかを特定することができます。
![スクリーンショット 2021-10-14 16.12.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/2427e643-0a17-e00a-933c-f744f33221ea.png)

# OCI APMとは
[OCI APM](https://docs.oracle.com/ja-jp/iaas/application-performance-monitoring/index.html)は[Oracle Cloud Observability and Management Platfotm](https://www.oracle.com/jp/manageability/)の中のサービスの一つです。
その中でもOCI APMは、分散トレーシングや合成モニタリングなどを提供するサービスになります。

今回は、このOCI APMを利用して、OKE上のコンテナアプリケーションをトレーシングしてみたいと思います。

# 事前準備

まずは、事前準備をしていきます。

事前準備は以下の4つです。

* ポリシーの作成
* APMドメインの作成
* OCIRレポジトリ作成
* OKEクラスタの準備
* サンプルアプリケーションの準備

## ポリシーの作成

OCIでは各サービスを利用するためにポリシーを作成する必要がある場合があります。
OCI APMを利用する場合にもポリシーが必要なので、作成していきます。
トライアル環境や管理者権限をお持ちの環境で実施する場合は本手順は不要ですので、無視してください。

OCIコンソールのハンバーガーメニューを開き、「アイデンティティとセキュリティ」から「ポリシー」を選択します。 

 ![6-001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/c1e2cf83-1def-b536-fae8-c76b772d55eb.png)

「ポリシーの作成」をクリックします。  

![5-005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/5f88d456-a6e8-244a-faae-81ef03bf99b1.png)


以下の情報を入力します。  
また、「手動エディタの表示」にチェックを入れます。  

key|value
-|-
名前| apm_policy
説明| apm_policy
コンパートメント | ご自身のコンパートメント名
ポリシー | `Allow group APM-Admins to manage apm-domains in compartment id <ご自身のコンパートメントOCID>`


![6-002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/3b91344a-6045-9e21-e36d-bb02bab1fa14.png)


画像はイメージですので、コンパートメントOCIDはご自身の環境に合わせて読み替えてください。 

「作成」をクリックします。  

これで、ポリシーの設定は完了です。  

## APMドメインの作成

ここでは、APMドメインの作成を行います。  

OCIコンソールのハンバーガーメニューを開き、「監視および管理」から「アプリケーション・パフォーマンス・モニタリング」カテゴリの「管理」を選択します。  

![6-003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/dd55d722-5b22-8a7f-f89a-9660e0cb9c0f.png)

「APMドメインの作成」をクリックします。  

![6-004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/ca43b006-31a4-fab8-9fcd-ee9da4edb749.png)

以下の情報を入力します。 

key|value
-|-
名前| oke-handson-apm
説明| oke-handson-apm

「作成」をクリックします。

![6-005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/1ed6dea9-4c32-10fb-ce09-a906a957bb3d.png)

ドメインが「作成中」のステータスになるので、「アクティブ」になるまで待機します。

![6-006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/11c98c32-c37b-0c37-ceb9-6b25c1272a13.png)

ドメインが「アクティブ」になったら、ドメイン名の箇所をクリックします。

「APMドメイン情報」の「データ・アップロード・エンドポイント」と「データ・キー」の「プライベート」キーの値をコピーし、エディタなどに記録しておきます。  
この値は、アプリケーション側からトレーシング情報をAPMにアップロードする際のエンドポイントとその際に利用するキーになり、後ほど利用します。

![6-007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/1fc6695f-3038-aba2-71cb-4fd166e9abf1.png)

![6-008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/5046d99b-cade-4386-6c60-c75ffe047524.png)


これで、APMドメインの作成は完了です。

## OCIRレポジトリの作成

後続手順で、サンプルアプリケーションをビルドして、コンテナイメージを作成します。  
そのコンテナイメージを格納するコンテナイメージレジストリのセットアップを行います。  

左上のハンバーガーメニューをクリックして、「開発者サービス」-「コンテナ・レジストリ」を選択します。

![1-3-001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/c74a55bf-ff7c-067c-bfab-8d5eacc9f7b3.png)


「リポジトリの作成」ボタンをクリックします。

![1-3-002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/adef5d05-e00c-1ea0-3153-4e2fe5a18162.png)


「リポジトリ名」に「frontend-app-apm」と入力、「アクセス」で「パブリック」を選択して、「リポジトリの作成」ボタンをクリックします。

![1-3-003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/7907fb10-2e83-936f-f75f-46467021f84d.png)

次に、OCIRにコンテナイメージをプッシュする際に必要となる、「Username」と「Password」を取得します。

「Username」は、`<オブジェクト・ストレージ・ネームスペース>/<ユーザ名>` となります。

＜ユーザ名＞を確認します。ユーザ名は右上にある「プロファイル」アイコンをクリックして、プロファイル名を選択します。

![1-3-004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/58f31602-4e85-4fb2-64c3-4b6221c093e9.png)

「ユーザーの詳細画面」の赤枠箇所をコピーして、テキストエディタにペーストしておきます。

![1-3-005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/eac9750e-440a-e372-48e7-a99592adb4d1.png)

次に、＜オブジェクト・ストレージ・ネームスペース＞を確認します。

右上にある「プロファイル」アイコンをクリックして、「テナンシ」を選択します。

![1-3-006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/08e25ea7-26fe-7931-bc5e-12ec4e2176d0.png)

「テナンシ詳細」の「オブジェクト・ストレージ・ネームスペース」の赤枠箇所をコピーして、テキストエディタにペーストしておきます。

![1-3-007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/4bcf9133-f3ec-05aa-0f7d-7a9b269c8c2e.png)

次に、「Password」となる認証トークンを設定します。

右上にある「プロファイル」アイコンをクリックして、プロファイル名を選択します。

![1-3-008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/b8eb9c08-d368-2c42-838c-a7672193a417.png)

左メニュー「認証トークン」を選択します。

![1-3-009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/980449b5-20e4-4548-c4a2-68ce80b0c7cd.png)

「トークンの作成」をボタンをクリックします。

![1-3-010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/0c6a3c32-9142-5b4f-01a0-c570b5af1142.png)

「説明」に「oke-handson-apm」と入力して、「トークンの生成」ボタンをクリックします。

![1-3-011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/df666d63-a14d-7679-e8b1-9f9a2f24519c.png)

「コピー」をクリックして、「閉じる」ボタンをクリックします。  コピーした認証トークンは、後の手順で必要となるので、テキストエディタなどにペーストしておきます。

![1-3-012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/2c7abc56-5435-8803-20e6-5a7e1c15fdd0.png)

以上で、認証トークンの作成は完了です。

以下、テキストエディタにペーストした内容に当てはめて利用します。

|key|value 
|---|---|
Username|`<オブジェクト・ストレージ・ネームスペース>/<ユーザ名>`
Password| `認証トークン`

以上でOCIRのセットアップは完了です。

## OKEクラスタの準備

OKEクラスタは[こちら](https://oracle-japan.github.io/ocitutorials/cloud-native/oke-for-commons/)の手順を参考に構築してください。

## サンプルアプリケーションの準備

APMの動作確認用に簡単なアプリケーションを用意しました。
東京2020オリンピック・パラリンピック大会のメダル獲得者の一覧を表示するアプリケーションです。

![2-1-001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/7246f493-8996-0582-0320-2d57bdd59fa6.png)


以下のレポジトリを利用します。

```shell
git clone https://github.com/oracle-japan/code-at-customer-handson
```

今回のアプリケーションはHelidonを利用した構成になっています。
Helidonについては[こちら](https://qiita.com/takuya_0301/items/c3b45b314a9c14b1c8d6)の記事で取り上げていますが、マイクロサービスに適したJavaアプリケーションフレームワークです。

Helidonでは、OCI APM用の専用エージェントが用意されており、依存関係(ライブラリ)と環境変数を設定するだけで利用できます。
詳細は[こちら](https://docs.oracle.com/ja-jp/iaas/application-performance-monitoring/doc/use-apm-tracer-helidon.html)をご確認ください。

先ほどプロビジョニングしたOCI APMを利用するための設定をしていきます。

APMにはAPM Browser AgentとAPM Server Agentが存在するので、その両方を設定していきます。

### サンプルアプリケーション(ブラウザ側)のAPM設定

まずは、APM Browser Agentから設定します。

フロントエンドアプリケーションのHTMLファイルを開きます。

```sh
vim code-at-customer-handson/olympic_frontend_apm/src/main/resources/web/index.html
```

```
~~~
    <script>
      window.apmrum = (window.apmrum || {}); 
      window.apmrum.serviceName='oke-helidon-demo-frontend-UI';
      window.apmrum.webApplication='OracleJetApp';
      window.apmrum.ociDataUploadEndpoint='https://xxxxxxxxxxxxxxx.apm-agt.us-ashburn-1.oci.oraclecloud.com';　#変更箇所1
      window.apmrum.OracleAPMPublicDataKey='<your-public-data-key>';　#変更箇所2
      window.apmrum.traceSupportingEndpoints =  [
        { headers: [ 'APM' ], hostPattern: '.*' },
      ]; 
    </script>
    <script async crossorigin="anonymous" src="https://xxxxxxxxxxxxxxx.apm-agt.us-ashburn-1.oci.oraclecloud.com/static/jslib/apmrum.min.js"></script> #変更箇所3
~~~
```

|変更箇所  |設定内容  |備考  |
|---|---|---|
変更箇所1 | [APMドメインの作成](#apmドメインの作成)で記録した「データ・アップロード・エンドポイント」|
変更箇所2|[APMドメインの作成](#apmドメインの作成)で記録したデータ・キーの「パブリック」キー|**プライベートキーではなく、パブリックキーとなるので注意してください。**
変更箇所3|staticより前の部分`https～.com`までを[APMドメインの作成](#apmドメインの作成)で記録した「データ・アップロード・エンドポイント」を設定します。

ソースコードを変更したので、コンテナイメージをビルドし、OCIR上にプッシュします。

```sh
cd code-at-customer-handson/olympic_frontend_apm
```

```sh
docker image build -t iad.ocir.io/<your-object-storage-namespace>/frontend-app-apm .
```

OCIRにログインします。「iad.ocir.io」エンドポイントについては、ビルド時と同様、環境に合わせてください。

:::note info
**Ashburn(us-ashburn-1)リージョンではない皆様**  
リージョンが、アッシュバーン(us-ashburn-1)ではない場合、環境に合わせて「iad.ocir.io」の部分も変更してください。
各リージョンのOCIRエンドポイントは[こちら](https://docs.oracle.com/ja-jp/iaas/Content/Registry/Concepts/registryprerequisites.htm)で確認できます。  
ここでは、以降も「iad.ocir.io」で進めます。
:::

「Username」と「Password」は、事前に確認した以下を入力します。

|入力項目  |入力内容
|---|---|
Username | `<オブジェクト・ストレージ・ネームスペース>/<ユーザ名>`|[OCIRレポジトリの作成](#ocirレポジトリの作成)で作成した内容
Password|`認証トークン` |[OCIRレポジトリの作成](#ocirレポジトリの作成)

```sh
docker login iad.ocir.io
```

```sh
docker image push iad.ocir.io/<your-object-storage-namespace>/frontend-app-apm
```

これでOCIRへのプッシュは完了です。

### サンプルアプリケーション(サーバサイド側)のAPM設定

Manifestのあるディレクトリに移動します。  

```shell
cd ~
```

```shell
cd code-at-customer-handson/k8s/app/for-oci-apm
```

フロントエンドアプリケーションのManifestをvimで開きます。

```sh
vim olympic_frontend.yaml
```

```yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-app
  labels:
    app: frontend-app
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend-app
      version: v1
  template:
    metadata:
      labels:
        app: frontend-app
        version: v1
    spec:
      containers:
      - name: frontend-app
        image: iad.ocir.io/orasejapan/frontend-app-apm
        ports:
        - containerPort: 8082
        env:
        - name: tracing.data-upload-endpoint
          valueFrom:
            secretKeyRef:
              name: apm-secret
              key: endpoint
        - name: tracing.private-data-key
          valueFrom:
            secretKeyRef:
              name: apm-secret
              key: private-key
(省略)
```

25行目~35行目の`env`フィールドにSecretから環境変数として`tracing.data-upload-endpoint`、`tracing.private-data-key`を読み込んでいます。
これと同じ設定をバックエンドアプリケーションとデータソースアプリケーションにも入れています。

ここで利用するSecretリソースを作成します。

|項目  |設定内容  |備考  |
|---|---|---|
APMエンドポイント|[APMドメインの作成](#apmドメインの作成)で記録した「データ・アップロード・エンドポイント」|
「データ・キー」の「プライベート」キー|[APMドメインの作成](#apmドメインの作成)で記録したデータ・キーの「プライベート」キー|**パブリックキーではなく、プライベートキーとなるので注意してください。**

```sh
kubectl create secret generic apm-secret --from-literal=endpoint=<APMエンドポイント> --from-literal=private-key=<「データ・キー」の「プライベート」キー>
```


これでサンプルアプリケーションのManifest設定の変更は完了です。  

# OCI APMでのトレーシング

いよいよ、OCI APMを利用したトレーシングを実施します。  

## OCI APMでの分散トレーシング

サンプルアプリケーションをデプロイします。  

```sh
cd ~
```

```sh
cd code-at-customer-handson/k8s/app/for-oci-apm
```

```sh
kubectl apply -f . 
```

***コマンド結果***

```sh
deployment.apps/backend-app-v1 created
deployment.apps/backend-app-v2 created
deployment.apps/backend-app-v3 created
service/backend-app created
deployment.apps/datasource-app created
service/datasource-app created
deployment.apps/frontend-app created
service/frontend-app created
```

アプリケーションにアクセスします。  

```sh
kubectl get svc frontend-app
```

***コマンド結果***

```sh
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
frontend-app   LoadBalancer   10.96.110.178   146.56.xxx.xxx   80:31031/TCP   58s
```

上記の場合は、`EXTERNAL-IP`である`146.56.xxx.xxx`がエンドポイントになります。

この場合は、以下のURLにアクセスします。  
`http://146.56.xxx.xxx`

何度かアクセスしたのちに、トレース情報をOCI APMから確認します。  

OCIコンソールのハンバーガーメニューを開き、「監視および管理」から「アプリケーション・パフォーマンス・モニタリング」カテゴリの「トレース・エクスプローラー」を選択します。  

![6-009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/c471fe9f-696e-b3d5-ddbe-ab08ba7e3d61.png)

画面上部にある「APMドメイン」から、[APMドメインの作成](#apmドメインの作成)で作成したAPMドメインを選択します。  

![6-010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/c502c05e-2631-b497-258d-15c25bc9efe6.png)


右側にある検索条件を「過去15分間」に選択し、「実行」ボタンをクリックします。  

![6-011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/8162dfa1-4526-eade-aaad-bd35ee7ad3cd.png)


複数のトレース情報が表示されますので、`Spans`が26になっている情報をクリックします。  

![スクリーンショット 2022-02-22 17.11.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/10235368-89e5-e325-2bff-9683293a7341.png)


以下のようなトレース情報が表示されます。
この情報で、どのコンポーネントがどれくらいの時間を要しているのかをクリアに確認できます。

![スクリーンショット 2022-02-22 17.12.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/c8467b65-0f53-86ad-a8f4-949397bd7bfe.png)


これで、OCI APMを利用したトレーシングは完了です。  

## OCI APMでのアプリケーションサーバのメトリクス監視

最後に、OCI APMではアプリケーションサーバのメトリクスも監視できるので、やってみたいと思います。

画面左上のプルダウンから「ダッシュボード」をクリックします。  

![6-015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/8c0a9740-e5c0-4635-cd05-b6bb48af2c51.png)

ダッシュボードから「アプリケーション・サーバー」をクリックします。  

![6-016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/208bb995-ea35-f36c-6f35-3fa4f386b1dd.png)


左上に「アプリケーションサーバを選択します」というプルダウンがあるので、任意のアプリケーションサーバ(実体はHelidonのPod)を選択します。  


![6-017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/07845803-70bd-ce15-4bf7-4307ad6022d3.png)

アプリケーションサーバ(今回はHelidon)のメトリクス情報が表示されます。  

![6-018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/e2e71bf9-d6f3-d266-38da-3ea01839550f.png)


ここで取得したメトリクスをもとに、OCI MonitoringやOCI Notificationsと連携すると、一定の閾値を超過した際にアラーム通知を行うこともできます。  

このように、OCI APMを利用すると詳細なトレーシングの取得と確認およびアプリケーションサーバのメトリクス監視を行うことができます。  

# まとめ

このように、OCI APMを利用すると分散トレーシングやアプリケーションサーバのメトリクス監視を一貫して行うことができます。

ぜひ、皆さんも触ってみてください！！