Automatisation de la construction d’image AppStream – partie 1 : nous n’aimons pas l’UI
Durant le confinement, nous avons eu de nombreuses demandes de nos clients pour implémenter Amazon AppStream.
Amazon AppStream 2.0 est un service managé qui permet de publier vos applications pour vos utilisateurs connectés à distance (similaire à Microsoft Remote Desktop Services, Citrix Virtual Apps, VMware Horizon or Nutanix Frame). Depuis début août 2020, AppStream permet également de publier un bureau complet pour les utilisateurs. AppStream étant un service managé, il n’y a pas d’infrastructure à gérer, seulement les images serveur AppStream.
Laurent Mas et moi-même avons donc relevé le challenge d’automatiser le processus de construction d’image AppStream, avec pour objectif de ne pas avoir à se connecter à l’image builder.
Automate everything
Voici les avantages d’automatiser la construction d’image AppStream :
- Processus de construction d’image immuable
- Facilité de mise à jour avec le patching Microsoft ou les mises à jour de l’agent AppStream
- Possibilité d’intégration dans un pipeline CI/CD
Quelques précisions avant d’entrer dans le détail de l’implémentation :
- Toutes les instances AppStream ont deux ENI (Elastic Network Interface) : une dans votre VPC et une dans le VPC géré par AWS. Ceci peut avoir son importance lors du dimensionnement de vos sous-réseaux.
- Il est possible de lier des instances AppStream à un domaine Active Directory y compris l’image builder
- Le provider AWS pour Terraform ne supporte pas Amazon AppStream
Nos outils :
- Terraform/CloudFormation
- Powershell et WinRM
- Chocolatey (https://chocolatey.org/)
Ici, nous avons déployé l’automatisation sur une instance Windows EC2, étant donné que nous allions utiliser WinRM pour échanger avec l’image builder AppStream.
Il existe déjà de la documentation sur le sujet sur le blog AWS (ici), mais la première étape décrite dans l’article est manuelle : se connecter à l’image builder AppStream depuis la console AWS !
AppStream image builder et AD
Sur l’image builder AppStream, nous n’avons pas de donnée utilisateur pour bootstrapper notre instance et il n’y a pas pas d’API pour récupérer un accès administrateur local donc… la seule solution était de joindre l’image builder AppStream à un domaine Active Directory dans une OU (Organizational unit) spécifique, avec une GPO pour configurer WinRM.
Par chance, la configuration de l’AD AppStream est possible avec CloudFormation et nous avions déjà un code Terraform pour déployer rapidement un AD managé dans AWS Directory Service et configurer les options DHCP.
Note : vous n’avez pas besoin d’un AD AWS complet. Vous pourriez simplement faire tourner un seul contrôleur de domaine Windows sur une EC2 pour les besoins de l’image builder. Les instances AppStream créées de cette image n’ont pas nécessairement à être jointes à un domaine AD si vous ne le souhaitez pas.
Depuis notre EC2 Windows, nous pouvons maintenant instancier un image builder avec l’image Windows Server 2019 la plus récente, et le joindre à notre domaine AD. Voici le code pour illustrer comment choisir l’OS de départ et créer l’instance image builder :
$aws_image = Get-APSImageList | where-object {($_.Name).StartsWith("AppStream-WinServer2019")} | sort CreatedTime | select -last 1
WriteLog "Latest Windows Server 2019 appstream image: $($aws_image.Name)" $LoggingFile 3 "full" "AppStreamImage"
WriteLog "Creating a new image builder: $target_image_name" $LoggingFile 0 "full" "AppStreamImage"
$new_image = New-APSImageBuilder -InstanceType $image_builder_instance_type `
-Name $target_image_name `
-DisplayName $target_image_name `
-ImageName $aws_image.Name `
-EnableDefaultInternetAccess $enable_internet `
-VpcConfig_SubnetId $subnet_id `
-VpcConfig_SecurityGroupIds $security_group_id `
-Region $region `
-DomainJoinInfo_DirectoryName $AD `
-DomainJoinInfo_OrganizationalUnitDistinguishedName $image_OU `
-IamRoleArn $appstream_role_arn
Il faut quelques minutes pour préparer l’image builder, puis vous pouvez la démarrer.
WriteLog "Starting the image builder: $target_image_name" $LoggingFile 3 "full" "AppStreamImage"
Start-APSImageBuilder -name $target_image_name
Après quelques minutes, nous pouvons récupérer l’adresse IP de l’ENI tournant dans notre VPC pour cet image builder en particulier :
# list ENI and find the one for our image builder
$new_image = Get-APSImageBuilderList -name $target_image_name
$ip_address = $new_image.NetworkAccessConfiguration.EniPrivateIpAddress
WriteLog "Image builder $target_image_name has IP address $ip_address" $LoggingFile 3 "full" "AppStreamImage"
Configurer WinRM
Dans l’Active Directory, nous avons configuré un script de lancement dans une GPO pour configurer WinRM et également la configuration d’un compte d’administrateur local de l’image builder.
A partir de là, nous n’avons plus qu’à utiliser Invoke-Command ou une commande similaire pour installer nos applications et configurer notre image en utilisant notre compte de service AD. Vous devez utiliser l’Image Assistant pour faire connaître au service AppStream vos applications publiées. Nous verrons ce point plus en détail dans un deuxième article.
Pour créer l’image, depuis l’image builder dans la session WinRM (Invoke-Command), vous devez invoquer l’exécutable Image Assistant et lui donner l’instruction de création d’image avec un nom choisi.
$exePath = "C:\Program Files\Amazon\Photon\ConsoleImageBuilder"
Set-Location $exePath
Write-Output "Creating snapshot for image builder $IBName"
$CreateCMD = '.\image-assistant.exe create-image --name ' + $ImageName
$Create = Invoke-Expression $CreateCMD | ConvertFrom-Json
if ($Create.status -eq 0) {
Write-Output "Successfully started creating image $ImageName"
} else {
Write-Output "ERROR creating Image $ImageName"
Write-Output "$Create.message"
}
Après avoir lancé la création d’image, l’instance image builder s’éteindra automatiquement et vous pourrez supprimer l’image builder.
while ((Get-APSImageBuilderList -name $target_image_name).State -ne "STOPPED"){
WriteLog "Waiting for image $target_image_name to be snapshot, sleeping for $retry_time seconds..." $LoggingFile 6 "verbose" "AppStreamImage"
Start-Sleep -s $retry_time
}
WriteLog "Removing the image builder: $target_image_name" $LoggingFile 3 "full" "AppStreamImage"
Remove-APSImageBuilder -name $target_image_name -Force
Notez que nous pouvons supprimer l’image builder parce que nous avons automatisé la totalité du processus, y compris l’installation des applications. Si vous installez les applications manuellement, alors vous aurez besoin de garder cette image pour une future mise à jour.
Merci à Mathieu Dalbes pour les heures passées à tester et à débugger à nos côtés !
Références :