[アップデート] AppStream 2.0 で新しいタイプのフリート Elastic Fleets が追加されました

2021.11.21

しばたです。

先日Amazon AppStream 2.0で新しいタイプのフリートとなるElastic Fleetsが追加されたと発表されました。
AWSからのアナウンスはこちらです。

本記事ではこのElastic Fleetsについて解説していきます。

Elastic Fleets とは?

従来AppStream 2.0ではアプリケーションを公開するためにカスタマイズしたEC2イメージを作成し、このイメージに対する起動設定やスケーリング設定などをFleetという単位でまとめていました。
Fleetは起動されるEC2インスタンスの利用方法よって「Always-On (インスタンス起動時常時課金)」および「On-Demand (インスタンス使用時のみ課金)」の2種類存在します。

今回追加されたElastic Fleetsは全く新しい方式で、EC2イメージをカスタマイズするのではなく、公開したいアプリケーションをS3上に仮想ディスク(VHD)の形で定義・保存しEC2インスタンス起動時に仮想ディスクをマウントして公開するものとなります。
併せてスケーリング設定も簡素化され従来のFleetの様にApplication Auto Scalingによる設定は不要となりAWSに完全にお任せする形となっています。

前掲のアナウンスではOSイメージのカスタマイズを行わなわずスケーリングを完全にAWSに任せる"サーバーレス"な方式であると形容されています。

対象プラットフォーム

Elastic FleetsはWindows Server (Windows Server 2019イメージ)とAmazon Linux 2イメージの両方でサポートされています。
また、現時点ではインスタンスタイプは「General Purpose」の以下のタイプのみ利用可能となっています。

  • stream.standard.small (1vCPU, 2GiB memory)
  • stream.standard.medium (2vCPU, 4GiB memory)

こちらは将来的に利用可能なタイプが増えていくものと予想されます。  

App block と Application

Elastic FleetsではVHDを配備するS3やVHDマウント用のセットアップスクリプトを「App block」と呼ばれるリソースに登録します。
公開アプリケーションは「Application」リソースに登録し実体のあるApp blockと紐づける形となっています。

公開アプリケーションが独立したリソースになるため従来よりアプリケーションの再利用性が高まるのは非常に良い感じです。

価格

Elastic Fleetsの料金は料金ページに記載されています。

詳細は上記ページで確認していただきたいですが、本日(2021年11月21日)時点の東京リージョンでWindows Serverを使用する際の利用費をざっくり比較してみます。
インスタンスタイプは比較がしやすいstream.standard.medium(2vCPU, 4GiB memory)とStandard.medium(2vCPU, 4GiB memory)にしています。

Fleet種別 価格(利用中) 価格(利用外) 備考
Always-On 0.12 USD 0.12 USD 利用外も定額課金
On-Demand 0.12 USD 0.029 USD 利用外価格はインスタンスタイプに依らず定額
Elastic 0.18 USD - 利用中のみ課金

サーバーレスな方式のため単純な利用費は若干割り増しとなっています。

とはいえ、Elastic FleetsではImage Builderの利用が必須ではないのでその費用が掛からないのと、イメージづくりにかかる結構な工数(人件費) *1を減らすことができると考えればこの価格差は十分許容できるものと私は考えます。

こちらは何を重視するかでElastic Fleetsを採用するか判断すると良いでしょう。

やってみた

それでは早速試してみます。

私の検証アカウントの東京リージョンでVPCなどは予め準備済みの状態から始めていきます。

0. 事前準備 (S3)

事前準備としてVHDを保存するS3バケットを作成し、AppStream 2.0からのアクセスを許可する様にバケットポリシーを設定してください。

バケットポリシー設定例

{ 
  "Version": "2012-10-17",
  "Statement": [     
      { 
       "Sid": "AllowAppStream2.0ToRetrieveObjects", 
       "Effect": "Allow", 
       "Principal": { 
          "Service": ["appstream.amazonaws.com"]         
        },
        "Action": ["s3:GetObject"],
        "Resource": [           
           "arn:aws:s3:::bucket/VHD object",
           "arn:aws:s3:::bucket/Setup script object",
           "arn:aws:s3:::bucket/Application icon object"
         ]         
      }      
  ]
}

今回はelastic-fleets-sample-20211121という名前のバケットを作っています。

バケットポリシーは雑にS3全体へのアクセスを許可しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAppStream2.0ToRetrieveObjects",
            "Effect": "Allow",
            "Principal": {
                "Service": "appstream.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::elastic-fleets-sample-20211121/*"
        }
    ]
}

1. 事前準備 (VHD周り)

作成したS3バケットに保存するVHD、セットアップスクリプトを保存します。
今回はWindows Server環境向けにポータブル版のPowerShell 7を公開してみようと思います。

VHDを作るための環境は適切なものを作ることができるのであればどこでも構いません。
AWSのドキュメントではWindows Server向けでは任意のWindows Server 2019 EC2を使う前提となっており、Amazon Linux向けは丁度良いデスクトップ環境がないためImage Builderを使う前提となっています。

今回は本日時点で最新の日本語版Windows Server 2019 EC2環境を新規に用意しています。

1-1. VHDの作成

まずはアプリケーションを保存するVHD(.vhdx)を作成します。

ドキュメントによればdiskpartコマンドを対話的に実行してVHDを作成していますが、面倒なので以下のコマンドで一気に作ります。

実際の環境ではVHDを作るディレクトリとサイズは適当に調整してください。

# 要管理者権限
mkdir C:\temp\
cd C:\temp\

# Hyper-V moduleが無い環境もあるのでdiskpartコマンドでVHD(vhdx)作成を頑張る
try {
    $vhdPath = "C:\temp\app.vhdx"     # VHDファイルへの絶対パス
    $logPath = "C:\temp\diskpart.log" # diskpart実行ログ
    $vhdSize = 512 # VHDの最大サイズ (MB)
    $tempFileName = "create_vhd_$(Get-Date -Format "yyyyMMdd_HHmmss").txt"
@"
create vdisk file=$vhdPath maximum=$vhdSize type=expandable
select vdisk file=$vhdPath
attach vdisk
convert mbr
create partition primary
format fs=ntfs quick
detach vdisk
exit
"@ | Out-File ".\$tempFileName" -Encoding oem
    diskpart /s $tempFileName > $logPath
} finally {
    if (Test-Path -LiteralPath ".\$tempFileName") {
        Remove-Item -LiteralPath ".\$tempFileName"
    }
}

VHDファイル(app.vhdx)がエラー無く作成されていればOKです。

1-2. VHDのマウント

次にこのVHDファイルをマウントします。
マウントの仕方は何でも良いですが、今回はPowerShellから以下の様に行いZドライブにマウントします。

# VHDのマウント
$imagePath = 'C:\temp\app.vhdx'
$mountDrive = 'Z:\'
$vhdx = Mount-DiskImage -ImagePath $imagePath -StorageType VHDX -NoDriveLetter
Get-Disk -DeviceId $vhdx.Number | Get-Partition | Add-PartitionAccessPath -AccessPath $mountDrive

エラー無く処理が完了しExplorerからZドライブが見えてればOKです。

1-3. アプリケーションの配備

マウントしたZドライブにアプリケーションを配備します。
今回は以下のコマンドを実行してZ:\pwsh\フォルダにポータブル版のPowerShell 7.2を配置します。

# ポータブル版のPowerShell 7.2のダウンロードと解凍
$ProgressPreference = 'SilentlyContinue'
$params = @{
    Uri     = 'https://github.com/PowerShell/PowerShell/releases/download/v7.2.0/PowerShell-7.2.0-win-x64.zip'
    OutFile = 'Z:\pwsh.zip'
}
Invoke-WebRequest @params
Expand-Archive -LiteralPath Z:\pwsh.zip -DestinationPath Z:\pwsh
Remove-Item -LiteralPath Z:\pwsh.zip

配置した結果はこんな感じ。

配置と同時に動作確認もしておきます。

1-4. VHDのアンマウント

アプリケーションの配備が完了したらVHDをアンマウントします。
今回はPowerShellからDismount-DiskImageコマンドレットを実行してアンマウントします。

# VHDのアンマウント
Dismount-DiskImage -ImagePath 'C:\temp\app.vhdx'

これでVHDの準備は完了です。

1-5. セットアップスクリプト、アイコンファイルの準備

次にこのVHDファイルを利用するためのセットアップスクリプトを用意します。

Elastic Fleetsでは設定したApp blockのVHDファイルは利用インスタンスの

  • C:\AppStream\AppBlocks\<App block名>\<vhd名> (Windowsの場合)
  • /opt/appstream/AppBlocks/<App block名>/<vhd名> (Linuxの場合)

に展開されます。

このVHDファイルをFleet起動時にどう扱うかは完全にユーザーに委ねられておりマウント処理などはすべて自分で記述する必要があります。
これがApp blockにおける「セットアップスクリプト」となります。

今回はVHDファイルをZ:\ドライブにマウントする初期処理を書いたスクリプトをsetup.ps1として保存します。

setup.ps1

#
# This script is for AppStream 2.0 Elastic fleet
#

# mount vhdx file
$appBlockName = 'pwsh-win'
$appBlockVHDPath = "C:\AppStream\AppBlocks\$appBlockName\app.vhdx"
$mountDrive = 'Z:\'
$vhdx = Mount-DiskImage -ImagePath $appBlockVHDPath -StorageType VHDX -NoDriveLetter
Get-Disk -DeviceId $vhdx.Number | Get-Partition | Add-PartitionAccessPath -AccessPath $mountDrive

今回はマウント処理だけ記述していますが、アプリケーションの種類によってはその他必要に応じた初期処理を書いてやります。

加えて、公開アプリケーションのアイコン用の画像ファイルも必要となりますので用意しておきます。
今回はGitHubに公開されている以下のアイコン画像ファイルをapp-icon.pngとして保存します。

  • https://raw.githubusercontent.com/PowerShell/PowerShell/v7.2.0/assets/Square150x150Logo.png

1-6. S3へのアップロード

ここまでの手順で用意した

  • VHDファイル (app.vhdx)
  • セットアップスクリプト (setup.ps1)
  • アイコンファイル (app-icon.png)

をS3にアップロードします。

アップロードする先はAppStream 2.0のサービスがアクセス可能であればどこでも構いません。
今回はs3://elastic-fleets-sample-20211121/pwsh-win/配下に各ファイルをアップロードしました。

これで前準備はすべて完了です。

2. App block 設定

ここからAppStream 2.0側の設定に移ります。
マネジメントコンソールからAppStream 2.0の管理画面を開くと左ペインに「Applications」欄が増えていることがわかります。

この「Applications」を選択するとタブでApp blockとApplicationを選べる様になっています。

App blockを選択するとこんな感じの画面になりますので、「Create app block」ボタンをクリックして新規作成を開始します。

App blockの設定画面では「VHDのパス」「セットアップスクリプトの保存先」「セットアップスクリプトの実行方法」を記載します。

S3のリソース指定は実際のファイルのURIを指定してやればOKです。
セットアップスクリプトはVHDと同じディレクトリに配置されますので「Setup script executable」にpoewrshell.exeを指定し、その引数にsetup.ps1をフルパスで記載します。

作成されたApp blockはこんな感じになります。

3. Application 設定

App blockの次はApplicationを作成します。
マネジメントコンソールから「Create application」ボタンをクリックして新規作成を開始します。

ここでは公開アプリケーションの各種設定を行います。
アプリケーションアイコンには前節でアップロードしたS3のパスを指定します。

公開アプリケーションはVHDがマウントされた後のパス(今回の場合だとZ:\pwsh\pwsh.exe)を記載し、その他プラットフォーム情報を記述してやります。
App blockとの紐づけもここで行います。

作成結果はこんな感じになります。

4. Fleet 設定

これで公開アプリケーションの設定が完了したのでFleet作成に取り掛かれます。
マネジメントコンソールから「Create fleet」ボタンをクリックします。

Fleet作成のウィザードが開始され、新たに「Elastic」が増えていますのでこれを選択し次へ進みます。

Fleetの設定画面は従来のものより簡素であり、インスタンスタイプ、対象プラットフォーム、Viewの種類を決めるだけです。
今回は動作確認のために「Desktop View」としています。

次に公開アプリケーションの指定を行います。
前項までで作成したApplicationがリストアップされるのでチェックを付け選択します。

あとはVPC設定などを行います。ここは従来通りです。

あとはウィザードの内容に従いFleetを作成します。

Elastic Fleetの場合利用可能になるまでに少し時間がかかります。
利用可能なった結果は以下の様になります。

6. Stack 設定以後

のこりの作業であるStackの作成+Fleetとの紐づけ、ユーザー登録といった作業は従来のFleetと同じです。
環境に合わせてよしなに設定してください。

7. 動作確認

最後に作った環境に接続確認していきます。
今回はWindows Clientから接続します。

AppStream 2.0環境にログインするとApplicationで設定した内容が反映されています。

アプリケーションの起動はOn-Demandと同様か気持ち早い程度の体感です。
一応FAQによると1分以内の起動とのことです。(On-Demandは2分以内)

最終的に以下の様な感じで無事起動できました。

VHDをマウントしたZドライブはこんな感じで参照可能です。
ちなみにElastic Fleetsはインスタンス起動の都度S3からVHDをダウンロードする仕組みですのでこのドライブにデータを保存しても永続化されません。

追記 : VHDのマウントポイントはネットワークドライブに限らない

【2021年11月22日追記】

記事を公開したあとで「VHDのマウントポイントは別にZドライブで無くても構わないよな。」と気が付いてしまいました...
たとえばセットアップスクリプトを以下の様に組むとVHDファイルをC:\Program Files\PowerShell\7\フォルダにマウントします。

setup.ps1

#
# This script is for AppStream 2.0 Elastic fleet
#

# mount vhdx file
$appBlockName = 'pwsh-win'
$appBlockVHDPath = "C:\AppStream\AppBlocks\$appBlockName\app.vhdx"
$mountPoint = 'C:\Program Files\PowerShell\7\' # マウントポイントはネットワークドライブに限らない
if (-not (Test-Path -LiteralPath $mountPoint)) {
    mkdir $mountPoint
}
$vhdx = Mount-DiskImage -ImagePath $appBlockVHDPath -StorageType VHDX -NoDriveLetter
Get-Disk -DeviceId $vhdx.Number | Get-Partition | Add-PartitionAccessPath -AccessPath $mountPoint

このためApplication設定を以下の様により従来のアプリケーションを模した形にすることが可能です。

(VHDの作りかたを工夫すれば従来のインストールパスを完全再現することも可能)

【追記ここまで】

最後に

長くなりましたが以上となります。

リリースされたばかりの機能でドキュメントがまだ充実しておらず実際に動作確認しながら仕様を調べたせいで初回動作までに非常に手間がかかってしまいました...

この点については早急に改善してほしいと強く願います。

とはいえ一度やり方を把握してしまえばVHDをメンテナンスするだけでアプリケーションを更新することができ、従来にくらべ十分に運用を簡素化できそうだと感じました。
すべてのアプリケーションがポータブルなわけではないので適用対象を見極める必要はありますがElastic Fleetsで利用できそうなものであれば積極的に導入を検討していくと良いでしょう。

脚注

  1. 実際にAppStream 2.0やその他VDI全般を使ったことがある方ならわかっていただけると思います...