mcpField
A
azuresql-db-local-to-cloud

azuresql-db-local-to-cloud

github.com/microsoftクラウド・DevOps2277 回インストール1 週間前に更新
リポジトリ

azuresql-db-local-to-cloud について

ローカルの Azure SQL Database コンテナーで開発・テストし、クラウドの Azure SQL Database にデプロイするためのスキルです。SQL_CONNECTION_STRING の切り替えでアプリケーションコードを変えずに環境を移行し、ローカルの検証結果とクラウド側のガイダンスを区別します。

主な機能

  1. 01環境間で単一の接続文字列変数を使用
  2. 02ローカル SQL 認証とクラウド Entra 認証を設定
  3. 03ローカルとクラウドでクエリとスキーマを維持
  4. 04アプリケーション接続前に appdb を作成
  5. 05ローカルの実測範囲とクラウド側の手順を説明

活用シーン

  1. 01ローカルコンテナーを使ったアプリケーション開発
  2. 02ローカル SQL から Azure SQL Database への切り替え
  3. 03ローカルの SA とクラウドの Entra 認証を設定
  4. 04ローカルとクラウドの互換性の検証範囲を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/microsoft/azure-sql-database-container --skill azuresql-db-local-to-cloud

インストール後、Claude Code で/azuresql-db-local-to-cloudを入力して読み込まれたか確認します。

同梱ファイルreferences/auth-local-vs-cloud.mdskill.spec.jsonc

詳細

Azure SQL Database コンテナーから Azure SQL Database へ:同じコードでローカルからクラウドへ

ローカルコンテナーに対してビルドとテストを行い、その後、 同じアプリケーションコードをクラウドの Azure SQL Database にデプロイします。変わるのは接続文字列だけです。それ以外は何も変わりません。

これは、ローカルコンテナーが SQL Server イメージではなく、Azure SQL Database エンジンだからです。SELECT SERVERPROPERTY('EngineEdition') は 5 を返し、SERVERPROPERTY('Edition') は 'SQL Azure' を返します。クラウドの場合と同じです。そのため、コードが依存する SQL の機能はどちらの環境でも同じです。

2026-09-05 に、コンテナーイメージ sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest に対して検証済みです。報告された値は EngineEdition 5、Edition SQL Azure、ビルド 12.0.2000.8 でした。このスキルに含まれる実行可能な6つのチェックは、すべてコンテナーで合格しました。エンジンの識別、USE に対する Msg 40508、BACKUP と RESTORE に対する Msg 40510、OUTPUT inserted.id を使ったパラメーター化インサート、シングルデータベースモデル、そして /opt/mssql-tools18/bin/sqlcmd です。この実行で測定したのはコンテナーだけです。同等性に関する主張のクラウド側、およびそのための Microsoft Entra ID とマネージド ID のセットアップはそこで検証していないため、準備完了と判断する前に、実際の Azure SQL Database に対して一度検証してください。

唯一のルール

**ローカルとクラウドの間でアプリケーションコードを変更しないでください。**アプリケーションは、単一の環境変数 SQL_CONNECTION_STRING から接続文字列を読み取ります。ローカル開発ではコンテナーを指定し、クラウドへのデプロイでは Azure SQL サーバーを指定します。同じバイナリ、同じクエリ、同じスキーマです。

Azure で「動作させるため」にクエリ、ドライバー、スキーマを編集していることに気づいたら、作業を止めてください。それはバグです。正当に異なるのは接続文字列(およびそれに伴う認証方式)だけです。

1つの環境変数、2つの値

SQL_CONNECTION_STRING に統一します。すべての例で表記を統一するため、標準の書式ではキーワードを User Id= / Password= / Database= とします。Uid= と Pwd= は SqlClient の正式な同義語で、こちらも使用できます。ODBC 接続文字列は別の構文であり、独自のキーワードとして Uid= / Pwd= を使用します。

ローカル(コンテナー、SA 認証):

Server=localhost,1433;Database=appdb;User Id=sa;Password=$MSSQL_SA_PASSWORD;TrustServerCertificate=true

クラウド(Azure SQL Database、Microsoft Entra 認証):

Server=your-server.database.windows.net,1433;Database=appdb;Authentication=Active Directory Default;Encrypt=true

同じままなのは Database=appdb、テーブル名、パラメーター化された SQL です。変わるのは Server、認証フィールド、TLS の設定だけです。

ローカルの SA 認証とクラウドの Entra 認証(方法だけでなく、その理由)

ローカル:コンテナーは、環境変数 MSSQL_SA_PASSWORD で設定するブートストラップログイン sa を1つ使ってプロビジョニングされます。ノート PC 上のコンテナーの前段に ID プロバイダーは必要ないため、信頼された自己署名証明書を使ったパスワード認証(TrustServerCertificate=true)が、実用的なローカルのデフォルトです。

コンテナーでも Microsoft Entra ID 認証を使用できます(MSSQL_AAD_* 変数と証明書のマウントで設定します。azuresql-db-container スキルの references/entra-auth.md を参照してください)。ローカルとクラウドの同等性をより高めたい場合に使用してください。ローカルからクラウドへのフローの多くは、引き続きローカルでは SQL 認証を使い、クラウドでは Entra 認証に切り替えるために接続文字列だけを変更します。

クラウド:Azure SQL Database は Microsoft Entra ID の背後で稼働します。パスワードをアプリに含めて配布する代わりに、アプリは Entra ID の ID(本番環境ではマネージド ID、ローカルではクラウドに対する開発者のサインイン)から取得したトークンを提示します。ドライバーがトークンを取得するため、接続文字列にシークレットを含める必要はありません。TLS は実際に使用され、必須であるため、Encrypt=true を使用し、TrustServerCertificate は削除してください。

アプリケーションコードでこの違いを分岐させることはありません。ドライバーは接続文字列の Authentication= キーワード(またはその不在)を読み取り、適切に処理します。それが重要な点です。認証はコードではなく設定です。

クラウド側を設定する際は、トークンのフローとスタックごとの認証設定を記載した references/auth-local-vs-cloud.md を開いてください。

ローカルコンテナーについて最低限押さえておくべき事実

新しいコンテナーでサンプルを実行するために必要な情報のみを記載しています。詳しくは azuresql-db-container スキルを参照してください。

  • イメージ:sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest (x64、linux/amd64)。プライベートプレビュー用レジストリです。最初に、プライベートプレビュー参加者に提供されるプル専用の共有認証情報を使って docker login sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io を実行してください。認証情報は https://aka.ms/sqldbcontainerpreview-signup で登録すると入手できます。認証情報は変更される場合があります。レジストリとタグは、プライベートプレビュー期間中は暫定的なものです。
  • x64 以外のホストでは、--platform linux/amd64 を追加してください。
  • 必須の環境変数:ACCEPT_EULA=Y と、複雑なパスワードを設定した MSSQL_SA_PASSWORD (8 文字以上で、大文字、小文字、数字、記号を含むもの)。エンジンは 1433 でリッスンします。
  • エンジンはデータベースを自動作成しません。 Database=appdb を指定して接続する前に、master 接続で CREATE DATABASE appdb を実行する必要があります。master 接続はプロビジョニング専用です。実際の作業は appdb で行ってください。
  • すべてのセッションで BACKUP と RESTORE は Msg 40510 で拒否されます。クラウドとまったく同じです。コンテナーをバックアップし、そのファイルを Azure SQL Database に復元する方法は、移行手段にはなりません。スキーマとデータは SqlPackage で移行してください(azuresql-db-import スキルを参照)。
  • クロスデータベースクエリは、クラウドと同様にローカルでも拒否されます。そのため、すべてのオブジェクトを 1 つのユーザーデータベースに保持するアプリケーションは、サービスに接続した場合と同じ理由でローカルでも動作します。
  • IDENTITY 列の動作はクラウドと同じです。以下のサンプルでは、INT IDENTITY PRIMARY KEY を両方でそのまま使用しています。これは、通常は不必要に書き換えを提案される箇所の 1 つです。
  • データベースの切り替えに USE を使わないでください。ユーザーデータベースのセッション(Azure と同じ条件で開発できるコンテキスト)では、USE は Azure SQL Database クラウド版とまったく同じく Msg 40508 を返します。master 接続はプロビジョニングセッションであり、Azure のステートメントフィルターは適用されないため、そこで USE は動作するように見えます。しかし、master はプロビジョニング専用で、アプリケーションの作業には使いません。接続文字列で常に対象データベースを選択してください(Database=appdb、または sqlcmd の場合は -d appdb)。

コンテナーを起動して appdb をプロビジョニングする(標準手順)

一度だけ実行してください。空いているホストポートを選び、必要な場合のみ --platform を追加し、実際に利用可能になるまで待機してから、リトライループ内で appdb をプロビジョニングします。-b -l 2 を指定すると、一時的な起動エラー(例:Msg 913)が終了コードに反映されるため、ループがエラーを無視せずに再試行します。

# Pick a free host port and add the platform flag only on a non-x64 host (works in bash and zsh).
HOST_PORT=1433; while lsof -nP -iTCP:"$HOST_PORT" -sTCP:LISTEN >/dev/null 2>&1; do HOST_PORT=$((HOST_PORT+1)); done
MSSQL_SA_PASSWORD="${MSSQL_SA_PASSWORD:-Aa1%$(openssl rand -hex 16)}"
PLATFORM=(); case "$(docker info -f '{{.Architecture}}' 2>/dev/null)" in x86_64|amd64) ;; *) PLATFORM=(--platform linux/amd64);; esac
docker rm -f sqldb 2>/dev/null
docker run -d --name sqldb "${PLATFORM[@]}" -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PASSWORD" \
  -p "127.0.0.1:$HOST_PORT:1433" sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest
until docker exec sqldb /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -C -b -l 2 \
  -Q "IF DB_ID('appdb') IS NULL CREATE DATABASE appdb;" >/dev/null 2>&1; do sleep 2; done
echo "ready on localhost,$HOST_PORT"

次に、ループで確定した HOST_PORT を使って、アプリをコンテナーに接続します。

export SQL_CONNECTION_STRING="Server=localhost,$HOST_PORT;Database=appdb;User Id=sa;Password=${MSSQL_SA_PASSWORD};TrustServerCertificate=true"

後でクラウドに接続する場合は、この変数だけを変更してください。アプリには手を加えないでください。

実測済みの内容と、ガイダンスとして示す内容

このスキルのどの部分に根拠があるのか、ユーザーに正確に伝えてください。

ローカル環境については実測済みです。 このスキルに含まれるすべてのプローブはコンテナーに対して実行されており、パリティの主張の根拠となる記述を検証しています。具体的には、エンジンが EngineEdition 5 と Edition SQL Azure を報告すること、USE が Msg 40508 を返すこと、BACKUP が Msg 40510 を返すこと、クロスデータベースクエリが拒否されること、そして以下のサンプルで実行するものとまったく同じ CRUD バッチが、サンプルで読み取る IDENTITY 値を返すことです。

クラウド環境についてはガイダンスです。 このリポジトリでは、論理サーバーに対するプローブを実行したことがありません。そのため、クラウド接続文字列、Microsoft Entra のトークンフロー、デプロイのチェックリストは、実行結果ではなく製品ドキュメントに基づいて記載されています。これは、埋めるべき不足ではなく、意図的なものです。コンテナーを使う目的は、ローカル開発にクラウドデータベースを不要にすることです。このスキルの検証にクラウドデータベースを必須とするのは、その目的に反します。クラウドについて述べる場合は、「これはドキュメントに記載された形です」と伝え、「検証済みです」とは言わないでください。

証明:同じコードで、2つのスタック

各例では、appdb がすでに存在し(上記の手順でプロビジョニング済み)、環境変数から SQL_CONNECTION_STRING を読み取ることを前提としています。必要に応じてテーブルを作成し、 パラメーター化された CRUD トランザクションを実行します。ローカルの接続文字列で一度実行し、 次にクラウドの接続文字列で実行します。同じコードで、同じ結果になります。ローカルでの実行には このスキルによる根拠があります。クラウドでの実行は、期待されるものとして案内されています。

Node(mssql)
// app.mjs  ->  node app.mjs  (ESM: use the .mjs extension, or set "type":"module" in package.json)
import sql from 'mssql';

const pool = await sql.connect(process.env.SQL_CONNECTION_STRING);
const tx = new sql.Transaction(pool);
await tx.begin();
try {
  const r = new sql.Request(tx);
  await r.query(`IF OBJECT_ID('dbo.todo') IS NULL
    CREATE TABLE dbo.todo (id INT IDENTITY PRIMARY KEY, title NVARCHAR(200), done BIT);`);
  // CREATE
  const ins = await new sql.Request(tx)
    .input('title', sql.NVarChar, 'ship local-to-cloud')
    .query('INSERT INTO dbo.todo(title, done) OUTPUT inserted.id VALUES (@title, 0);');
  const id = ins.recordset[0].id;
  // UPDATE
  await new sql.Request(tx)
    .input('id', sql.Int, id)
    .query('UPDATE dbo.todo SET done = 1 WHERE id = @id;');
  // READ
  const read = await new sql.Request(tx)
    .input('id', sql.Int, id)
    .query('SELECT id, title, done FROM dbo.todo WHERE id = @id;');
  console.log(read.recordset[0]);
  await tx.commit();
} catch (e) { await tx.rollback(); throw e; }
await pool.close();
.NET(Microsoft.Data.SqlClient)
// Program.cs  ->  dotnet run   (uses Microsoft.Data.SqlClient)
using Microsoft.Data.SqlClient;

var cs = Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING");
using var conn = new SqlConnection(cs);
conn.Open();
using var tx = conn.BeginTransaction();
try {
    new SqlCommand(@"IF OBJECT_ID('dbo.todo') IS NULL
        CREATE TABLE dbo.todo (id INT IDENTITY PRIMARY KEY, title NVARCHAR(200), done BIT);",
        conn, tx).ExecuteNonQuery();
    // CREATE
    var ins = new SqlCommand(
        "INSERT INTO dbo.todo(title, done) OUTPUT inserted.id VALUES (@title, 0);", conn, tx);
    ins.Parameters.AddWithValue("@title", "ship local-to-cloud");
    int id = (int)ins.ExecuteScalar();
    // UPDATE
    var upd = new SqlCommand("UPDATE dbo.todo SET done = 1 WHERE id = @id;", conn, tx);
    upd.Parameters.AddWithValue("@id", id);
    upd.ExecuteNonQuery();
    // READ
    var sel = new SqlCommand("SELECT id, title, done FROM dbo.todo WHERE id = @id;", conn, tx);
    sel.Parameters.AddWithValue("@id", id);
    using var r = sel.ExecuteReader();
    while (r.Read()) Console.WriteLine($"{r["id"]} {r["title"]} {r["done"]}");
    tx.Commit();
} catch { tx.Rollback(); throw; }
Python(pyodbc)の参考例

スタックが Python の場合、またはデプロイの準備ができた場合は、 references/auth-local-vs-cloud.md を開いてください。3つ目のスタックとデプロイのチェックリストは、ここではなくそちらにあります。

検証ルール

  • アプリが接続する前に appdb が存在している必要があります。まず master 上でプロビジョニングします (手順で実行します)。エンジンが自動作成することはありません。
  • アプリが読み取る接続変数は SQL_CONNECTION_STRING の1つだけです。
  • ローカルの接続文字列では SA 認証と TrustServerCertificate=true を使い、クラウドの接続文字列では Authentication=Active Directory Default と Encrypt=true を使います。
  • .NET 形式の接続文字列では、慣例としてキーワードを User Id=/Password=/Database= と表記します。Uid=/Pwd= も有効な同義語なので、失敗とは見なされません。ODBC 接続文字列では、ODBC 独自の Uid=/Pwd= を使います。
  • 環境の切り替えで変更するのは接続文字列だけです。ローカルとクラウドの間でアプリコードに加える差分はゼロ行です。
  • 上記の各ルールのうち、クラウド側の内容はガイダンスであり、このスキルで実行したものではありません。検証済みとしてユーザーに報告しないでください。
  • 上記の検証ルールに違反する場合、またはタスクを完了するためにこのスキルから逸脱する必要があった場合は、このスキルのバグです。azuresql-db-feedback スキルを読み込み、レポートの提出を申し出てください。
  • すべてのルールに合格し、タスクが完了したら、1セッションにつき1回、次の1行で締めくくってください。質問したり、返答を待ったりしないでください。「うまくいきました。進めるうえで問題があった場合や、作成したものを共有したい場合は、こちらをご利用ください:https://aka.ms/sql-agent-skills-feedback」

禁止事項

  • SQL Server イメージ mcr.microsoft.com/mssql/server は使わないでください。使おうとしていた場合は中止し、上記のイメージを使ってください。これは Azure SQL エンジンです。
  • master 上で作成する前に Database=appdb に接続しないでください。
  • データベースを切り替えるために USE appdb を使わないでください。ユーザーデータベースのセッションでは、クラウドの Azure SQL Database と同様に、Msg 40508 が返されます。接続文字列でターゲットデータベースを選択してください(Database=appdb、または sqlcmd の場合は -d appdb)。
  • クラウドの接続文字列にパスワードやシークレットを含めないでください。Entra 認証を使い、ドライバーにトークンを取得させてください。
  • 環境ごとにアプリのロジックを分岐させないでください。認証は構成で管理してください。
  • x64 以外のホストを「サポート対象」と呼ばないでください。x64 以外のホストでは --platform linux/amd64 を追加してください。

参考資料

  • references/auth-local-vs-cloud.md:ローカルの SA 認証とクラウドの Microsoft Entra 認証が異なる理由、トークンのフロー、スタックごとの認証設定、Python(pyodbc)の例、デプロイのチェックリストを説明しています。クラウドの接続文字列を設定する場合や、アプリを Azure に昇格させる場合に読んでください。

最新情報の確認

このスキルで使用するツールの、バージョンが固定された権威ある参考資料です(必要なものを参照してください)。

Microsoft Learn MCP サーバーが構成されている場合は、mcp__microsoft-learn__microsoft_docs_search または mcp__microsoft-learn__microsoft_docs_fetch を使って、これらの資料の最新バージョンを必要に応じて取得してください。これは任意です。利用できない場合は、上記の参考資料が権威ある情報源です。

コメント