Azure Container Instancesでアウトバウンド時のIPアドレスを固定する
日次で外部サービスにアクセスするプログラムをAzure Container Instances(ACI)を使って動かす際に、静的IPアドレスを固定する必要があり、ひと工夫したのでそれの備忘録。
以下のドキュメントにも記載のある通り、Azure FireWall( +ルートテーブル・パブリックIPアドレス)というサービスを利用し、ACIをデプロイしているサブネットから外へのルーティングをAzure Firewallに向けてあげることで、必ず静的IPアドレスを利用して外部にアクセスすることができます。
ただし、Azure Firewallはリソースを作っておくだけで1時間あたり140円ほどかかり、1ヶ月で見ると約10万程度かかってしまう。 azure.microsoft.com
今回ACIは毎日決まった時間に1回動かせればよく、Azure Firewallが必要な時間は1日1時間にも満たないので割りに合わず・・・。
そこで、Azure Automationを利用し、ACIを実行をさせる前後で、Azure Firewallのデプロイ・削除を行わせることで、お金をかけずに日次バッチ処理をさせることにしました。実行スケジュールもいい感じに設定できます。
Azure Automationでは、PowerShellなどを利用してAzureリソースの作成・実行・削除などの命令を行うことができます。 事前準備として、VNet・サブネット(ACI配置用とAzure Firewall配置用)・パブリックIPアドレス・ACI(サブネットに配置して)をドキュメントを参考に作成してください。
Azure AutomationのRunbookには以下の様なコードを記述します。
# 認証関連の設定 $connection = Get-AutomationConnection -Name AzureRunAsConnection$ErrorActionPreference = 'Stop' $logonAttempt = 0 while(!($connectionResult) -And ($logonAttempt -le 10)) { $LogonAttempt++ $connectionResult = Connect-AzAccount ` -ServicePrincipal ` -Tenant $connection.TenantID ` -ApplicationId $connection.ApplicationID ` -CertificateThumbprint $connection.CertificateThumbprint Start-Sleep -Seconds 30 } # Azure Firewallの作成 $Azfw = New-AzFirewall -ResourceGroupName <リソースグループ名> -Name testFW -Location "Japan East" -VirtualNetworkName <ACIとAzure Firewallが存在するVnet名> -PublicIpName <パブリックIPアドレス名> #Azure FirewallのプライベートIPアドレスを取得 $AzfwPrivateIP = $Azfw.IpConfigurations.privateipaddress # ルートテーブルを作成 $routeTableDG = New-AzRouteTable ` -ResourceGroupName <リソースグループ名> ` -Name Firewall-rt-table ` -location "Japan East" ` -DisableBgpRoutePropagation #ルートテーブルのルールを作成 Add-AzRouteConfig ` -Name DG-Route ` -RouteTable $routeTableDG ` -AddressPrefix 0.0.0.0/0 ` -NextHopType VirtualAppliance ` -NextHopIpAddress $AzfwPrivateIP ` | Set-AzRouteTable # ACIを配置しているサブネットの情報を取得 $networkProfile = Get-AzVirtualNetwork -ResourceGroupName <リソースグループ名> -Name <ACIとAzure Firewallが存在するVnet名> $subnetProfile = Get-AzVirtualNetwork -ResourceGroupName <リソースグループ名> -Name <ACIとAzure Firewallが存在するVnet名> | Get-AzVirtualNetworkSubnetConfig -Name <ACIを配置しているサブネット名> $delegation = Get-AzDelegation -Subnet $subnetProfile # ルートテーブルとサブネットの関連付け Set-AzVirtualNetworkSubnetConfig ` -VirtualNetwork $networkProfile ` -Name <ACIを配置しているサブネット名> ` -AddressPrefix 10.3.1.0/24 ` -Delegation $delegation ` -RouteTable $routeTableDG | Set-AzVirtualNetwork # Azure FirewallのSNATルールを作成 $AppRule1 = New-AzFirewallApplicationRule -Name Allow -SourceAddress <ACIを配置しているサブネットのアドレス空間> ` -Protocol http, https -TargetFqdn <接続先のFQDN> $AppRuleCollection = New-AzFirewallApplicationRuleCollection -Name App-Coll01 ` -Priority 200 -ActionType Allow -Rule $AppRule1 $Azfw.ApplicationRuleCollections.Add($AppRuleCollection) Set-AzFirewall -AzureFirewall $Azfw # ACI実行 Invoke-AzResourceAction -ResourceGroupName <リソースグループ名> -ResourceName <ACI名> -Action Start -ResourceType Microsoft.ContainerInstance/containerGroups -Force # ACI停止待ち while ($true) { Start-Sleep -Seconds 30 $resultContainerStatus = Get-AzContainerGroup -ResourceGroupName <リソースグループ名> -Name<ACI名> if(($resultContainerStatus.State -eq 'Failed') -Or ($resultContainerStatus.State -eq 'Succeeded')) { break } } # ACIサブネットとルートテーブルの関連付けを解除 Set-AzVirtualNetworkSubnetConfig ` -VirtualNetwork $networkProfile ` -Name <ACIを配置しているサブネット名> ` -AddressPrefix<ACIを配置しているサブネットのアドレス空間> ` -Delegation $delegation ` -RouteTable $null | Set-AzVirtualNetwork # ルートテーブル削除 Remove-AzRouteTable -ResourceGroupName <リソースグループ名> -Name Firewall-rt-table -Force # Azure Firewall削除 Remove-AzFirewall -ResourceGroupName <ACI名> -Name testFW -Force
Azure Automationの他に、Logic Appsという同じ様にAzureリソースの管理・スケジュール実行できるサービスがあり、こちらのほうが使いやすかったりしそうなのですが、 当時はAzure Firewallのデプロイができなさそうだったため、Automationを利用しました。(現時点では不明)