この記事はUnreal Engine (UE) Advent Calendar 2024 のシリーズ1、12月16日分に向けて書いたものです。
UEのプロジェクトの開発を進めるにあたり、パッケージングは時間がかかる上にたくさんのエラーログの調査に時間が食われる事この上ないため、 定期的にパッケージングをして問題をこまめに潰しておく事はとても大切です。
高性能PCを組んでJenkins環境を構築したり、職場の多数のPCで分散ビルドを行う事例も見られますが、 パッケージの数が多くなるとビルド時間が長期化したり、多数のPCを扱うとPC故障の対応に追われるリスクも上がるため AWSやAzure等のクラウド環境に構築する流れが主流になりつつあるようです。 クラウドでビルドするメリットは必要なビルド環境を必要な分だけ確保する事ができ、使った分だけの料金がかかる事にあるため、 構築時の敷居の高さが解消すれば個人や小規模の現場にも広がる可能性を秘めています。
UEのクラウドビルド環境のシステム構成に関する情報も、徐々に公開されるようになっており、とてもありがたい限りです。
特にこのパルワールドのポケットペアさんの講演は、Subversionチェックアウトに1時間かかるような肥大化したプロジェクトでも高速にビルド環境の構築が可能となり、 個人的に衝撃を受けてのたうち回っていました。
本稿ではその環境構築をやってみる系の途中経過の話になります。まだ課題がある状況のため「やってみた」に到達していない点につきましては先に平謝りいたします。
Jenkins Controller を AWS に構築する
何はともあれJenkins ControllerをAWSに立てない事には始まりません。 CDKソースをhttps://github.com/tomotaco/cdk-ec2-jenkins に置いておきますので、さくっと git clone で取得して cdk deploy して下さい。
deployに成功すると、Public IP アドレスが表示されるので、ブラウザからhttp://[PublicIPAddress]:8080
を開きます。
初期管理パスワードを入力する画面が表示されますが、AWSのEC2コンソールからSystemManager経由でログインするか、 下記のようにssh接続で初期管理パスワードが書かれたファイルの内容を確認の上、入力して下さい。
$ ssh ec2-user@[PublicIPAddress] -i [YourKeyPair] sudo cat /var/lib/jenkins/secrets/initialAdminPassword
EC2 AmazonLinux2023インスタンスにJenkinsとRedis stackをインストールした構成になっています。 Redis stackはEBSのSnapshotID等の状態を保存する用途に使用します。 Jenkinsの状態(ジョブやプラグイン等のデータ)を保存するJENKINS_HOMEディレクトリと、Redi stackのデータディレクトリは AmazonLinuxとは別のEBS Volume(Persistent volume)に保存し、インスタンスの終了(削除)時に削除しない設定にしています。
何らかの理由でインスタンスを再構築する場合は、このPersistent Volumeを下記コマンドでSnapshot化しておきます。
$ aws --profile [YourAWSProfile] ec2 create-snapshot --volume-id [VolumeID] --description "Jenkins Persistent snapshot" --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=jenkins-persistent-snapshot}]'
SnapshotIDが表示されるのでこれを指定して cdk deploy を実行します。 これで再構築前のジョブやプラグイン・SnapshotID等が復元された状態でJenkinsインスタンスが再構築されます。
$ AWS_PROFILE=[YourAWSProfile] cdk deploy -c jenkinsPersistentSnapshotId=[SnapshotID]
パルワールドの講演では ECSonEC2 にJenkinsを構築していますが、これはJenkinsのDocker imageをそのまま使用するためではないかと推測しています。 また、Jenkinsの状態をファイルサーバ(Amazon FSx for NetApp ONTAP)に保存するようにしていますが、 下記記事によると最低容量が1TBかららしいので、DDCの共有に使用する目的がない限り 個人で使うのはちょっと敷居が高いのでは…と思っていったん手を出していません。
Jenkins Agent を AWS に構築する
JekinsにはEC2インスタンスを立てて分散ビルドのAgentとして使用するプラグインがあります。
- ec2-plugin (https://github.com/jenkinsci/ec2-plugin)
- ec2-fleet-plugin (https://github.com/jenkinsci/ec2-fleet-plugin)
本稿では前者の ec2-plugin を導入してみました。
WindowsServerのAgent につながらない
WindowsServerインスタンスをAgentとして使用する例としては下記記事が見つかります。
こちら参考に構築してもWinRMで疎通できませんでした。 下記LinuxのPowerShell7から接続してみると、WSmanがないと言われてしまいます。
PS /home/ec2-user> Enter-PSSession -ComputerName [AgentIPAddress] -Credential [AdminAccountName]
PowerShell credential request
Enter your credentials.
Password for user [AdminAccountName]: ***************
Enter-PSSession: This parameter set requires WSMan, and no supported WSMan client library was found. WSMan is either not installed or unavailable for this system.
MicrosoftのリファレンスPowerShell での WS-Management (WSMan) を使用したリモート処理 によると、LinuxではWSManに対応していないため、SSH接続を使えとあります。
先の【CI奮闘記】第7章:Amazon EC2のWindows ServerをJenkinsのエージェントとして利用する!についても、 連載を遡ってみると分かりますが、Jenkins ControllerにWindowsServerインスタンスを使用しています。(もはや、せやな…としか言いようがない)
WindowsServer2022にSSH接続できるようにする
しょうがないのでWindowsServer2022インスタンスを構築する時にsshで接続できるように細工しました。 具体的には、ec2-pluginの設定にUserDataスクリプトを指定し、インスタンス構築時に流し込んでもらいます。
WindowsServerへのOpenSSHのインストール方法は下記クラスメソッドさんの記事を参考にさせて頂きました。
インストール後してsshdを起動した後、公開鍵あり・パスワードなしログインを可能にするため下記設定を行い、sshdを再起動します。
- S3から公開鍵ファイルを取得し、
C:\ProgramData\ssh\administrators_authorized_keys
に保存 - 上記公開鍵ファイルの権限をAdministratorsのみにフルコントロールを許可するよう設定
C:\ProgramData\ssh\sshd_config
に公開鍵認証あり・パスワード認証なしの設定を追加
# Install OpenSSH Server
Write-Output "Install OpenSSH server"
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Set-Service -Name sshd -StartupType Automatic
Start-Service sshd
# Copy ssh rsa Key
Write-Output "Copy ssh rsa key"
$PREREQ_PREFIX="[KeyPrefixForAuthorizedKeys]"
$RSA_PUB_KEY = "[AuthorizedKeysForYourKeyPair]"
$RSA_PUB_KEY_FILE="C:\ProgramData\ssh\administrators_authorized_keys"
$SSHD_CONFIG_FILE="C:\ProgramData\ssh\sshd_config"
Write-Output "Retrieve from S3: $RSA_PUB_KEY"
Read-S3Object -BucketName [YourBucketName] -Region ap-northeast-1 -Key $PREREQ_PREFIX/$RSA_PUB_KEY -File $RSA_PUB_KEY_FILE
# Set premission to ssh rsa key
Write-Output "Set premission to ssh rsa key"
$NewAcl = Get-Acl -Path "$RSA_PUB_KEY_FILE"
# Prohibit inheritance
$NewAcl.SetAccessRuleProtection($true, $false)
# Create new rule
$fileSystemAccessRuleArgumentList = "BUILTIN\Administrators", "FullControl", "Allow"
$fileSystemAccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $fileSystemAccessRuleArgumentList
# Apply new rule
$NewAcl.SetAccessRule($fileSystemAccessRule)
Set-Acl -Path "$RSA_PUB_KEY_FILE" -AclObject $NewAcl
sleep 10
# Change auth mode
echo "" >> $SSHD_CONFIG_FILE
echo "PubkeyAuthentication yes" >> $SSHD_CONFIG_FILE
echo "PasswordAuthentication no" >> $SSHD_CONFIG_FILE
Restart-Service sshd
さらに、WindowsServer2022に標準で入っているWindows PowerShell5.1ではSSH接続に不具合が出るため、 PowerShell6以降をPSRemotingオプションを有効にしてインストールし、OpenSSHのデフォルトシェルに設定しておく必要があります。 PowerShellのパッケージはchocolateyを使ってインストールしています。(理由は後述しますが、ec2-plugin側と合わせるためです)
# install PowerShell7
choco install powershell-core
# Set PowerShell7 to default shell
Write-Output "Set PowerShell7 to default shell"
$PWSH_PATH="C:\Program Files\PowerShell\7\pwsh.exe"
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "$PWSH_PATH" -PropertyType String -Force
ec2-plugin で Windows Agentに SSH で接続できるようにする
ec2-pluginのWindowsインスタンス接続処理はWinRMしか対応していないため、そのままでは接続する事ができません。 幸い、ec2-plugin リポジトリにWindowsAgent にSSH接続する pull requestが投稿されています。
残念ながらレビュー不足のため取り込まれていないため、今回はリポジトリをcloneして手元でマージを行いました。 こちらに置いてあります。
Javaの実行環境(バージョンは11・17・21のいずれか)と、Apacke mavenがインストトールされている環境なら下記コマンドでビルドできます。
$ mvn package
この pull request を適用したec2-pluginは、ssh接続の疎通に成功すると chocolatey と使ってJavaの実行環境(temurin17)をインストールするため、 あらかじめUserDataスクリプト側でchocolateyをインストールしておく必要があります。
ただ、試した所、UserData側のchocolateyと、ssh疎通後に実行されるchocolateyとが競合する現象が確認されたため、UserDataスクリプト側で先にtemurin17をインストールしておく必要がありました。
# Install chocolatey
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Conifigure chocolatey to install packages with -y option.
choco feature enable -n allowGlobalConfirmation
#install OpenJDK17
choco install temurin17
UserData スクリプトの完全版を下記場所に置いておきます。
Agentの起動に成功すると、下記のようなログが出力されます。
:
Dec 13, 2024 12:10:01 PM hudson.plugins.ec2.EC2Cloud
INFO: connect fresh as root
Dec 13, 2024 12:10:01 PM hudson.plugins.ec2.EC2Cloud
INFO: Connecting to 172.31.40.241 on port 22, with timeout 10000.
Dec 13, 2024 12:10:01 PM hudson.plugins.ec2.EC2Cloud
INFO: Connection allowed after the host key has been verified
Dec 13, 2024 12:10:01 PM hudson.plugins.ec2.EC2Cloud
INFO: Connected via SSH.
Dec 13, 2024 12:10:01 PM hudson.plugins.ec2.EC2Cloud
INFO: Creating tmp directory (c:\windows\Temp) if it does not exist
A subdirectory or file c:\windows\Temp already exists.
Error occurred while processing: c:\windows\Temp.
Dec 13, 2024 12:10:01 PM hudson.plugins.ec2.EC2Cloud
INFO: Verifying: java -fullversion
openjdk full version "17.0.13+11"
Dec 13, 2024 12:10:02 PM hudson.plugins.ec2.EC2Cloud
INFO: Copying remoting.jar to: c:\windows\Temp
Dec 13, 2024 12:10:02 PM hudson.plugins.ec2.EC2Cloud
INFO: Launching remoting agent (via Trilead SSH2 Connection): java -jar c:\windows\Temp/remoting.jar -workDir c:\JenkinsAgent
<===[JENKINS REMOTING CAPACITY]===>Remoting version: 3248.3250.v3277a_8e88c9b_
Launcher: EC2WindowsSSHLauncher
Communication Protocol: Standard in/out
This is a Windows agent
Agent successfully connected and online
VisualStudio2022 AMI で起動するとssh接続が切れる
これで一安心…と思いきやそうは問屋が下しません。 WindowsServer2022 の AMI で起動した時はsshの疎通が完了しAgentとして使用できるようになりますが、 UEのビルドにはVisualStudio2022が必要です。
EC2インスタンス上でVisualStudio2022を使用するにはライセンスの制限からVisualStudio2022AMIからの起動が必要となります。 詳しい手順はクラスメソッドさんの記事をご覧下さい。
- Microsoft Visual Studioライセンスが含まれたAMIがリリースされました。EC2上でVisual Studioを使いやすくなりました
- Visual Studio入りAMIが使える様になった件をライセンス面から調査してみた
- [2024年12月版] 新しいRemote Desktop Service SALを使ってVisual Studio AMIを試してみた
VisualStudio2022 AMI から起動したインスタンスではライセンス管理にActiveDirectoryが使用されており、 AWSLicenseManagerからのSystemManager経由でドメイン参加の処理が走り、その際にいったん再起動が行われます。
ec2-pluginでJenkinsAgentとの接続している状態では…ssh接続が切れると…インスタンス終了(削除)が走ってしまい、 今のところSSHの再接続をする方法がありません。ec2-pluginをいじろうにも、SSH接続して標準入出力で制御する大元の構造を修正する必要がありそうで修正規模が大きくなりそうです。
まとめ
ということでまだ検証の途中のためいったん時間切れとなります。今のところ今後の予定としては、
- 素のVisualStudio2022AMIから起動せず、ドメイン参加が完了した状態でsysprep→AMIを作成してそこから起動してみる
- 余力が有り余っていれば ec2-plugin をいじる
ひとまずは上記の2つを試してみたいと思います。