Azure FunctionsからプライベートエンドポイントのCosmos DBに接続すーる

# はじめに
Azure FunctionsからプライベートエンドポイントのCosmos DBに接続していきます

# 開発環境
- Windows 10 PC
- Azure

# 導入
## 仮想ネットワークの作成

1．仮想ネットワークの作成

Azure Functionsに合わせて、リージョンは East Asia にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/813543d8-5e6d-321d-99d9-8de5aad74af9.png)

2．仮想ネットワークの暗号化にチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/fc033d00-fbe6-8b92-b044-c7d00eb6134c.png)

3．VNet用のサブネットを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/1c2f136b-105e-242b-f190-fc456c0a707c.png)

4．Cosmos DB用のサブネットを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/4b912985-a869-0734-6852-3b4f90217b79.png)

このような形になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/7e331c15-23c3-a3e0-4ebf-471acb6ed0cc.png)

## Cosmos DBの作成

1．コア（SQL）- 推奨 を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/210c4945-8c07-42b9-3bb8-b5da0c812c94.png)

2．インスタンスの詳細を設定
Azure Functionsに合わせて、リージョンは East Asia にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/5fa215bf-6c4a-2d60-ed9f-24f18a4fd848.png)

3．Itemsコンテナーの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/039a6e3a-6ca2-47a4-4447-dae00a319ed3.png)

4．データエクスプローラーで新しいアイテムを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/5ac63a8f-1f92-14ab-06aa-7bc12f9ae7b1.png)

5．パブリックアクセスを無効に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/b3a2836f-0f9e-18d1-0f61-857cc52cccae.png)

6．プライベートエンドポイントを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/1c873e83-191b-b7dc-6b11-8da29355ff30.png)

7．リソースを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/feeaf136-282d-19ea-4f72-ae028e378d83.png)

8．仮想ネットワークで、Cosmos DB用のサブネットを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/c34b0544-b463-4c56-ecca-b22969ab05a8.png)

9．プライベートDNS統合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/09c0d1f9-6328-3656-ca4d-6f10a7d85914.png)

プライベートアクセスで承認済みになればOKです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/1e9f015f-f507-e08c-a2c6-f74659dfd931.png)

## 関数アプリの作成

1．Flex 従量課金プランを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/ce625126-e2c7-43f6-de79-fa158d64550c.png)

2．利用できるリージョン一覧はこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/f7b1b2f7-aa7f-8919-b817-bfe721cd6ada.png)

3．East Asia、Node.js（20 LTS）で作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/20405c7c-5d5f-c20b-2aa4-01a45bff1241.png)

4．Cursorで Create Function Project -> s-fujimoto-241224 Functionsのソースコード用のフォルダを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/0c2d9db6-b77a-876d-d3dc-e10676170d1d.png)

5．TypeScript を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/108513da-5aa1-c860-4e1e-18540f02041f.png)

6．Model V4 を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/a3d872ff-a34f-83f2-26fb-e85d44ba6809.png)

7．HTTP Trigger を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/657195ad-c262-beaf-d4c6-9530d11d064b.png)

8．ファイル名は httpTrigger1 とした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/3983b666-9843-c365-a022-5c70723d8ece.png)

9．最初のプログラム（httpTrigger1.ts）

```httpTrigger1.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";

export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || await request.text() || 'world';

    return { body: `Hello, ${name}!` };
};

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: httpTrigger1
});

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/8024b906-0e1a-d094-581d-69f02489d30b.png)

10．Start debugging to update this list... をクリックしデバッグ開始
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/afe1a989-0249-7e9f-b384-8f4da036eed6.png)

11．http://localhost:7071/api/httpTrigger1 にアクセスしてテスト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/76c739e7-a085-2331-1a6e-5e9060e8e3f1.png)

12．Deploy to Azure をクリックしデプロイ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/99710fee-a008-c2d6-901c-22be431e0447.png)

13．ポータルに戻ると関数が見えるように
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/5282ea40-e68a-65c2-1b16-73dc39df4511.png)

14．ポータルからテスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/29a8a66c-2d91-085c-d4af-d648bbefb03c.png)

## 関数アプリの仮想ネットワーク統合

1．ネットワーク -> 送信トラフィックの構成 -> 仮想ネットワーク統合 「未構成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/22fc7cfd-ef9a-2aeb-63ca-9d6a36986b8b.png)

2．VNet用のサブネットを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/42402da8-89a3-4634-b756-00764d982afd.png)

このような形になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/7cb8e650-3784-05c4-1300-26ccbf825cd3.png)

## CosmosDBからデータを取得するだけの関数アプリ

1．httpTrigger1.tsを編集

```httpTrigger1.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { CosmosClient } from "@azure/cosmos";

const endpoint = process.env.COSMOS_ENDPOINT || "";
const key = process.env.COSMOS_KEY || "";
const databaseId = process.env.COSMOS_DATABASE_ID || "ToDoList";
const containerId = process.env.COSMOS_CONTAINER_ID || "Items";

const client = new CosmosClient({ endpoint, key });
const container = client.database(databaseId).container(containerId);

export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    if (!endpoint || !key) {
        context.log(`[ERROR] CosmosDB connection information is not properly configured`);
        return {
            status: 500,
            body: "Server configuration error"
        };
    }

    try {
        const { resources: items } = await container.items.readAll().fetchAll();
        
        context.log(`Retrieved ${items.length} items from CosmosDB`);

        return {
            status: 200,
            jsonBody: items
        };
    } catch (error) {
        context.log(`[ERROR] Error fetching items from CosmosDB: ${error}`);
        return {
            status: 500,
            body: "Error fetching items from CosmosDB"
        };
    }
}

app.http('httpTrigger1', {
    methods: ['GET'],
    authLevel: 'anonymous',
    handler: httpTrigger1
});

```

2．ライブラリのインストール

```
npm install @azure/cosmos
```

package.jsonはこのような形になります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/5142bb2a-5322-1c6b-8f01-acdfaeb2be26.png)

3．local.settings.json を編集し、キーとエンドポイントをコピペ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/f0907a5b-f92c-4766-8aa4-7891affd62c2.png)

```local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "COSMOS_ENDPOINT": "https://xxxx.documents.azure.com:443/",
    "COSMOS_KEY": "<INSERT-YOUR-COSMOS-KEY>",
    "COSMOS_DATABASE_ID": "ToDoList",
    "COSMOS_CONTAINER_ID": "Items"
  }
}
```

4．ローカルからはテストはできない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/a2eb1f42-f739-e16d-3ea6-a5b4547b0e06.png)

5．ポータルの関数アプリ -> 環境変数の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/79e82a3c-742d-af0b-d0fe-03835f337a41.png)

6．デプロイして、ポータル上でテスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/e4c22d1a-0b14-54ad-7664-86163bd3d48a.png)

全体の構成図はこのようになります。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/e26add6f-7f5d-39d7-c5ce-19ccf55b1dcc.png)

お疲れ様でした