初期化コンテナーで Azure Container Instances をデプロイする
実際のアプリケーションが起動する前に特定のタスクを実行することが必要な場合があります。 たとえば、コンテナーからの受信接続を受け入れるように特定のサービスを構成することや、シークレットを Azure Key Vault からボリュームに挿入することが必要な場合があります。 初期化 (init) コンテナーを使用すると、これらの前提条件の検証または初期化タスクを実装できます。
init コンテナーはサイドカー パターンの一例ですが、このコンテナーは、コンテナー グループ内の他のすべてのコンテナーが開始される前に実行されます。 コンテナー グループ内のアプリケーション コンテナーは、定義された init コンテナーでそのタスクが正常に完了した後にのみ開始されます。 Azure Container Instances init コンテナーは、Kubernetes init コンテナーと同じ概念です。
顧客は、IP アドレスではなく完全修飾ドメイン名 (FQDN) を使用して API に到達したいと考えています。 また、コンテナー グループを再作成する場合に FQDN が変更されないようにしたいとも考えています。 このユニットでは、顧客が常に IP アドレスではなくドメイン名を使用して API にアクセスできるようにするために、init コンテナーを使用してドメイン ネーム システム (DNS) を更新します。
次の図は、Container Instances init コンテナーのトポロジを示しています。
init コンテナーは、アプリケーション コンテナーに割り当てられている IP アドレスを取得し、API クライアントでコンテナーに到達するために使用される DNS エントリを更新します。 init コンテナーとアプリケーション コンテナーは同じネットワーク スタックを共有するため、init コンテナーから参照可能な IP アドレスは、アプリケーション コンテナーで使用されるアドレスと同じです。
初期化スクリプトと DNS ゾーンを作成する
最初に、Azure サービス プリンシパルを作成します。init コンテナーではマネージド ID を使用できないため、init コンテナーはこのサービス プリンシパルを使用して、アプリケーションの IP アドレスを取得し、DNS を更新します。 この例では、わかりやすくするために、サービス プリンシパルに共同作成者ロールを割り当てます。 運用環境では、より厳格な制限が必要な場合があります。
Azure portal の Azure Cloud Shell で、次のコードを実行してサービス プリンシパルを作成します。
# Create service principal for authentication scope=$(az group show -n $rg --query id -o tsv) new_sp=$(az ad sp create-for-rbac --scopes $scope --role Contributor --name acilab -o json) sp_appid=$(echo $new_sp | jq -r '.appId') && echo $sp_appid sp_tenant=$(echo $new_sp | jq -r '.tenant') && echo $sp_tenant sp_password=$(echo $new_sp | jq -r '.password')
アプリケーション クライアントでコンテナー インスタンスにアクセスするための Azure プライベート DNS ゾーンを作成し、そのゾーンを仮想ネットワークに関連付けます。
# Create Azure DNS private zone and records dns_zone_name=contoso.com az network private-dns zone create -n $dns_zone_name -g $rg az network private-dns link vnet create -g $rg -z $dns_zone_name -n contoso --virtual-network $vnet_name --registration-enabled false
Note
この DNS ゾーンは、前のユニットで作成した DNS ゾーンとは異なります。前のゾーンは、コンテナー インスタンスで Azure SQL Database にアクセスするために使用されました。
スクリプトを init コンテナーに挿入する方法は数多くあります。 この場合は、Azure Files 共有を使用してスクリプトを格納します。 次のコードを実行して、初期化スクリプトと Azure Files 共有を作成し、スクリプトを共有にアップロードします。
# Create script for init container storage_account_name="acilab$RANDOM" az storage account create -n $storage_account_name -g $rg --sku Standard_LRS --kind StorageV2 storage_account_key=$(az storage account keys list --account-name $storage_account_name -g $rg --query '[0].value' -o tsv) az storage share create --account-name $storage_account_name --account-key $storage_account_key --name initscript init_script_filename=init.sh init_script_path=/tmp/ cat <<EOF > ${init_script_path}${init_script_filename} echo "Logging into Azure..." az login --service-principal -u \$SP_APPID -p \$SP_PASSWORD --tenant \$SP_TENANT echo "Finding out IP address..." # my_private_ip=\$(az container show -n \$ACI_NAME -g \$RG --query 'ipAddress.ip' -o tsv) && echo \$my_private_ip my_private_ip=\$(ifconfig eth0 | grep 'inet addr' | cut -d: -f2 | cut -d' ' -f 1) && echo \$my_private_ip echo "Deleting previous record if there was one…" az network private-dns record-set a delete -n \$HOSTNAME -z \$DNS_ZONE_NAME -g \$RG -y echo "Creating DNS record..." az network private-dns record-set a create -n \$HOSTNAME -z \$DNS_ZONE_NAME -g \$RG az network private-dns record-set a add-record --record-set-name \$HOSTNAME -z \$DNS_ZONE_NAME -g \$RG -a \$my_private_ip EOF az storage file upload --account-name $storage_account_name --account-key $storage_account_key -s initscript --source ${init_script_path}${init_script_filename}
この初期化スクリプトでは Azure CLI を使用して、コンテナー インスタンスの IP アドレスを検出し、プライベート DNS ゾーンに A レコードを作成するコマンドを実行します。 このスクリプトでは、環境変数として検出されることが予想されるサービス プリンシパルのアプリケーション ID とシークレットを使用して認証を行います。
init コンテナーを使用してコンテナー グループをデプロイする
前のユニットで使用したファイルを基にして YAML ファイルを作成できるようになりました。 次の YAML コードで、以下の項目に注意してください。
initContainers
セクションが作成されています。initContainer
では、Azure CLI が既にインストールされているmicrosoft/azure-cli:latest
イメージが使用されます。- init コンテナーでは、Azure Files ボリュームからマウントされた /mnt/init/ フォルダーに格納されているスクリプトが実行されます。
- リソース グループ、コンテナー インスタンス名、サービス プリンシパル資格情報は、変数として渡されます。
- サービス プリンシパル シークレットは、セキュリティで保護された環境変数として渡されます。
- コンテナーの YAML 定義の残りの部分は、前のユニットから変更されていません。
次のコードを実行して YAML ファイルを作成します。
# Create YAML aci_subnet_id=$(az network vnet subnet show -n $aci_subnet_name --vnet-name $vnet_name -g $rg --query id -o tsv) aci_yaml_file=/tmp/acilab.yaml cat <<EOF > $aci_yaml_file apiVersion: '2023-05-01' location: $location name: $aci_name properties: subnetIds: - id: $aci_subnet_id initContainers: - name: azcli properties: image: mcr.microsoft.com/azure-cli:latest command: - "/bin/sh" - "-c" - "/mnt/init/$init_script_filename" environmentVariables: - name: RG value: $rg - name: SP_APPID value: $sp_appid - name: SP_PASSWORD secureValue: $sp_password - name: SP_TENANT value: $sp_tenant - name: DNS_ZONE_NAME value: $dns_zone_name - name: HOSTNAME value: $aci_name - name: ACI_NAME value: $aci_name volumeMounts: - name: initscript mountPath: /mnt/init/ containers: - name: nginx properties: image: nginx ports: - port: 443 protocol: TCP resources: requests: cpu: 1.0 memoryInGB: 1.5 volumeMounts: - name: nginx-config mountPath: /etc/nginx - name: sqlapi properties: image: erjosito/yadaapi:1.0 environmentVariables: - name: SQL_SERVER_FQDN value: $sql_server_fqdn - name: SQL_SERVER_USERNAME value: $sql_username - name: SQL_SERVER_PASSWORD secureValue: $sql_password ports: - port: 8080 protocol: TCP resources: requests: cpu: 1.0 memoryInGB: 1 volumeMounts: volumes: - secret: ssl.crt: "$ssl_crt" ssl.key: "$ssl_key" nginx.conf: "$nginx_conf" name: nginx-config - name: initscript azureFile: readOnly: false shareName: initscript storageAccountName: $storage_account_name storageAccountKey: $storage_account_key ipAddress: ports: - port: 443 protocol: TCP type: Private osType: Linux tags: null type: Microsoft.ContainerInstance/containerGroups EOF
生成された YAML ファイルを検証して、変数の置換が正しく機能したことを確認します。
# Check YAML file more $aci_yaml_file
コンテナー インスタンスを作成します。 アプリケーション コンテナーと NGINX コンテナーが開始される前に init コンテナーが実行されるため、これらのインスタンスの作成にはしばらく時間がかかります。
# Deploy ACI az container create -g $rg --file $aci_yaml_file
init コンテナーによって Azure プライベート DNS ゾーンに A レコードが作成されたことを確認します。
# Verify A records in the Azure Private DNS zone az network private-dns record-set a list -z $dns_zone_name -g $rg --query '[].{RecordName:name,IPv4Address:aRecords[0].ipv4Address}' -o table
SQL API エンドポイントを使用して、コンテナーに到達できることをテストします。 IP アドレスではなくドメイン名を使用してコンテナーにアクセスします。
# Test aci_fqdn=${aci_name}.${dns_zone_name} && echo $aci_fqdn ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "nslookup $aci_fqdn" ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_fqdn/api/healthcheck" ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_fqdn/api/sqlversion" ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_fqdn/api/sqlsrcip"
各コンテナーの個々のコンテナー インスタンス ログを検査できます。 たとえば、次のコードを実行して、init コンテナー ログにアクセスします。
# Init container logs az container logs -n $aci_name -g $rg --container-name azcli
課金が継続されないように、Azure リソース グループを削除して、このユニットとモジュール用に作成したすべてのリソースをクリーンアップします。
# Clean up module az group delete -n $rg -y --no-wait