AzureをInstanaで可視化してみた(FaaSの利用：Azure Function)

こんにちは、Instanaユーザー会の運営をお手伝いさせていただいております、カワノです！
この記事は[Instana Observability Advent Calendar 2023](https://qiita.com/advent-calendar/2023/instana) 12日目のエントリになります。

昨日に引き続き、「AzureをInstanaで可視化してみた」をやってみます。
前回は、IaaSである「Azure仮想マシン」上のWordpressをInstanaで可視化してみました。
実際にはほとんどオンプレのLinuxサーバとやっていることは同じなので、クラウド成分は低めでした。
ということで今回は、クラウドならでは「Azure Function」上でサーバレスアプリを可視化してみましょう。

## 参考サイト
今回は、以下のサイトを参考に、Azure FunctionとAzure Table Storageを使って、単純にカウントアップするアプリを構築してみます。
* [クイックスタート: コマンド ラインから Azure に JavaScript 関数を作成する](https://learn.microsoft.com/ja-jp/azure/azure-functions/create-first-function-cli-node?tabs=macos%2Cazure-cli%2Cbrowser&pivots=nodejs-model-v4)

## Functionプロジェクト作成
上記サイトをなぞります。
### Azure Functions Core Toolsの導入

私の環境は Intel mac なので、 以下のコマンドで Azure Function Core Toolsを導入します。
```shell
brew tap azure/functions
brew install azure-functions-core-tools@4
```

### nodejsバージョン確認とnvm導入
Azure Functionで利用可能なnodejsのバージョンを確認すると、nodejs18までGAとなっていました。(2023/12/10時点) 
[Azure Functions ランタイム バージョンの概要](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-versions?tabs=isolated-process%2Cv4&pivots=programming-language-javascript#languages)

私の環境にはverion21が入っていたので、改めてnodejsのバージョン18を導入します。

#### nvm導入
npmの複数バージョンを管理・利用できるnvmを導入します。
https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating
```shell
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
```
ターミナルを一度再起動します。

#### nodejs バージョン18 導入
nodejs バージョン18 を導入します。
```shell
nvm install 18
```

出力内容
```shell
Downloading and installing node v18.19.0...
Downloading https://nodejs.org/dist/v18.19.0/node-v18.19.0-darwin-x64.tar.xz...
################################################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v18.19.0 (npm v10.2.3)
Creating default alias: default -> 18 (-> v18.19.0)
```

バージョン確認しましょう。
```shell
node -v
```
出力内容
```
v18.19.0
```
OKです。



### プロジェクトの作成
func init コマンドを実行して、LocalFunctionProj という名前のフォルダーに関数プロジェクトを作成します。
```shell
func init LocalFunctionProj --model V4
```

途中、コンソールに入力を求められます。最初に`3. node`を、次は`1. javaScript`を選択します。
```shell
Select a number for worker runtime:
1. dotnet
2. dotnet (isolated process)
3. node
4. python
5. powershell
6. custom
Choose option: 3
node
Select a number for language:
1. javascript
2. typescript
Choose option: 1
javascript
The new Node.js programming model is generally available. Learn more at https://aka.ms/AzFuncNodeV4
Writing package.json
Writing .funcignore
Writing .gitignore
Writing host.json
Writing local.settings.json
Writing /Users/tetsu/work/advcal2023/LocalFunctionProj/.vscode/extensions.json
Running 'npm install'...
```

プロジェクトディレクトリに移動し、関数を作成します。
```shell
cd LocalFunctionProj
func new
```

途中、コンソールに入力を求められます。`7. HTTP trigger`を選択します。 Function nameはとりあえずデフォルトの`httpTrigger`のままにしましょう。
```shell
Select a number for template:
1. Azure Blob Storage trigger
2. Azure Cosmos DB trigger
3. Durable Functions entity
4. Durable Functions orchestrator
5. Azure Event Grid trigger
6. Azure Event Hub trigger
7. HTTP trigger
8. Azure Queue Storage trigger
9. Azure Service Bus Queue trigger
10. Azure Service Bus Topic trigger
11. Timer trigger
12. Dapr Publish Output Binding
13. Dapr Service Invocation Trigger
14. Dapr Topic Trigger
Choose option: 7
HTTP trigger
Function name: [httpTrigger]
Creating a new file /Users/tetsu/work/advcal2023/LocalFunctionProj/src/functions/httpTrigger.js
The function "httpTrigger" was created successfully from the "HTTP trigger" template.
```

### Functionローカル実行
```shell
func start
```
出力内容
```
Azure Functions Core Tools
Core Tools Version:       4.0.5455 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.27.5.21554

[2023-12-10T04:16:35.039Z] Worker process started and initialized.

Functions:

	httpTrigger: [GET,POST] http://localhost:7071/api/httpTrigger
```

では、動作を確認します。
```shell
$ curl "http://localhost:7071/api/httpTrigger?name=hoge"
Hello, hoge!
$ curl "http://localhost:7071/api/httpTrigger?name=fuga"
Hello, fuga!
$curl "http://localhost:7071/api/httpTrigger"
Hello, world!
```
大丈夫そうですね。


### Function の作成
ここからは、Azure CLIを操作します。Azure CLI自体のインストールは、[こちら](https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli) をご参照ください。

最初にAzureにログインしておきます。
```shell
az login
```

#### Functionアプリの作成
最初に、StorageAccountを作成します。functionには必須なんだそうです。
```shell
az storage account create --name forfunc20231212 --location japaneast --resource-group advcal1 --sku Standard_LRS --allow-blob-public-access false
```
名前は`forfunc20231212`、東日本リージョンに作りました。

続けて Functionアプリをつくります。パラメータが多いよ…
```shell
az functionapp create --resource-group advcal1 --runtime node --runtime-version 18 --functions-version 4 --name advcalfuncapp --storage-account forfunc20231212 --consumption-plan-location japaneast
```
ランタイムはNode、バージョンは18、Functionのバージョンはv4、Functionの名前は`advcalfuncapp`、東日本リージョンに作りました。

#### Functionアプリのデプロイ
最初に作ったアプリをデプロイします。
```shell
func azure functionapp publish advcalfuncapp
```
実行場所は`LocalFunctionProj`ディレクトリですね。

出力内容
```shell
Setting Functions site property 'netFrameworkVersion' to 'v6.0'
Getting site publishing info...
[2023-12-10T04:34:23.778Z] Starting the function app deployment...
Creating archive for current directory...
Uploading 609.69 KB [###################################################################]
Upload completed successfully.
Deployment completed successfully.
[2023-12-10T04:34:46.046Z] Syncing triggers...
Functions in advcalfuncapp:
    httpTrigger - [httpTrigger]
        Invoke url: https://advcalfuncapp.azurewebsites.net/api/httptrigger
```

デプロイ完了です。
動作確認してみましょう。
```shell
$ curl "https://advcalfuncapp.azurewebsites.net/api/httptrigger"
Hello, world!
$ curl "https://advcalfuncapp.azurewebsites.net/api/httptrigger?name=hoge"
Hello, hoge!
$ curl "https://advcalfuncapp.azurewebsites.net/api/httptrigger?name=fuga"
Hello, fuga!
$ curl "https://advcalfuncapp.azurewebsites.net/api/httptrigger?name=bar"
Hello, bar!
```

ちゃんと動作していますね。

## Instana Agent設定
Azure Fuctionアプリは完成しました。では、Instana Agentの準備をします。

Instanaのdocは以下です。
[Monitoring Azure Functions サービス](https://www.ibm.com/docs/ja/instana-observability/current?topic=agents-azure-functions)

最初にこんな記載があります。
> Instana UI で Azure Functions サービスに関連するメトリックを表示するには、Instana ホスト・エージェント をインストールし、「 センサーの構成 」セクションの説明に従って Azure センサーを有効にする必要があります。 Azure Functions センサーは、Instana ホスト・エージェントのインストール後に自動的に有効になります。
> Instana UI で Azure Functions トレースを表示するには、 Instana Azure Functions トレーサーのインストール のセクションで説明されているように、Instana Azure Functions トレーサーを Azure Functions アプリケーションに追加する必要があります。

上記の通り、Instana でAzure Functionを可視化するためには、
1. Functionとは別にAzure仮想マシンを準備 (Instanaの情報収集のためのサーバとして利用する)
1. 1のAzure仮想マシンに、ホスト用のInstana Agentを導入
1. 設定ファイルを編集しセンサーを有効にする
1. トレーサーをAzure Functionアプリに追加する
という手順を行う必要があります。

今回、[1日前](https://qiita.com/tty-kwn/items/174a63a1d09e72f433ee)に作成したInstana Agent導入済みのAzure仮想マシンがありますので、そちらを使ってセットアップを行います。

### Azureセンサーの有効化
Agentの設定ファイル`configuration.yaml`(`<instana agent dir> /etc/instana/configuration.yaml`) で Azure センサーを有効します。
有効にするために最低限必要な情報は以下のとおりです。
```yaml
com.instana.plugin.azure:
  enabled: true
  subscription: "[Your-Subscription-Id]"
  tenant: "[Your-Tenant-Id]"
  principals:
    - id: "[Your-Service-Principal-Account-Id]"
      secret: "[Your-Service-Principal-Secret]"
```

Functionアプリが作れているので、Azure SubscriptionやTenant情報はすでに保有しているものとします。

#### サービスプリンシパルの作成
監視対象のサービスに対して読み取り権限を持つサービスプリンシパルを用意します。
[リソースにアクセスできる Microsoft Entra アプリケーションとサービス プリンシパルを作成する](https://learn.microsoft.com/ja-jp/entra/identity-platform/howto-create-service-principal-portal)を参考に、サービスプリンシパルを作成、設定していきます。

##### 「アプリの登録」の作成
[Entra管理センター](https://entra.microsoft.com/)を開き、左メニューの`ID > アプリケーション > アプリの登録` を選択します。
`新規登録`をクリックします。
![Entra_Menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/06dd65c4-b634-d3fb-8151-52ce0040ac50.png)
アプリの登録を行います。今回は`advcal1-app`という名前で作成します。
![regist_app1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/de4a756a-4961-5e3e-44c8-e834ff7d4a9e.png)

##### ロール割り当て
[Azure Portal](https://portal.azure.com)にアクセスし、Instanaで監視したいSubscriptionを選択します。
左メニューの`アクセス制御(IAM)`を選択し、`ロールの割り当ての追加`をクリックします。
ロールは**閲覧者**で、メンバに先ほど作成した`advcal1-app`を選択します。(UI上で選択肢が出ないようです。検索文字列に`advcal1-app`と入力することで検索、選択できました)
選択完了したら`レビューと割り当て`を行います。

##### 認証設定
[Entra管理センター](https://entra.microsoft.com/)を開き、左メニューの`ID > アプリケーション > アプリの登録` を選択します。
作成した「アプリの登録」(`advcal1-app`)をクリックし、左メニューの`証明書とシークレット`をクリックします。

続けて、`クライアントシークレット`タブの`新しいクライアントシークレット`を選択します。
![AppSecret.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/e97ad4eb-4f3f-775e-19d7-a748db5c08dd.png)

名前と有効期限を決定し、作成すると、画面上にシークレットの値が表示されますので、これをどこか忘れないところにコピーしておきます。
![appSecret2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/81f8bec1-ee61-535c-499a-f835e1bcf3d0.png)

#### Agent設定ファイルの編集
ようやく、Azure上での作業が終わりました。
azureの設定はコメントアウトされていますので、外して サブスクリプションID、テナントID、サービスプリンシパルアカウントID、サービスプリンシパルシークレットをそれぞれ設定ファイルに貼り付けます。
(IDどこだっけ？となったら以下参照)
![Azure_ref.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/3e288be2-c629-6dc9-ae4e-c913186a9c08.png)
![AgentConfig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/5b4f564f-af5b-2219-007e-bea5e35646d6.png)

Azure Functions サービス・センサーは、デフォルトで有効なので、以上で可視化の最低限設定は完了です。
Instanaの挙動を見てみましょう。

Functionの可視化は、`インフラストラクチャー`で見ることができます。項目については下記のドキュメントをご確認ください。
https://www.ibm.com/docs/ja/instana-observability/current?topic=agents-azure-functions#viewing-metrics
![Instana_Metric.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224464/5e07c30b-4462-9d8b-49ea-1cdda4883d15.png)




### (補足) Instana Azure Functions トレーサーのインストール
この記事では単純なFunctionアプリを作成したのですが、 AppServiceを利用するパターンだとTraceを有効にできます。インフラストラクチャービュー以外でもより多くの情報を参照できそうですね。

参考：[Instana Azure Functions トレーサーのインストール](https://www.ibm.com/docs/ja/instana-observability/current?topic=agents-azure-functions#installing-instana-azure-functions-tracers)
> Windows または Docker コンテナー上で実行される AppService としてデプロイされた Azure Functions のインスツルメンテーションを有効にすることができます。 .NET Framework、.Net Core、および .Net のインスツルメンテーションを有効にするには、 Azure Functions をモニターする予定の環境で Instana エージェントが実行されていることを確認してください。 

以上で終了となります。ありがとうございました。