Microsoft Azure をゼロからプロレベルまで: CLI、Bicep、Python による 100 の例

Microsoft Azure をゼロからプロレベルまで: CLI、Bicep、Python による 100 の例

Microsoft Azure は、サーバーを買わずに Web サイト、データベース、コンテナー、データパイプライン、AI サービスを動かすためのクラウドプラットフォームです。この記事では、最初のサインインから本番を意識した構成まで、100 の例で導きます。Azure CLI、リソースグループとタグ、Bicep によるインフラのコード化、マネージド ID と RBAC による ID 管理、仮想マシン、App Service、コンテナーと Kubernetes、SAS とライフサイクルルールによるストレージ、SQL と Cosmos DB、サーバーレスの Functions、仮想ネットワークとプライベートエンドポイント、Service Bus と Event Hubs、Log Analytics と Application Insights による監視、Key Vault、コスト管理を学びます。正直な注記: クラウドのコマンドと SDK の例は、Azure のサブスクリプションが必要なため実行していません。実行済みとして示した例は、このコンピューターで実際に実行し、その出力をコードの後ろに示しています。

必要なもの

サブスクリプションのある Azure アカウント(ほとんどの例には無料試用版で十分です)、Azure CLI、Python 3.10 以降、そして Bicep 拡張機能を入れた Visual Studio Code などのエディターです。学習にはサンドボックスのサブスクリプションを使い、実際の秘密情報をコマンドやコードに貼り付けないでください。一部のリソースには料金がかかるため、終わったら学習用のリソースグループを削除してください。

例の使い方

bash の例は Azure CLI で、Bicep の例は Azure CLI または VS Code で使います。Azure のアカウントが不要な Python の例は python で実行でき、実際の出力を示しています。Azure を呼び出す例はサブスクリプションがないと動きません。

トピック 1: Azure の基礎

Azure はサブスクリプション、リソースグループ、リソースで構成されます。サインインし、コマンドがどこで実行されるかを確認し、探しやすく費用を把握しやすい名前を使う方法を学びます。

Azure CLI とサインイン

Azure CLI はすべての Azure サービスに使える一つのツールです。インストールし、az login を実行し、az account show で確認します。コマンドは選択中のサブスクリプションに対して働くので、作成や削除の前に必ず確認してください。

リージョンと命名

各リソースはリージョンに置かれるので、利用者に近いリージョンを選び、必要なサービスがあるかを確認します。ストレージアカウント名は厳格です。3 から 24 文字の小文字と数字で、Azure 全体で一意でなければなりません。

命名規則

rg-app-env-region-01 のような形式は名前を統一し、人がリソースを見つけやすく、費用を理解しやすくします。小さな関数で名前を作り、すべてのスクリプトで再利用してください。

図解

一般的な Azure アプリケーションの構成: ユーザーはロードバランサーを経由して Web アプリに到達し、アプリは Key Vault から秘密情報を、データベースからデータを読み、ログとメトリックは Log Analytics に流れます
一般的な Azure アプリケーションの構成: ユーザーはロードバランサーを経由して Web アプリに到達し、アプリは Key Vault から秘密情報を、データベースからデータを読み、ログとメトリックは Log Analytics に流れます

例 1: Azure CLI のインストールとサインイン

コマンドラインツールを設定し、アカウントにログインします。

winget install -e --id Microsoft.AzureCLI
az --version
az login

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 2: 有効なサブスクリプションの確認

コマンドがどのサブスクリプションを変更するかを確かめます。

az account show --output table
az account list --query "[].{name:name, id:id, default:isDefault}" --output table

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 3: リソースグループの作成

一つのリージョンの関連リソースをまとめる入れ物です。

az group create --name rg-learn-dev --location southeastasia

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 4: Azure リージョンの一覧

デプロイできるリージョンを調べます。

az account list-locations --query "[?metadata.regionCategory=='Recommended'].name" --output tsv

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 5: ストレージアカウント名の検証

名前は 3 から 24 文字の小文字と数字です。

import re

def valid_storage_name(name):
    return re.fullmatch(r"[a-z0-9]{3,24}", name) is not None

for candidate in ("stlearndev01", "Store-1", "ab", "a" * 25):
    print(repr(candidate), valid_storage_name(candidate))

出力:

'stlearndev01' True
'Store-1' False
'ab' False
'aaaaaaaaaaaaaaaaaaaaaaaaa' False

例 6: 命名規則からリソース名を作る

一貫した名前は、リソースの検索と課金の把握を容易にします。

def resource_name(kind, app, env, region, index=1):
    return f"{kind}-{app}-{env}-{region}-{index:02d}"

print(resource_name("rg", "shop", "dev", "sea"))
print(resource_name("app", "shop", "prod", "sea", 3))

出力:

rg-shop-dev-sea-01
app-shop-prod-sea-03

トピック 2: リソースグループ、タグ、CLI の出力

リソースグループは一つのアプリケーションや環境のリソースをまとめます。タグは所有者と費用を記録し、CLI は人やスクリプトのために出力を絞り込み、整形できます。

リソースグループと削除

関連するリソースを一つのグループにまとめると、まとめて管理・削除できます。グループを削除すると中のすべてが消えるので、--no-wait は確信がある場合だけ使い、自分が作成していないグループは決して削除しないでください。

所有者と費用のためのタグ

タグは owner や costcenter のようなキーと値の組です。リソースを作るときに付け、欠けているものをスクリプトで確認します。費用レポートはタグごとに支出をまとめられます。

出力、クエリ、既定値

人には --output table、スクリプトには json を使います。--query は JMESPath でフィールドを絞り込みます。az configure で既定のグループとリージョンを設定すると、毎回入力せずに済みます。

例 7: リソースグループへのタグ付け

タグで所有者、コストセンター、環境を記録します。

az group update --name rg-learn-dev \
  --tags owner=team-a costcenter=1001 environment=dev

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 8: 必須タグの確認

チームに必要なタグがないリソースを見つけます。

REQUIRED = {"owner", "costcenter", "environment"}

def missing_tags(tags):
    return sorted(REQUIRED - set(tags))

print(missing_tags({"owner": "team-a", "environment": "dev"}))
print(missing_tags({"owner": "x", "costcenter": "1", "environment": "prod"}))

出力:

['costcenter']
[]

例 9: 待たずにリソースグループを削除

一つのコマンドでグループ全体を削除します。

az group delete --name rg-learn-test --yes --no-wait

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 10: 遅延が最も小さいリージョンの選択

利用者にとって最も速く応答するリージョンを選びます。

latency_ms = {"southeastasia": 42, "japaneast": 71, "eastus": 210, "westeurope": 185}

best = min(latency_ms, key=latency_ms.get)
print("closest region:", best, latency_ms[best], "ms")

出力:

closest region: southeastasia 42 ms

例 11: JMESPath クエリで出力を絞る

必要なフィールドと行だけを表示します。

az vm list \
  --query "[?powerState=='VM running'].{name:name, rg:resourceGroup}" \
  --output table

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 12: 出力形式の選択

人向けかスクリプト向けかに応じて表、JSON、YAML を選びます。

az group list --output table
az group list --output json
az group list --output yaml

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 13: スクリプトでリソースをループ処理

すべてのリソースグループに同じコマンドを実行します。

for rg in $(az group list --query "[].name" -o tsv); do
  echo "resource group: $rg"
done

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 14: 既定のグループとリージョンの設定

同じオプションを毎回入力しなくて済むようにします。

az configure --defaults group=rg-learn-dev location=southeastasia
az configure --list-defaults

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 3: スクリプトと自動化

繰り返し行う作業はスクリプトにまとめます。ループ、再試行、JSON の解析により、一回限りのコマンドがパイプラインで実行できる信頼性の高い自動化に変わります。

リソースに対するループ

シェルのループは一覧の各リソースに対して一つのコマンドを実行します。一覧は小さく保ち、何かを変える前に結果を確認してください。

JSON 出力の解析

テキストを読む代わりに、CLI に JSON を要求して解析します。種類ごとにリソースをまとめると、読みやすい要約ができます。

再試行と待機

Azure API は混雑したクライアントを制限します。待ち時間を少しずつ長くして再試行すれば、スクリプトはサービスを圧迫せずに回復できます。

例 15: CLI の JSON 出力を解析

リソースの一覧を要約に変えます。

import json

sample = """[{"name": "vm-web-01", "type": "Microsoft.Compute/virtualMachines", "location": "southeastasia"},
           {"name": "stlearn01", "type": "Microsoft.Storage/storageAccounts", "location": "southeastasia"}]"""

resources = json.loads(sample)
by_type = {}
for r in resources:
    by_type.setdefault(r["type"].split("/")[-1], []).append(r["name"])
for kind, names in sorted(by_type.items()):
    print(kind, names)

出力:

storageAccounts ['stlearn01']
virtualMachines ['vm-web-01']

例 16: 不安定な呼び出しをバックオフで再試行

制限されたリクエストのたびに待ち時間を長くします。

import time

def call_with_retry(fn, attempts=4, base_delay=0.05):
    for n in range(attempts):
        try:
            return fn()
        except ConnectionError as e:
            if n == attempts - 1:
                raise
            delay = base_delay * (2 ** n)
            print(f"attempt {n + 1} failed ({e}); retrying in {delay:.2f}s")
            time.sleep(delay)

state = {"calls": 0}
def flaky_list():
    state["calls"] += 1
    if state["calls"] < 3:
        raise ConnectionError("throttled")
    return ["rg-learn-dev"]

print(call_with_retry(flaky_list))

出力:

attempt 1 failed (throttled); retrying in 0.05s
attempt 2 failed (throttled); retrying in 0.10s
['rg-learn-dev']

例 17: CLI のバージョンと拡張機能の確認

ツールと拡張機能を最新に保ちます。

az version
az extension list --output table
az extension add --name containerapp --upgrade

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 18: サービスプリンシパルを安全に作成

自動化のためのアプリの ID を、最小の範囲で与えます。

# Store the output securely: it contains a password. Never commit it to Git.
az ad sp create-for-rbac --name sp-learn-deploy --role Contributor \
  --scopes /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 4: Bicep によるインフラのコード化

Bicep は Azure のリソースをコードで記述します。テンプレートはレビューでき、バージョン管理でき、毎回同じように展開できます。ポータルでクリックするより安全です。

リソース、パラメーター、出力

リソースの宣言は種類と API バージョンを指定し、プロパティを設定します。パラメーターはテンプレートを再利用可能にし、@secure はパスワードがログに残るのを防ぎます。出力は ID などの値を呼び出し元に返します。

モジュール、条件、ループ

モジュールは大きなテンプレートを再利用可能なファイルに分けます。条件は真のときだけリソースを作ります(例えば本番環境)。ループは一つのリストから複数のリソースを作ります。

安全なデプロイ

変更を確認するには az deployment group what-if を使い、その後で作成します。uniqueString で作った名前は、同じサブスクリプション内の環境間の衝突を避けます。

例 19: 最小構成の Bicep ストレージアカウント

ストレージアカウントをコードとして記述します。

param location string = resourceGroup().location
param storageName string

resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
  }
}

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 20: パラメーター、出力、秘密の値

テンプレートを再利用し、パスワードをファイルに書かないようにします。

@minLength(3)
@maxLength(24)
param storageName string

@allowed([
  'dev'
  'test'
  'prod'
])
param environment string = 'dev'

@secure()
param adminPassword string

output storageId string = storage.id
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageName
  location: resourceGroup().location
  sku: { name: environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS' }
  kind: 'StorageV2'
}

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 21: main.bicep からモジュールをデプロイ

大きなテンプレートを再利用可能なモジュールに分けます。

// main.bicep
targetScope = 'resourceGroup'
module network './modules/network.bicep' = {
  name: 'networkDeploy'
  params: {
    prefix: 'shop-dev'
  }
}
output vnetId string = network.outputs.vnetId

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 22: 条件付きリソース

本番環境でだけリソースを作ります。

param environment string

resource logs 'Microsoft.OperationalInsights/workspaces@2022-10-01' = if (environment == 'prod') {
  name: 'log-shop-prod'
  location: resourceGroup().location
  properties: {
    retentionInDays: 90
  }
}

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 23: Bicep でコンテナーをループ作成

一つのリストから複数の Blob コンテナーを作ります。

param containerNames array = [
  'uploads'
  'exports'
  'backups'
]

resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' existing = {
  name: 'stlearndev01'
}

resource containers 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-05-01' = [for name in containerNames: {
  name: '${storage.name}/default/${name}'
}]

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 24: uniqueString による一意の名前

サブスクリプション内で衝突しない名前を生成します。

param prefix string = 'shop'

var uniqueSuffix = uniqueString(resourceGroup().id)
var storageName = toLower('st${prefix}${uniqueSuffix}')

output generatedName string = storageName

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 25: Bicep ファイルのデプロイ

テンプレートからリソースを作成または更新します。

az deployment group create \
  --resource-group rg-learn-dev \
  --template-file main.bicep \
  --parameters storageName=stlearndev01 environment=dev

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 26: what-if で変更内容を事前確認

デプロイが何を追加、変更、削除するかを先に確認します。

az deployment group what-if \
  --resource-group rg-learn-dev \
  --template-file main.bicep \
  --parameters storageName=stlearndev01

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 5: ID とアクセス制御

セキュリティは、誰が何をできるかを決めることから始まります。マネージド ID はパスワードなしでアプリに資格情報を与え、ロールベースのアクセス制御は各 ID に必要な権限だけを与えます。

マネージド ID

マネージド ID は、Azure がアプリのために管理するアカウントです。アプリは秘密情報を保存せずにトークンを取得できます。複数のリソースが一つの ID を共有するときは、ユーザー割り当て ID を使います。

RBAC と最小権限

ロールの割り当ては、ID をスコープ(例えば一つのストレージアカウント)のロールに結び付けます。仕事に合う組み込みロールを優先し、どれも合わないときだけカスタムロールを作ります。

サービスプリンシパルとトークン

サービスプリンシパルは自動化のための ID です。そのパスワードは秘密情報なので、パイプラインの保管庫に保存します。トークンは署名された文字列で有効期限を持ち、その時刻はペイロードから読めます。

例 27: ユーザー割り当てのマネージド ID

パスワードを保存せずにアプリが使う ID です。

param location string = resourceGroup().location

resource appIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'id-shop-dev'
  location: location
}

output principalId string = appIdentity.properties.principalId

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 28: RBAC で読み取りアクセスを付与

ID に必要なロールだけを与えます。

PRINCIPAL_ID=$(az identity show --name id-shop-dev --resource-group rg-learn-dev --query principalId -o tsv)
az role assignment create \
  --assignee-object-id "$PRINCIPAL_ID" \
  --assignee-principal-type ServicePrincipal \
  --role "Storage Blob Data Reader" \
  --scope /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev/providers/Microsoft.Storage/storageAccounts/stlearndev01

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 29: サービスプリンシパルでパイプラインにサインイン

自動化はパイプラインの秘密情報でログインします。

az login --service-principal \
  --username "$AZURE_CLIENT_ID" \
  --password "$AZURE_CLIENT_SECRET" \
  --tenant "$AZURE_TENANT_ID"

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 30: ロール割り当ての確認

リソースで誰が何をできるかを確認します。

assignments = [
    {"principal": "id-shop-dev", "role": "Storage Blob Data Reader", "scope": "stlearndev01"},
    {"principal": "sp-learn-deploy", "role": "Contributor", "scope": "rg-learn-dev"},
    {"principal": "id-shop-dev", "role": "Key Vault Secrets User", "scope": "kv-shop-dev"},
]

def roles_for(principal):
    return sorted(a["role"] for a in assignments if a["principal"] == principal)

print(roles_for("id-shop-dev"))
print(roles_for("nobody"))

出力:

['Key Vault Secrets User', 'Storage Blob Data Reader']
[]

例 31: マネージド ID で VM にサインイン

VM はパスワードなしでトークンを取得します。

az login --identity
az account show --query "user.assignedIdentityInfo" -o tsv

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 32: JWT からトークンの有効期限を読む

トークンはペイロードに有効期限を持ちます。

import base64
import json

def jwt_payload(token):
    part = token.split(".")[1]
    part += "=" * (-len(part) % 4)
    return json.loads(base64.urlsafe_b64decode(part))

payload = {"aud": "https://management.azure.com/", "exp": 1767225600, "upn": "[email protected]"}
raw = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
token = f"header.{raw}.signature"

claims = jwt_payload(token)
print("audience:", claims["aud"])
print("expires at unix time:", claims["exp"])

出力:

audience: https://management.azure.com/
expires at unix time: 1767225600

例 33: 最小権限のカスタムロール

一つの範囲で一つの操作だけを許可します。

{
  "Name": "Blob Uploader",
  "IsCustom": true,
  "Description": "Can upload blobs to one storage account only.",
  "Actions": [],
  "DataActions": [
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write"
  ],
  "AssignableScopes": [
    "/subscriptions/<subscription-id>/resourceGroups/rg-learn-dev"
  ]
}

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 34: カスタムロールの作成

ロール定義をサブスクリプションに登録します。

az role definition create --role-definition @blob-uploader.json

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 6: コンピュート: 仮想マシンと App Service

Azure はコードを仮想マシンや管理されたプラットフォームで動かします。App Service はサーバーの作業のほとんどを取り除き、仮想マシンは OS を完全に制御できます。

仮想マシンとスケールセット

仮想マシンはサイズ、イメージ、ディスク、ネットワークインターフェースを持ちます。スケールセットは同一の VM を動かし、需要に応じて増減します。開発用マシンは夜に止めて費用を節約します。

App Service プランと Web アプリ

プランはマシンとその料金を定義し、Web アプリはその上で動きます。コードは zip ファイルとしてデプロイし、構成はアプリ設定で行い、利用者が変更を見る前にデプロイスロットで試します。

自動スケールの判断

スケールルールは、平均 CPU などのメトリックをしきい値と比べ、インスタンスを追加または削除します。クールダウンは、システムがサイズの間で行ったり来たりするのを防ぎます。

例 35: Linux VM の作成

選んだサイズとイメージで仮想マシンを起動します。

az vm create \
  --resource-group rg-learn-dev \
  --name vm-web-01 \
  --image Ubuntu2204 \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 36: VM のサイズとディスクの一覧

サイズ変更の前に容量とストレージを確認します。

az vm list-sizes --location southeastasia --output table | head -n 10
az vm disk list --resource-group rg-learn-dev --output table

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 37: 仮想マシンスケールセット

同じ VM を一緒に増減させて動かします。

resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = {
  name: 'vmss-web'
  location: resourceGroup().location
  sku: {
    name: 'Standard_B2s'
    capacity: 2
  }
  properties: {
    upgradePolicy: { mode: 'Rolling' }
    // osProfile, networkProfile and storageProfile go here
  }
}

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 38: 開発用 VM の自動シャットダウン

テスト用マシンを毎晩止めて費用を節約します。

az vm auto-shutdown --resource-group rg-learn-dev --name vm-web-01 --time 2100

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 39: App Service プランと Web アプリの作成

管理された Linux サーバーで Web アプリを動かします。

az appservice plan create --name plan-shop-dev --resource-group rg-learn-dev --sku B1 --is-linux
az webapp create --name app-shop-dev-01 --resource-group rg-learn-dev \
  --plan plan-shop-dev --runtime "PYTHON:3.12"

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 40: zip ファイルからコードをデプロイ

アプリのパッケージを Web アプリにアップロードします。

zip -r app.zip . -x "*.git*"
az webapp deploy --resource-group rg-learn-dev --name app-shop-dev-01 \
  --src-path app.zip --type zip

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 41: アプリ設定とステージングスロット

利用者に届く前に新しいバージョンを試します。

az webapp config appsettings set --resource-group rg-learn-dev --name app-shop-dev-01 \
  --settings ENVIRONMENT=dev LOG_LEVEL=info
az webapp deployment slot create --resource-group rg-learn-dev --name app-shop-dev-01 --slot staging

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 42: CPU に基づくスケールの判断

混雑時はインスタンスを増やし、空いたら減らします。

def scale_decision(cpu_samples, instances, minimum=1, maximum=5):
    average = sum(cpu_samples) / len(cpu_samples)
    if average > 75 and instances < maximum:
        return instances + 1, f"scale out (avg CPU {average:.0f}%)"
    if average < 25 and instances > minimum:
        return instances - 1, f"scale in (avg CPU {average:.0f}%)"
    return instances, f"hold (avg CPU {average:.0f}%)"

print(scale_decision([82, 90, 78], 2))
print(scale_decision([10, 12, 15], 2))
print(scale_decision([40, 45, 50], 2))

出力:

(3, 'scale out (avg CPU 83%)')
(1, 'scale in (avg CPU 12%)')
(2, 'hold (avg CPU 45%)')

トピック 7: コンテナー: レジストリ、Container Apps、Kubernetes

コンテナーは、アプリとそれに必要なすべてをまとめて包みます。Azure はイメージをレジストリに保存し、必要な制御の度合いに応じて Container Apps か Kubernetes で動かします。

Azure Container Registry

レジストリはイメージのための非公開の保管場所です。az acr build で Azure 内にイメージをビルドすれば、ビルドはあなたのコンピューターに依存せず、結果をレジストリに送れます。

Container Apps と AKS

Container Apps はクラスターを管理せずにコンテナーを動かし、ゼロまで縮小できます。AKS は大規模なシステム向けの管理された Kubernetes です。AKS はマネージド ID でレジストリからイメージを取得できるので、パスワードは不要です。

タグと後片付け

ロールバックできるように、各イメージにバージョン、日付、コミットのタグを付けます。タグのない古いイメージを削除するパージタスクをスケジュールし、ストレージ費用を抑えます。

例 43: コンテナーレジストリの作成

コンテナーイメージを保存する非公開の場所です。

az acr create --resource-group rg-learn-dev --name acrshopdev01 --sku Basic
az acr login --name acrshopdev01

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 44: イメージのビルドとプッシュ

Azure でイメージをビルドし、レジストリに保存します。

az acr build --registry acrshopdev01 --image shop-api:1.0.0 .
az acr repository show-tags --name acrshopdev01 --repository shop-api -o table

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 45: コンテナーアプリの実行

サーバーを管理せずにコンテナーを動かします。

az containerapp env create --name cae-shop-dev --resource-group rg-learn-dev --location southeastasia
az containerapp create --name ca-shop-api --resource-group rg-learn-dev \
  --environment cae-shop-dev \
  --image acrshopdev01.azurecr.io/shop-api:1.0.0 \
  --target-port 8080 --ingress external --min-replicas 0 --max-replicas 3

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 46: AKS クラスターの作成

レジストリからイメージを取得する、管理された Kubernetes クラスターです。

az aks create \
  --resource-group rg-learn-dev \
  --name aks-shop-dev \
  --node-count 2 \
  --enable-managed-identity \
  --attach-acr acrshopdev01 \
  --generate-ssh-keys
az aks get-credentials --resource-group rg-learn-dev --name aks-shop-dev

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 47: Kubernetes へのデプロイ

マニフェストを適用し、ロールアウトの完了を待ちます。

kubectl apply -f deployment.yaml
kubectl rollout status deployment/shop-api
kubectl get pods -l app=shop-api

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 48: Kubernetes のデプロイマニフェスト

Pod、レプリカ数、リソースを記述します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: shop-api
  template:
    metadata:
      labels:
        app: shop-api
    spec:
      containers:
        - name: shop-api
          image: acrshopdev01.azurecr.io/shop-api:1.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 100m
              memory: 128Mi

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 49: イメージタグの生成

バージョン、日付、コミットで各イメージにタグを付けます。

from datetime import date

def image_tag(version, commit, when):
    short = commit[:7]
    return f"{version}-{when.strftime('%Y%m%d')}-{short}"

print(image_tag("1.4.2", "9f3c1ab7e54d0a12", date(2026, 1, 15)))

出力:

1.4.2-20260115-9f3c1ab

例 50: タスクで古いイメージを削除

タグのないイメージを定期的に削除して容量を節約します。

az acr task create --name purge-old-images --registry acrshopdev01 \
  --cmd "acr purge --filter 'shop-api:.*' --ago 30d --untagged" \
  --schedule "0 1 * * *" --context /dev/null

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 8: ストレージ: Blob、キュー、アクセス制御

ストレージアカウントは、ファイル、メッセージ、テーブルを保持します。Entra ID でアクセスを保護し、共有が必要なときは有効期限の短い SAS リンクを使い、ライフサイクルルールで古いデータを安価な階層へ移します。

Blob とパスの命名

Blob コンテナーはファイルを保持します。デバイスと日付を含むパスを使うと、一日分のデータをすばやく一覧表示したり削除したりできます。内容を公開する必要がない限り、パブリックアクセスはオフにしてください。

共有アクセス署名

SAS リンクは短時間、限られたアクセスを与えます。読み取りなど必要な権限だけを与え、使える中で最も短い有効期限を選びます。

ライフサイクルルールとキュー

ライフサイクルルールは Blob を cool または archive 階層へ移し、設定した日数の後に削除します。キューはバックグラウンドのワーカーのためにメッセージを保持するので、遅い処理が Web リクエストを止めることはありません。

例 51: ストレージアカウントの作成

安全な既定値: TLS 1.2 と、公開 Blob へのアクセスを無効にします。

az storage account create \
  --name stlearndev01 \
  --resource-group rg-learn-dev \
  --location southeastasia \
  --sku Standard_LRS \
  --kind StorageV2 \
  --min-tls-version TLS1_2 \
  --allow-blob-public-access false

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 52: 日付で分けた Blob パス

デバイスと日付で整理し、問い合わせを速く保ちます。

from datetime import datetime

def blob_path(device, when, filename):
    return f"telemetry/{device}/{when:%Y/%m/%d}/{when:%H%M%S}-{filename}"

print(blob_path("sensor-7", datetime(2026, 1, 15, 8, 30, 5), "batch.json"))

出力:

telemetry/sensor-7/2026/01/15/083005-batch.json

例 53: Blob のアップロード

CLI でファイルをコンテナーにコピーします。

az storage container create --name uploads --account-name stlearndev01 --auth-mode login
az storage blob upload --account-name stlearndev01 --container-name uploads \
  --name reports/2026-01.csv --file ./report.csv --auth-mode login

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 54: Entra ID を使った Python からのアップロード

アカウントキーの代わりに Azure の ID を使います。

from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient

client = BlobServiceClient(
    account_url="https://stlearndev01.blob.core.windows.net",
    credential=DefaultAzureCredential(),
)
blob = client.get_blob_client(container="uploads", blob="reports/2026-01.csv")
with open("report.csv", "rb") as data:
    blob.upload_blob(data, overwrite=True)

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 55: 有効期限の短い SAS の作成

期限が切れ、読み取りだけを許可するリンクです。

EXPIRY=$(date -u -d "+1 hour" '+%Y-%m-%dT%H:%MZ')
az storage blob generate-sas --account-name stlearndev01 --container-name uploads \
  --name reports/2026-01.csv --permissions r --expiry "$EXPIRY" --auth-mode login --as-user --output tsv

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 56: SAS の権限の説明

共有アクセス署名が何をどれだけの間許可するかを説明します。

from datetime import datetime, timedelta, timezone

def describe_sas(permissions, expiry):
    names = {"r": "read", "w": "write", "d": "delete", "c": "create"}
    allowed = ", ".join(names[p] for p in permissions)
    left = expiry - datetime(2026, 1, 15, 8, 0, tzinfo=timezone.utc)
    return f"allows {allowed} for {int(left.total_seconds() // 60)} minutes"

print(describe_sas("rw", datetime(2026, 1, 15, 9, 0, tzinfo=timezone.utc)))

出力:

allows read, write for 60 minutes

例 57: Blob のライフサイクルルール

古いデータを安価なストレージへ移し、その後削除します。

{
  "rules": [
    {
      "enabled": true,
      "name": "archive-telemetry",
      "type": "Lifecycle",
      "definition": {
        "filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["telemetry/"] },
        "actions": {
          "baseBlob": {
            "tierToCool": { "daysAfterModificationGreaterThan": 30 },
            "delete": { "daysAfterModificationGreaterThan": 365 }
          }
        }
      }
    }
  ]
}

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 58: バックグラウンド作業のためのストレージキュー

ジョブをキューに入れ、後でワーカーに処理させます。

az storage queue create --name jobs --account-name stlearndev01 --auth-mode login
az storage message put --queue-name jobs --content "resize:photo-42" \
  --account-name stlearndev01 --auth-mode login

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 9: データベース: Azure SQL と Cosmos DB

Azure は管理されたリレーショナルデータベースと、世界中に分散された NoSQL データベースを提供します。パスワードではなく ID で接続し、クエリでは常にパラメーターを使います。

Azure SQL

Azure SQL は管理された SQL Server データベースです。Microsoft Entra ID 認証とプライベートエンドポイントを有効にすると、データベースには保存されたパスワードも公開アドレスもなくなります。

パラメーター化されたクエリ

利用者の入力は、決して文字列連結で SQL に入れず、パラメーターとして渡します。データベースは入力をデータとして扱うので、SQL インジェクションを防げます。

Cosmos DB とパーティションキー

Cosmos DB はコンテナーに JSON ドキュメントを保存します。パーティションキーは、データを複数のマシンにどう分散するかを決めます。顧客 ID のように値の種類が多いキーは、負荷を均等に保ちます。

例 59: Azure SQL サーバーとデータベース

プライベートネットワーク対応の管理されたリレーショナルデータベースです。

az sql server create --name sql-shop-dev-01 --resource-group rg-learn-dev \
  --location southeastasia --enable-public-network false --enable-ad-only-auth \
  --external-admin-principal-type User --external-admin-name [email protected]
az sql db create --resource-group rg-learn-dev --server sql-shop-dev-01 \
  --name shopdb --service-objective S0

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 60: パスワードなしで Azure SQL に接続

保存されたパスワードの代わりに Entra ID で認証します。

import pyodbc

conn = pyodbc.connect(
    "Driver={ODBC Driver 18 for SQL Server};"
    "Server=tcp:sql-shop-dev-01.database.windows.net,1433;"
    "Database=shopdb;Encrypt=yes;"
    "Authentication=ActiveDirectoryDefault;"
)
cursor = conn.cursor()
cursor.execute("SELECT TOP 5 name FROM sys.tables")
print([row.name for row in cursor.fetchall()])

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 61: パラメーター化されたクエリ

値をパラメーターとして渡し、入力がクエリを変えないようにします。

import sqlite3

conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE orders (id INTEGER, customer TEXT, total REAL)")
conn.executemany("INSERT INTO orders VALUES (?, ?, ?)",
                 [(1, "ana", 120.0), (2, "ben", 75.5)])

customer = "ana' OR '1'='1"          # hostile input stays a plain value
rows = conn.execute("SELECT id, total FROM orders WHERE customer = ?", (customer,)).fetchall()
print("matches:", rows)
conn.close()

出力:

matches: []

例 62: Cosmos DB コンテナーの作成

パーティションキーを持つ、世界中に分散されたデータベースです。

az cosmosdb create --name cosmos-shop-dev-01 --resource-group rg-learn-dev \
  --locations regionName=southeastasia failoverPriority=0
az cosmosdb sql database create --account-name cosmos-shop-dev-01 --resource-group rg-learn-dev \
  --name shop
az cosmosdb sql container create --account-name cosmos-shop-dev-01 --resource-group rg-learn-dev \
  --database-name shop --name orders --partition-key-path "/customerId"

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 63: Cosmos DB への項目の書き込み

コンテナーに JSON ドキュメントを保存します。

from azure.cosmos import CosmosClient
from azure.identity import DefaultAzureCredential

client = CosmosClient("https://cosmos-shop-dev-01.documents.azure.com:443/", DefaultAzureCredential())
container = client.get_database_client("shop").get_container_client("orders")
container.upsert_item({"id": "o-1001", "customerId": "ana", "total": 120.0})

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 64: パーティションキーのハッシュで項目を分散

良いキーはデータをパーティション全体に均等に分けます。

import hashlib

def partition_for(key, partitions=4):
    digest = hashlib.sha256(key.encode("utf-8")).hexdigest()
    return int(digest, 16) % partitions

counts = [0, 0, 0, 0]
for customer in ["ana", "ben", "chai", "dao", "eve", "fon", "gus", "hana"]:
    counts[partition_for(customer)] += 1
print("items per partition:", counts)

出力:

items per partition: [4, 1, 1, 2]

トピック 10: Azure Functions によるサーバーレス

Azure Functions は、HTTP リクエスト、タイマー、キュー内のメッセージなど、何かが起きたときに小さなコードを実行します。実行に対して料金を払い、サーバーを管理する必要はありません。

トリガーとバインディング

トリガーは HTTP リクエストやタイマーなど、関数を開始するものです。バインディングは、キューへの書き込みのように関数を他のサービスに結び付け、接続のコードを減らします。

タイマーと cron スケジュール

タイマートリガーは秒を先頭に置いた六つのフィールドの NCRONTAB 式を使います。式 0 */5 * * * * は五分ごとに実行されます。

冪等な処理

キューは同じメッセージを二回以上配信することがあります。処理済みの ID を記録して重複をスキップすれば、ジョブを二回実行しても顧客に二回課金されることはありません。

例 65: 関数アプリの作成

Consumption プランのサーバーレスコードです。

az storage account create --name stfuncshopdev01 --resource-group rg-learn-dev --sku Standard_LRS
az functionapp create --name func-shop-dev-01 --resource-group rg-learn-dev \
  --storage-account stfuncshopdev01 --consumption-plan-location southeastasia \
  --runtime python --runtime-version 3.12 --functions-version 4 --os-type Linux

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 66: HTTP でトリガーされる関数

Web リクエストが届いたときにコードを実行します。

import azure.functions as func

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)

@app.route(route="hello", methods=["GET"])
def hello(req: func.HttpRequest) -> func.HttpResponse:
    name = req.params.get("name", "world")
    return func.HttpResponse(f"Hello, {name}!", status_code=200)

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 67: cron スケジュールのタイマー関数

サーバーなしで五分ごとにコードを実行します。

import logging
import azure.functions as func

app = func.FunctionApp()

@app.timer_trigger(schedule="0 */5 * * * *", arg_name="timer", run_on_startup=False)
def every_five_minutes(timer: func.TimerRequest) -> None:
    logging.info("checking sensors")

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 68: cron 式の次の実行時刻

スケジュールが次にいつ動くかを計算します。

def next_minutes(expression, current_minute):
    field = expression.split()[1]           # minute field, for example */5
    step = int(field.removeprefix("*/"))
    return step - (current_minute % step) if current_minute % step else step

for minute in (0, 3, 12, 14):
    print(f"at minute {minute:2d}: next run in {next_minutes('0 */5 * * * *', minute)} min")

出力:

at minute  0: next run in 5 min
at minute  3: next run in 2 min
at minute 12: next run in 3 min
at minute 14: next run in 1 min

例 69: 関数アプリの発行

Python コードを Azure Functions にデプロイします。

func azure functionapp publish func-shop-dev-01 --python

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 70: キューでトリガーされる関数

メッセージを一つずつ処理し、結果を別のキューに書きます。

import azure.functions as func

app = func.FunctionApp()

@app.queue_trigger(arg_name="msg", queue_name="jobs", connection="AzureWebJobsStorage")
@app.queue_output(arg_name="out", queue_name="done", connection="AzureWebJobsStorage")
def process(msg: func.QueueMessage, out: func.Out[str]) -> None:
    out.set(f"processed:{msg.get_body().decode('utf-8')}")

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 71: 冪等なメッセージ処理

同じメッセージが二度届いても一度だけ処理します。

processed_ids = set()

def handle(message):
    if message["id"] in processed_ids:
        return "skipped duplicate"
    processed_ids.add(message["id"])
    return f"processed {message['id']}"

events = [{"id": "e1"}, {"id": "e2"}, {"id": "e1"}]
for event in events:
    print(handle(event))

出力:

processed e1
processed e2
skipped duplicate

例 72: アプリ設定での Key Vault 参照

シークレットをコピーせずにアプリに読み込みます。

az functionapp config appsettings set --name func-shop-dev-01 --resource-group rg-learn-dev \
  --settings "[email protected](VaultName=kv-shop-dev;SecretName=db-password)"

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 11: ネットワーク: 仮想ネットワーク、NSG、プライベートエンドポイント

仮想ネットワークは Azure 内のあなた専用のネットワークです。サブネットは層を分け、セキュリティルールは通信を制限し、プライベートエンドポイントはサービスを公開インターネットから遠ざけます。

仮想ネットワークとサブネット

10.10.0.0/16 のようなアドレス範囲を選び、Web とデータ用のサブネットに分けます。Azure は各サブネットで五つのアドレスを予約するので、/24 では使えるアドレスが 251 になります。

ネットワークセキュリティグループ

NSG は優先度付きの許可と拒否のルールの一覧です。HTTPS の 443 など必要なポートだけを許可し、それ以外は既定で拒否します。

プライベートエンドポイントと DNS

プライベートエンドポイントは、サービスにネットワーク内のプライベート IP を与えます。プライベート DNS ゾーンは、そのサービス名をその IP に解決するので、アプリケーションのコードを変える必要はありません。

例 73: 仮想ネットワークとサブネット

Web とデータ用にサブネットを分けたプライベートネットワークです。

az network vnet create --name vnet-shop-dev --resource-group rg-learn-dev \
  --address-prefix 10.10.0.0/16 --subnet-name snet-web --subnet-prefix 10.10.1.0/24
az network vnet subnet create --vnet-name vnet-shop-dev --resource-group rg-learn-dev \
  --name snet-data --address-prefixes 10.10.2.0/24

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 74: ネットワークセキュリティグループのルール

インターネットからの HTTPS だけを許可します。

az network nsg create --name nsg-web --resource-group rg-learn-dev
az network nsg rule create --nsg-name nsg-web --resource-group rg-learn-dev \
  --name allow-https --priority 100 --direction Inbound --access Allow \
  --protocol Tcp --destination-port-ranges 443 --source-address-prefixes Internet

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 75: ストレージのプライベートエンドポイント

ストレージアカウントにネットワーク内からだけ接続します。

az network private-endpoint create --name pe-storage --resource-group rg-learn-dev \
  --vnet-name vnet-shop-dev --subnet snet-data \
  --private-connection-resource-id $(az storage account show -n stlearndev01 -g rg-learn-dev --query id -o tsv) \
  --group-id blob --connection-name conn-storage

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 76: プライベート DNS ゾーン

仮想ネットワーク内でプライベートエンドポイントの名前を解決します。

az network private-dns zone create --resource-group rg-learn-dev \
  --name privatelink.blob.core.windows.net
az network private-dns link vnet create --resource-group rg-learn-dev \
  --zone-name privatelink.blob.core.windows.net --name link-shop \
  --virtual-network vnet-shop-dev --registration-enabled false

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 77: パブリックロードバランサー

受信トラフィックを複数の仮想マシンに分散します。

az network public-ip create --name pip-lb --resource-group rg-learn-dev --sku Standard
az network lb create --name lb-shop --resource-group rg-learn-dev --sku Standard \
  --public-ip-address pip-lb --backend-pool-name be-web
az network lb probe create --lb-name lb-shop --resource-group rg-learn-dev \
  --name probe-https --protocol Tcp --port 443

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 78: サブネットサイズの計算

CIDR ブロックで使える IP アドレス数を数えます。

import ipaddress

def usable_hosts(cidr):
    net = ipaddress.ip_network(cidr)
    return net.num_addresses - 5          # Azure reserves 5 addresses in every subnet

for block in ("10.10.1.0/24", "10.10.2.0/27", "10.10.0.0/16"):
    print(block, usable_hosts(block))

出力:

10.10.1.0/24 251
10.10.2.0/27 27
10.10.0.0/16 65531

トピック 12: メッセージングとストリーミング: Service Bus と Event Hubs

サービス同士はメッセージを通して通信します。Service Bus は信頼性の高い業務メッセージ向けで、Event Hubs はテレメトリのような大量のストリーム向けです。

Service Bus のキュー

キューは、受信者がメッセージを完了するまで保持します。処理が終わってから完了させることで、障害が起きても注文が失われず再試行になります。失敗が多すぎるメッセージはデッドレターキューへ移ります。

Event Hubs とパーティション

イベントハブはストリームを複数のパーティションに分け、多くの読み手が並列に読めるようにします。イベントはバッチで送り、各バッチを上限サイズ以下に保ちます。

どちらを選ぶか

一つ一つのメッセージが重要で、意図どおりに正確に処理される必要があるときは Service Bus を使います。大量のイベントを集め、パーティション内で順番に処理してよいときは Event Hubs を使います。

例 79: Service Bus キュー

デッドレターに対応した、アプリ間の信頼性の高いメッセージングです。

az servicebus namespace create --name sb-shop-dev --resource-group rg-learn-dev --location southeastasia --sku Standard
az servicebus queue create --namespace-name sb-shop-dev --resource-group rg-learn-dev \
  --name orders --max-delivery-count 5 --dead-lettering-on-message-expiration true

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 80: Service Bus へのメッセージ送信

Python から注文をキューに入れます。

from azure.identity import DefaultAzureCredential
from azure.servicebus import ServiceBusClient, ServiceBusMessage

with ServiceBusClient("sb-shop-dev.servicebus.windows.net", DefaultAzureCredential()) as client:
    with client.get_queue_sender("orders") as sender:
        sender.send_messages(ServiceBusMessage('{"orderId": "o-1001"}'))

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 81: メッセージの受信と完了

処理が済んでからだけメッセージを削除します。

from azure.identity import DefaultAzureCredential
from azure.servicebus import ServiceBusClient

with ServiceBusClient("sb-shop-dev.servicebus.windows.net", DefaultAzureCredential()) as client:
    with client.get_queue_receiver("orders", max_wait_time=5) as receiver:
        for msg in receiver:
            print(str(msg))
            receiver.complete_message(msg)     # removes it only after processing succeeded

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 82: テレメトリ用の Event Hubs

毎秒数百万のイベントを受け付けるストリームです。

az eventhubs namespace create --name evhns-shop-dev --resource-group rg-learn-dev --location southeastasia --sku Standard
az eventhubs eventhub create --name telemetry --namespace-name evhns-shop-dev --resource-group rg-learn-dev \
  --partition-count 4 --message-retention 1

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 83: Event Hubs へのバッチ送信

効率のためにイベントをバッチにまとめます。

import json
from azure.eventhub import EventData, EventHubProducerClient
from azure.identity import DefaultAzureCredential

producer = EventHubProducerClient(
    fully_qualified_namespace="evhns-shop-dev.servicebus.windows.net",
    eventhub_name="telemetry",
    credential=DefaultAzureCredential(),
)
with producer:
    batch = producer.create_batch()
    batch.add(EventData(json.dumps({"device": "sensor-7", "temp_c": 21.5})))
    producer.send_batch(batch)

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 84: サイズ上限でメッセージを分割

各バッチを上限サイズ以下に保ちます。

def make_batches(messages, limit_bytes=60):
    batches, current, size = [], [], 0
    for msg in messages:
        n = len(msg.encode("utf-8"))
        if current and size + n > limit_bytes:
            batches.append(current)
            current, size = [], 0
        current.append(msg)
        size += n
    if current:
        batches.append(current)
    return batches

events = [f'{{"id": {i}, "temp": 21.{i}}}' for i in range(6)]
for number, batch in enumerate(make_batches(events), start=1):
    print("batch", number, len(batch), "messages")

出力:

batch 1 2 messages
batch 2 2 messages
batch 3 2 messages

トピック 13: 監視: Log Analytics、Application Insights、アラート

見えないものは直せません。Azure Monitor はログとメトリックを集め、Log Analytics は KQL で問い合わせさせ、アラートは問題が起きたときにチームへ知らせます。

Log Analytics と KQL

Log Analytics ワークスペースは多くのリソースからのログを保存します。Kusto Query Language はそれを絞り込み、要約し、グラフにします。例えば時間ごとの失敗数を数えられます。

Application Insights

Application Insights は、コードからのリクエスト、依存関係、カスタムイベントを追跡します。アプリが遅いことだけでなく、どの呼び出しが遅いのかを見つけるのに使います。

誤報のないアラート

メトリックアラートは、値がしきい値を超えたときに発報します。条件が連続した複数のサンプルで成り立つことを求めると、一度のスパイクで当番のエンジニアが起こされることはありません。

例 85: Log Analytics ワークスペース

すべてのリソースのログを問い合わせる一か所の場所です。

az monitor log-analytics workspace create --resource-group rg-learn-dev \
  --workspace-name log-shop-dev --location southeastasia --retention-time 30

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 86: 失敗を調べる KQL クエリ

Kusto Query Language で時間ごとの失敗リクエストを数えます。

AppRequests
| where TimeGenerated > ago(24h)
| where Success == false
| summarize failures = count() by bin(TimeGenerated, 1h), ResultCode
| order by TimeGenerated desc

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 87: 診断設定

プラットフォームのログとメトリックをワークスペースに送ります。

az monitor diagnostic-settings create \
  --name diag-storage \
  --resource /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev/providers/Microsoft.Storage/storageAccounts/stlearndev01 \
  --workspace log-shop-dev \
  --logs '[{"category":"StorageRead","enabled":true}]' \
  --metrics '[{"category":"Transaction","enabled":true}]'

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 88: Application Insights のテレメトリ

Python コードからリクエストとカスタムイベントを追跡します。

from opentelemetry import trace
from azure.monitor.opentelemetry import configure_azure_monitor

configure_azure_monitor(connection_string="InstrumentationKey=<key>;IngestionEndpoint=https://southeastasia-1.in.applicationinsights.azure.com/")
tracer = trace.get_tracer("shop")
with tracer.start_as_current_span("checkout") as span:
    span.set_attribute("order.total", 120.0)

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 89: 応答時間のメトリックアラート

API が遅いときに当番チームに通知します。

az monitor metrics alert create --name alert-slow-api --resource-group rg-learn-dev \
  --scopes /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev/providers/Microsoft.Web/sites/app-shop-dev-01 \
  --condition "avg HttpResponseTime > 2" --window-size 5m --evaluation-frequency 1m \
  --action /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev/providers/microsoft.insights/actionGroups/ag-oncall

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 90: 連続した異常値の後でアラート

異常値が続いたときだけ通知して誤報を減らします。

def should_alert(samples, threshold=2.0, required=3):
    streak = 0
    for value in samples:
        streak = streak + 1 if value > threshold else 0
        if streak >= required:
            return True
    return False

print(should_alert([1.0, 2.5, 2.7, 2.9, 1.1]))
print(should_alert([2.5, 1.0, 2.5, 2.5, 1.0]))

出力:

True
False

トピック 14: セキュリティ: Key Vault、秘密情報、脅威からの保護

秘密情報はコードやログではなく保管庫に置くべきです。Key Vault はアクセス制御付きで保存し、Defender for Cloud はリソースを脅威の観点から監視します。

Key Vault とアクセス

Key Vault は秘密情報、キー、証明書を保存します。ロールベースのアクセスを使い、各アプリには必要な秘密情報だけの読み取り権限を与え、すべてのアクセスを記録します。

秘密情報を安全に読む

DefaultAzureCredential は、Azure ではマネージド ID を、コンピューターではあなたのサインインを使うので、同じコードが両方で動きます。秘密情報を決して表示せず、ログに書き込まないでください。

Defender for Cloud

Defender for Cloud はセキュリティの状態を評価し、VM、ストレージ、Key Vault の脅威保護を有効にします。推奨事項を定期的に確認してください。

例 91: Key Vault とシークレット

アクセス制御付きの保管庫にパスワードを保存します。

az keyvault create --name kv-shop-dev --resource-group rg-learn-dev --location southeastasia \
  --enable-rbac-authorization true
az keyvault secret set --vault-name kv-shop-dev --name db-password --value "$DB_PASSWORD"

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 92: Python からシークレットを読む

DefaultAzureCredential でシークレットを取得します。

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

client = SecretClient(vault_url="https://kv-shop-dev.vault.azure.net/", credential=DefaultAzureCredential())
password = client.get_secret("db-password").value
# use the value, never print it

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 93: ログからシークレットを隠す

何かを書き込む前にパスワードとキーを隠します。

import re

def redact(text):
    text = re.sub(r"(password|secret|token)=\S+", r"\1=***", text, flags=re.IGNORECASE)
    text = re.sub(r"(AccountKey=)[^;\s]+", r"\1***", text)
    return text

print(redact("connecting with password=hunter2 to host"))
print(redact("AccountKey=abc123==;EndpointSuffix=core.windows.net"))

出力:

connecting with password=*** to host
AccountKey=***;EndpointSuffix=core.windows.net

例 94: Defender for Cloud のプラン

VM、ストレージ、Key Vault の脅威保護を有効にします。

az security pricing create --name VirtualMachines --tier Standard
az security pricing create --name StorageAccounts --tier Standard
az security pricing create --name KeyVaults --tier Standard

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

トピック 15: DevOps、コスト、ガバナンス

本番のシステムには、繰り返し実行できるパイプライン、支出の上限、新しいリソースすべてが従うべきルールが必要です。これらの習慣により、チームが大きくなっても Azure は信頼でき、手頃な費用で使えます。

パイプラインとロールバック

パイプラインはすべての変更をテストし、main ブランチからデプロイします。リリース後はエラー率と遅延を監視し、しきい値を超えたらロールバックします。

予算とコストの見積もり

予算は月額の上限を設定し、到達する前に通知を送ります。時間とストレージからコストを見積もり、実際の請求と比べ、毎日のレポートをエクスポートします。

Azure Policy

ポリシーはリソースをルールと照合します。例えばオーナータグの必須化です。deny の効果は、規則に合わないリソースの作成を止め、合意した基準を強制します。

例 95: Azure DevOps のパイプライン

push のたびにテストし、main から Web アプリをデプロイします。

trigger:
  branches:
    include: [main]

pool:
  vmImage: ubuntu-latest

steps:
  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.12'
  - script: pip install -r requirements.txt && pytest
    displayName: Test
  - task: AzureWebApp@1
    inputs:
      azureSubscription: sc-shop-dev
      appName: app-shop-dev-01
      package: '$(System.DefaultWorkingDirectory)'

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 96: 月次の予算

支出の上限を設定し、到達前に通知します。

az consumption budget create --budget-name budget-dev --amount 200 \
  --category Cost --time-grain Monthly \
  --start-date 2026-01-01 --end-date 2026-12-31 \
  --resource-group rg-learn-dev

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 97: 月額料金の見積もり

利用時間とストレージから大まかな費用を計算します。

def monthly_cost(hours_per_day, hourly_rate, storage_gb, storage_rate, days=30):
    compute = hours_per_day * days * hourly_rate
    storage = storage_gb * storage_rate
    return round(compute + storage, 2)

print(monthly_cost(10, 0.05, 120, 0.02))
print(monthly_cost(24, 0.05, 120, 0.02))

出力:

17.4
38.4

例 98: コストデータのエクスポート

毎日のコストレポートをストレージアカウントに送ります。

az costmanagement export create --name daily-costs \
  --scope "/subscriptions/<subscription-id>/resourceGroups/rg-learn-dev" \
  --storage-account-id /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev/providers/Microsoft.Storage/storageAccounts/stlearndev01 \
  --storage-container exports --timeframe MonthToDate --recurrence Daily \
  --recurrence-period from=2026-01-01T00:00:00Z to=2026-12-31T00:00:00Z

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

例 99: ロールバックの判断

エラー率と遅延からロールバックするかを決めます。

def should_roll_back(error_rate, previous_error_rate, latency_ms, latency_limit=800):
    if error_rate > 0.05:
        return True, "error rate above 5 percent"
    if error_rate > previous_error_rate * 2 and error_rate > 0.01:
        return True, "error rate doubled since the last release"
    if latency_ms > latency_limit:
        return True, "latency above limit"
    return False, "healthy"

print(should_roll_back(0.02, 0.01, 300))
print(should_roll_back(0.07, 0.01, 300))

出力:

(False, 'healthy')
(True, 'error rate above 5 percent')

例 100: Azure Policy でタグを必須にする

所有者タグのない新しいリソースを拒否します。

az policy definition create --name require-owner-tag --display-name "Require owner tag" \
  --rules '{"if":{"field":"tags[owner]","exists":"false"},"then":{"effect":"deny"}}' --mode Indexed
az policy assignment create --name require-owner --policy require-owner-tag \
  --scope /subscriptions/<subscription-id>/resourceGroups/rg-learn-dev

*この例はここでは実行していません。Azure のサブスクリプションまたは Azure のツールが必要だからです。*

練習プロジェクト: ストレージと監視を備えた安全な Web アプリ

いくつかの節の考え方を使う、小さく安全な構成を一つ作ります。Bicep とスクリプトはまず自分で書き、その後で例と比べてください。課金を避けるため、終わったらリソースグループを削除してください。

1. owner と environment のタグを付けたリソースグループを作り、欠けているタグをスクリプトで確認します。

2. TLS 1.2 を使い、パブリックな Blob アクセスを許可しないストレージアカウントの Bicep テンプレートを書き、デプロイ前に what-if で確認します。

3. ユーザー割り当てのマネージド ID を作り、そのストレージアカウントだけに Storage Blob Data Reader ロールを与えます。

4. マネージド ID で Blob を読む Web アプリをデプロイし、平均応答時間が二秒を超え続けたときのアラートを追加します。

5. 月額上限の 80 パーセントで予算を作り、リソースグループを削除して、ポータルで削除を確認します。

次のステップ

次は、Azure のアーキテクチャガイダンスを学び、AZ-900 や AZ-104 のようなロールベースの資格を取得し、GitHub Actions や Azure DevOps でインフラのパイプラインを練習してください。まずはサンドボックスのサブスクリプションで各コマンドを実行し、デプロイするバージョンのサービスのドキュメントを読んでください。

まとめ

Azure は、コードで記述し、パスワードではなく ID で守り、監視し、費用を管理するとき、プロフェッショナルなプラットフォームになります。100 の例を通して、この記事では Azure CLI、リソースグループとタグ、スクリプト、Bicep、ID と RBAC、仮想マシンと App Service、コンテナーと Kubernetes、ストレージ、データベース、サーバーレスの Functions、ネットワーク、メッセージング、監視、Key Vault とセキュリティ、費用とガバナンスを含む DevOps を扱いました。ラボで安全な Web アプリを作り、一度に一つの設定を変えて、各部分の動きを確かめてください。