AWS Deadline Cloudがリリースされてからしばらく経ちましたが、皆さま使われていますか?
弊社ではCMFを使用して構築・運用を行っています。AWS Dead CloudはSMFの場合比較的簡単に構築ができますが、CMFを使用すると一気にハードルが上がります。
本記事ではHoudiniをインストールしたLinuxワーカーのフリートを例にして紹介します。
フリートとは
ジョブを実行するサーバーのことをワーカーと呼びます。ここは従来のDeadlineと同じです。
AWS Deadline Cloudでは、このワーカーの集まりのことをフリートと呼び、フリートに対して自動スケーリングの設定等を行います。
SMFではAWSが提供するセットアップ済みのワーカーを使用します。またイベントベース自動スケーリングの設定もフリート設定時に自動で構築されるため、非常にお手軽に構築が可能です。
一方で、SMFでは基本的にユーザーがワーカーをカスタマイズすることはできません。
また利用できるソフトウェアに制限があり、デフォルトでは特定のソフトウェアの特定のバージョンでのみ利用可能です。
要するに、ワーカーに関して詳細な制御を行いたい場合はCMFを使用せよということです。
またCMFの場合は、AWSクラウド外(オンプレミス、他クラウド)にワーカーをセットアップすることも可能ですが、本記事ではAWSクラウド上への構築に絞って話を進めます。
カスタムのCondaPackageを作成して使用することでSMFをカスタマイズすることも可能みたいです。こちらも気になるところですが、この記事ではCMFにフォーカスします
https://aws.amazon.com/jp/blogs/media/create-a-conda-package-and-channel-for-aws-deadline-cloud/
CMF(customer-managed fleet)で必要になる追加の作業
CMFの場合はSMFと比べて以下の作業が必要になります。
- DeadlineCloudワーカーエージェントのインストール
- ジョブ用のソフトウェアのインストール
- ライセンスエンドポイントの設定
- AMIの作成
- オートスケーリンググループの構築
各作業については公式ドキュメントにも記載がありますが結構大変です。。
https://docs.aws.amazon.com/ja_jp/deadline-cloud/latest/userguide/manage-cmf.html
本記事ではCMFの構築を簡単にするため、
- EC2 Image Builderによってワーカー構築作業をコード管理する
- CMF 構築一式をCloudFormationによってコード管理する
の2つを紹介します。
EC2 Image Builderによってワーカー構築作業をコード管理する
Image Builderを使用してDeadlineCloudワーカーエージェント、各ソフトウェアがインストールされたマシンイメージを構築します。
Image BuilderについてはこちらのClassmethodの記事がわかりやすいです。
https://dev.classmethod.jp/articles/ec2-image-builder-primer/
DeadlineCloudWorkerAgentのインストールコンポーネント
コンポーネント定義
name: InstallDeadlineCloudWorkerAgent
description: Install Deadline Cloud Worker Agent on Amazon Linux 2023
schemaVersion: 1.0
parameters:
- FarmId:
type: string
default: ''
description: The Deadline Cloud Farm ID
- FleetId:
type: string
default: ''
description: The Deadline Cloud Fleet ID
phases:
- name: build
steps:
- name: CreateAndConfigurePythonVenv
action: ExecuteBash
inputs:
commands:
- python3 -m venv /opt/deadline/worker
- source /opt/deadline/worker/bin/activate
- pip install --upgrade pip
- name: InstallDeadlineCloudWorkerAgent
action: ExecuteBash
inputs:
commands:
- source /opt/deadline/worker/bin/activate
- python -m pip install deadline-cloud-worker-agent
- name: ConfigureDeadlineCloudWorkerAgent
action: ExecuteBash
inputs:
commands:
- /opt/deadline/worker/bin/install-deadline-worker --farm-id '{{ FarmId }}' --fleet-id '{{ FleetId }}' --allow-shutdown -y
- name: PrepareDeadlineCloudWorkerAgent
action: ExecuteBash
inputs:
commands:
- systemctl stop deadline-worker
- systemctl enable deadline-worker
- rm -rf /var/lib/deadline/*
- rm -rf /var/log/amazon/deadline/*
- name: verify
steps:
- name: CheckDeadlineWorkerStatus
action: ExecuteBash
inputs:
commands:
- systemctl status deadline-worker
Houdiniのインストールコンポーネント
コンポーネント定義
name: InstallHoudini
description: Install Houdini on Amazon Linux 2023 using EC2 Image Builder
schemaVersion: 1.0
parameters:
- HoudiniVersion:
type: string
description: Houdini Version
- EULA:
type: string
description: Date of EULA
- InstallerBucket:
type: string
phases:
- name: build
steps:
- name: InstallDependencies
action: ExecuteBash
inputs:
commands:
- dnf install mesa-libGLU libXcursor libXScrnSaver -y
- name: InstallHoudini
action: ExecuteBash
inputs:
commands:
- aws s3 cp s3://{{ InstallerBucket }}/houdini-py39-{{ HoudiniVersion }}-linux_x86_64_gcc11.2.tar.gz .
- tar -xvf houdini-py39-{{ HoudiniVersion }}-linux_x86_64_gcc11.2.tar.gz
- ./houdini-py39-{{ HoudiniVersion }}-linux_x86_64_gcc11.2/houdini.install --accept-EULA {{ EULA }} --auto-install --install-houdini --install-bin-symlink --no-install-license --no-install-menus --install-hfs-symlink
- name: InstallDeadlineCloudForHoudini
action: ExecuteBash
inputs:
commands:
- dnf install python3-pip -y
- pip3 install deadline deadline-cloud-for-houdini
- name: IncreaseMaxStackSize
action: ExecuteBash
inputs:
commands:
- echo " * soft stack 50000" >> /etc/security/limits.conf
- echo " * hard stack 50000" >> /etc/security/limits.conf
- name: Reboot
action: Reboot
inputs:
delaySeconds: 60
- name: verify
steps:
- name: VerifyHoudiniInstall
action: ExecuteBash
inputs:
commands:
- houdini --version
- hython -c "exit()"
イメージレシピの定義
作成した各コンポーネントを関連付けたイメージレシピを作成し、各コンポーネントのパラメーターを設定してマシンイメージの構築を行います。
このようにイメージビルダーによってワーカーイメージの構築を行うことで、各ファーム、フリートに関連付けられたワーカーエージェントのインストールが行えます。
またインストールするソフトウェアのバージョンをコンポーネント定義のパラメータとして持たせることで、別のバージョンのソフトウェアをインストールする際にイメージレシピを編集するだけで簡単にワーカーのセットアップが可能になります。
Cloud Formationによるコード管理
上記のImage Builderの設定等を含めて、Deadline Cloudの構築をCloud Formationによって自動化します。
Cloud Formationによって管理する際にテンプレートを以下の2つに分割しています。
- farm.yaml
- queue.yaml
FarmとQueueでテンプレートを分割する理由は、一つのファームに対して複数のキューを作成したいためです。
具体的には開発、本番などの環境ごとでファームを分け、プロジェクトごとでキューを分ける形が良いと思います。
具体的には以下のような構造になります。
- development-farm
- project-a-development-queue
- project-b-development-queue
- production-farm
- project-a-production-queue
- project-b-production-queue
farm.yaml
Farm、ネットワークの構築を行います。Environmentパラメーターによって開発、本番環境を指定するようにします
Cloud Formationテンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Deploy AWS Deadline Cloud Farm Resources
Parameters:
Environment:
Type: String
AllowedValues:
- development
- production
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.0.0.0/16
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.0.10.0/24
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 10.0.11.0/24
Mappings:
EnvironmentMap:
development:
DisplayName: Development
Tag: Dev
production:
DisplayName: Production
Tag: Prod
RegionMap:
us-east-1:
AZs:
- us-east-1a
- us-east-1b
- us-east-1c
us-west-2:
AZs:
- us-west-2a
- us-west-2b
- us-west-2c
ap-northeast-1:
AZs:
- ap-northeast-1a
- ap-northeast-1c
- ap-northeast-1d
Resources:
Farm:
Type: AWS::Deadline::Farm
Properties:
DisplayName: !Sub
- DeadlineCloud ${EnvDisplayName} Farm
- EnvDisplayName: !FindInMap
- EnvironmentMap
- !Ref Environment
- DisplayName
############################################################
# Network
############################################################
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub deadline-cloud-${Environment}-vpc
- Key: Environment
Value: !Ref Environment
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub deadline-cloud-${Environment}-igw
- Key: Environment
Value: !Ref Environment
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref IGW
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnet1CIDR
AvailabilityZone: !Select
- 0
- !FindInMap
- RegionMap
- !Ref AWS::Region
- AZs
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub deadline-cloud-${Environment}-worker-public-subnet-a
- Key: Environment
Value: !Ref Environment
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnet2CIDR
MapPublicIpOnLaunch: true
AvailabilityZone: !Select
- 1
- !FindInMap
- RegionMap
- !Ref AWS::Region
- AZs
Tags:
- Key: Name
Value: !Sub deadline-cloud-${Environment}-worker-public-subnet-c
- Key: Environment
Value: !Ref Environment
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
WorkerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security Group created for deadline workers
GroupName: WorkerSecurityGroup
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 22
ToPort: 22
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
VpcId: !Ref VPC
############################################################
# EC2 Image Builder Components
############################################################
SoftwareInstallerBucket:
Type: AWS::S3::Bucket
WorkerAgentBuildComponent:
Type: AWS::ImageBuilder::Component
Properties:
Data: |
name: InstallDeadlineCloudWorkerAgent
description: Install Deadline Cloud Worker Agent on Amazon Linux 2023
schemaVersion: 1.0
parameters:
- FarmId:
type: string
default: ''
description: The Deadline Cloud Farm ID
- FleetId:
type: string
default: ''
description: The Deadline Cloud Fleet ID
phases:
- name: build
steps:
- name: CreateAndConfigurePythonVenv
action: ExecuteBash
inputs:
commands:
- python3 -m venv /opt/deadline/worker
- source /opt/deadline/worker/bin/activate
- pip install --upgrade pip
- name: InstallDeadlineCloudWorkerAgent
action: ExecuteBash
inputs:
commands:
- source /opt/deadline/worker/bin/activate
- python -m pip install deadline-cloud-worker-agent
- name: ConfigureDeadlineCloudWorkerAgent
action: ExecuteBash
inputs:
commands:
- /opt/deadline/worker/bin/install-deadline-worker --farm-id '{{ FarmId }}' --fleet-id '{{ FleetId }}' --allow-shutdown -y
- name: PrepareDeadlineCloudWorkerAgent
action: ExecuteBash
inputs:
commands:
- systemctl stop deadline-worker
- systemctl enable deadline-worker
- rm -rf /var/lib/deadline/*
- rm -rf /var/log/amazon/deadline/*
- name: verify
steps:
- name: CheckDeadlineWorkerStatus
action: ExecuteBash
inputs:
commands:
- systemctl status deadline-worker
Name: !Sub deadline-cloud-worker-agent-${Environment}-build
Platform: Linux
SupportedOsVersions:
- Amazon Linux 2023
Version: 1.0.1
HoudiniBuildComponent:
Type: AWS::ImageBuilder::Component
Properties:
Data:
Fn::Sub:
- |
name: InstallHoudini
description: Install Houdini on Amazon Linux 2023 using EC2 Image Builder
schemaVersion: 1.0
parameters:
- HoudiniVersion:
type: string
description: Houdini Version
- EULA:
type: string
description: Date of EULA
phases:
- name: build
steps:
- name: InstallDependencies
action: ExecuteBash
inputs:
commands:
- |
dnf install -y alsa-lib \
openssl \
dbus-libs \
expat \
fontconfig \
glibc \
libatomic \
libevent \
libglvnd-glx \
libglvnd-opengl \
libICE \
libSM \
libX11 \
libX11-xcb \
libxcb \
libXcomposite \
libXcursor \
libXdamage \
libXext \
libXfixes \
libXi \
libxkbcommon \
libxkbcommon-x11 \
libXrandr \
libXrender \
libXScrnSaver \
libXt \
libXtst \
libzstd \
nspr \
nss \
nss-util \
openldap \
pciutils-libs \
tbb \
xcb-util \
xcb-util-image \
xcb-util-keysyms \
xcb-util-renderutil \
xcb-util-wm \
zlib
- name: InstallHoudini
action: ExecuteBash
inputs:
commands:
- aws s3 cp s3://${InstallerBucket}/houdini-py39-{{ HoudiniVersion }}-linux_x86_64_gcc11.2.tar.gz .
- tar -xvf houdini-py39-{{ HoudiniVersion }}-linux_x86_64_gcc11.2.tar.gz
- ./houdini-py39-{{ HoudiniVersion }}-linux_x86_64_gcc11.2/houdini.install --accept-EULA {{ EULA }} --auto-install --install-houdini --install-bin-symlink --no-install-license --no-install-menus --install-hfs-symlink
- name: InstallDeadlineCloudForHoudini
action: ExecuteBash
inputs:
commands:
- dnf install python3-pip -y
- pip3 install deadline deadline-cloud-for-houdini
- name: IncreaseMaxStackSize
action: ExecuteBash
inputs:
commands:
- echo " * soft stack 50000" >> /etc/security/limits.conf
- echo " * hard stack 50000" >> /etc/security/limits.conf
- name: LoginAsRoot
action: ExecuteBash
inputs:
commands:
- sudo su
- name: verify
steps:
- name: VerifyHoudiniInstall
action: ExecuteBash
inputs:
commands:
- houdini --version
- hython -c "exit()"
- InstallerBucket: !Ref SoftwareInstallerBucket
Name: !Sub houdini-${Environment}-build
Platform: Linux
SupportedOsVersions:
- Amazon Linux 2023
Version: 1.0.4
ImageBuilderLogBucket:
Type: AWS::S3::Bucket
Properties:
LifecycleConfiguration:
Rules:
- Id: AutoDelete
Status: Enabled
ExpirationInDays: 14
ImageBuilderEC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: LogBucketAccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:List*
Resource:
- '*'
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${ImageBuilderLogBucket}
- !Sub arn:aws:s3:::${ImageBuilderLogBucket}/*
- PolicyName: InstallerBucketAccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${SoftwareInstallerBucket}
- !Sub arn:aws:s3:::${SoftwareInstallerBucket}/*
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/EC2InstanceProfileForImageBuilder
- arn:aws:iam::aws:policy/AWSDeadlineCloud-WorkerHost
ImageBuilderInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ImageBuilderEC2Role
WorkerInfrastructureConfiguration:
Type: AWS::ImageBuilder::InfrastructureConfiguration
Properties:
InstanceProfileName: !Ref ImageBuilderInstanceProfile
InstanceTypes:
- m5.xlarge
Name: !Sub deadline-cloud-worker-${Environment}-infrastructure-configuration
SubnetId: !Ref PublicSubnet1
SecurityGroupIds:
- !Ref WorkerSecurityGroup
TerminateInstanceOnFailure: true
Logging:
S3Logs:
S3BucketName: !Ref ImageBuilderLogBucket
Outputs:
Farm:
Value: !GetAtt Farm.FarmId
VpcId:
Value: !Ref VPC
PublicSubnet1Id:
Value: !Ref PublicSubnet1
PublicSubnet2Id:
Value: !Ref PublicSubnet2
WorkerSecurityGroupId:
Value: !Ref WorkerSecurityGroup
WorkerAgentBuildComponent:
Value: !Ref WorkerAgentBuildComponent
HoudiniBuildComponent:
Value: !Ref HoudiniBuildComponent
WorkerInfrastructureConfiguration:
Value: !Ref WorkerInfrastructureConfiguration
queue.yaml
Queue、Fleet、ワーカーイメージの構築を行います。またワーカーのオートスケーリングの設定を行います。
Cloud Formationテンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Deploy AWS Deadline Cloud Queue & Fleet
Parameters:
Environment:
Type: String
AllowedValues:
- development
- staging
- production
FarmId:
Type: String
VpcId:
Type: AWS::EC2::VPC::Id
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
WorkerSecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
ParentImageId:
Type: AWS::EC2::Image::Id
Default: ami-0d03c6e00d5732e28
WorkerAgentBuildComponent:
Type: String
HoudiniBuildComponent:
Type: String
HoudiniVersion:
Type: String
Default: "20.0.590"
HoudiniEULA:
Type: String
Default: "2021-10-13"
WorkerInfrastructureConfiguration:
Type: String
Mappings:
EnvironmentMap:
development:
DisplayName: Development
Tag: Dev
production:
DisplayName: Production
Tag: Prod
Resources:
JobAttachmentBucket:
Type: AWS::S3::Bucket
QueuePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:ListBucket
- s3:GetBucketLocation
Resource:
- !Sub arn:aws:s3:::${JobAttachmentBucket}
- !Sub arn:aws:s3:::${JobAttachmentBucket}/DeadlineCloud/*
Condition:
StringEquals:
aws:ResourceAccount: !Ref AWS::AccountId
- Effect: Allow
Action:
- logs:GetLogEvents
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/deadline/${FarmId}/*
QueueRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- deadline.amazonaws.com
- credentials.deadline.amazonaws.com
Action:
- sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnEquals:
aws:SourceArn: !Sub arn:aws:deadline:${AWS::Region}:${AWS::AccountId}:farm/${FarmId}
ManagedPolicyArns:
- !Ref QueuePolicy
Queue:
Type: AWS::Deadline::Queue
Properties:
DisplayName: !Sub
- ${AWS::StackName} ${EnvDisplayName} Queue
- EnvDisplayName: !FindInMap
- EnvironmentMap
- !Ref Environment
- DisplayName
FarmId: !Ref FarmId
JobAttachmentSettings:
RootPrefix: DeadlineCloud
S3BucketName: !Ref JobAttachmentBucket
JobRunAsUser:
RunAs: WORKER_AGENT_USER
RoleArn: !GetAtt QueueRole.Arn
FleetRolePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/deadline/${FarmId}/*
Condition:
ForAnyValue:StringEquals:
aws:CalledVia:
- deadline.amazonaws.com
- Effect: Allow
Action:
- logs:PutLogEvents
- logs:GetLogEvents
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/deadline/${FarmId}/*
FleetRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: credentials.deadline.amazonaws.com
Action:
- sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnEquals:
aws:SourceArn: !Sub arn:aws:deadline:${AWS::Region}:${AWS::AccountId}:farm/${FarmId}
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSDeadlineCloud-FleetWorker
- !Ref FleetRolePolicy
Fleet:
Type: AWS::Deadline::Fleet
Properties:
Configuration:
CustomerManaged:
Mode: NO_SCALING
WorkerCapabilities:
CpuArchitectureType: x86_64
MemoryMiB:
Max: 32768
Min: 8192
OsFamily: LINUX
VCpuCount:
Max: 8
Min: 4
DisplayName: !Sub
- ${AWS::StackName} ${EnvDisplayName} Fleet
- EnvDisplayName: !FindInMap
- EnvironmentMap
- !Ref Environment
- DisplayName
FarmId: !Ref FarmId
MaxWorkerCount: 10
MinWorkerCount: 0
RoleArn: !GetAtt FleetRole.Arn
QueueFleetAssociation:
Type: AWS::Deadline::QueueFleetAssociation
Properties:
FarmId: !Ref FarmId
FleetId: !GetAtt Fleet.FleetId
QueueId: !GetAtt Queue.QueueId
############################################################
# License Endpoint
############################################################
DeadlineLicenseEndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Security Group created for ${AWS::StackName} ${Environment} deadline license endpoint
GroupName: !Sub ${AWS::StackName}-${Environment}-deadlineLicenseEndpointSecurityGroup
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
VpcId: !Ref VpcId
HoudiniInboundRule:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
FromPort: 1715
ToPort: 1715
SourceSecurityGroupId: !Ref WorkerSecurityGroupId
GroupId: !Ref DeadlineLicenseEndpointSecurityGroup
MantraInboundRule:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
FromPort: 1717
ToPort: 1717
SourceSecurityGroupId: !Ref WorkerSecurityGroupId
GroupId: !Ref DeadlineLicenseEndpointSecurityGroup
DeadlineLicenseEndpoint:
Type: AWS::Deadline::LicenseEndpoint
Properties:
SecurityGroupIds:
- !Ref DeadlineLicenseEndpointSecurityGroup
SubnetIds: !Ref SubnetIds
VpcId: !Ref VpcId
Houdini20MeteredProduct:
Type: AWS::Deadline::MeteredProduct
Properties:
Family: product-houdini
LicenseEndpointId: !GetAtt DeadlineLicenseEndpoint.LicenseEndpointId
Port: 1715
ProductId: houdini-20.0
Vendor: sidefx
Mantra20MeteredProduct:
Type: AWS::Deadline::MeteredProduct
Properties:
Family: product-mantra
LicenseEndpointId: !GetAtt DeadlineLicenseEndpoint.LicenseEndpointId
Port: 1717
ProductId: mantra-20.0
Vendor: sidefx
############################################################
# EC2 Image Builder
############################################################
ImageRecipe:
Type: AWS::ImageBuilder::ImageRecipe
Properties:
Components:
- ComponentArn: !Ref WorkerAgentBuildComponent
Parameters:
- Name: FarmId
Value:
- !Ref FarmId
- Name: FleetId
Value:
- !GetAtt Fleet.FleetId
- ComponentArn: !Ref HoudiniBuildComponent
Parameters:
- Name: HoudiniVersion
Value:
- !Ref HoudiniVersion
- Name: EULA
Value:
- !Ref HoudiniEULA
Name: !Sub ${AWS::StackName}-${Environment}-worker-recipe
ParentImage: !Ref ParentImageId
BlockDeviceMappings:
- Ebs:
VolumeSize: 60
VolumeType: gp3
DeviceName: /dev/xvda
Version: 1.1.1
Image:
Type: AWS::ImageBuilder::Image
Properties:
ImageRecipeArn: !Ref ImageRecipe
InfrastructureConfigurationArn: !Ref WorkerInfrastructureConfiguration
ImageTestsConfiguration:
ImageTestsEnabled: true
TimeoutMinutes: 60
ImageParameter:
Type: AWS::SSM::Parameter
Properties:
DataType: aws:ec2:image
Name: !Sub ${AWS::StackName}-${Environment}-worker-image-id
Type: String
Value: !GetAtt Image.ImageId
Description: !Sub ${AWS::StackName}-${Environment}-worker-image-id
############################################################
# Auto Scaling
############################################################
DeadlineCloudWorkerRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AWSDeadlineCloud-WorkerHost
Tags:
- Key: Environmet
Value: !Ref Environment
- Key: FarmId
Value: !Ref FarmId
- Key: FleetId
Value: !GetAtt Fleet.FleetId
InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref DeadlineCloudWorkerRole
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Sub DeadlineCloudWorker-LaunchTemplate-${Fleet.FleetId}
LaunchTemplateData:
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: true
Groups:
- !Ref WorkerSecurityGroupId
DeleteOnTermination: true
ImageId: !Sub '{{resolve:ssm:${ImageParameter}}}'
InstanceInitiatedShutdownBehavior: terminate
IamInstanceProfile:
Arn: !GetAtt InstanceProfile.Arn
MetadataOptions:
HttpTokens: required
HttpEndpoint: enabled
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Name
Value: !Sub DeadlineCloudWorker-${Fleet.FleetId}
- Key: Environmet
Value: !Ref Environment
- Key: FarmId
Value: !Ref FarmId
- Key: FleetId
Value: !GetAtt Fleet.FleetId
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash
/opt/hfs${HoudiniVersion}/bin/hserver -S "http://${LicenseEndpointDnsName}:1715;http://${LicenseEndpointDnsName}:1717"
- LicenseEndpointDnsName: !GetAtt DeadlineLicenseEndpoint.DnsName
HoudiniVersion: !Ref HoudiniVersion
TagSpecifications:
- ResourceType: launch-template
Tags:
- Key: Environmet
Value: !Ref Environment
- Key: FarmId
Value: !Ref FarmId
- Key: FleetId
Value: !GetAtt Fleet.FleetId
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub DeadlineCloudWorker-AutoScalingGroup-${Fleet.FleetId}
MinSize: 0
MaxSize: 10
VPCZoneIdentifier: !Ref SubnetIds
NewInstancesProtectedFromScaleIn: true
MixedInstancesPolicy:
InstancesDistribution:
OnDemandBaseCapacity: 0
OnDemandPercentageAboveBaseCapacity: 0
SpotAllocationStrategy: capacity-optimized
OnDemandAllocationStrategy: lowest-price
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
Overrides:
- InstanceType: m5.large
- InstanceType: m5d.large
- InstanceType: m5a.large
- InstanceType: m5ad.large
- InstanceType: m5n.large
- InstanceType: m5dn.large
- InstanceType: m4.large
- InstanceType: m3.large
- InstanceType: r5.large
- InstanceType: r5d.large
- InstanceType: r5a.large
- InstanceType: r5ad.large
- InstanceType: r5n.large
- InstanceType: r5dn.large
- InstanceType: r4.large
MetricsCollection:
- Granularity: 1Minute
Metrics:
- GroupMinSize
- GroupMaxSize
- GroupDesiredCapacity
- GroupInServiceInstances
- GroupTotalInstances
- GroupInServiceCapacity
- GroupTotalCapacity
AutoScalingLambda:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |-
"""
This lambda is configured to handle "Fleet Size Recommendation Change"
messages. It will handle all such events, and requires
that the ASG is named based on the fleet id. It will scale up/down the fleet
based on the recommended fleet size in the message.
Example EventBridge message:
{
"version": "0",
"id": "6a7e8feb-b491-4cf7-a9f1-bf3703467718",
"detail-type": "Fleet Size Recommendation Change",
"source": "aws.deadline",
"account": "111122223333",
"time": "2017-12-22T18:43:48Z",
"region": "us-west-1",
"resources": [],
"detail": {
"farmId": "farm-12345678900000000000000000000000",
"fleetId": "fleet-12345678900000000000000000000000",
"oldFleetSize": 1,
"newFleetSize": 5,
}
}
"""
import json
import boto3
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
auto_scaling_client = boto3.client("autoscaling")
def lambda_handler(event, context):
logger.info(event)
event_detail = event["detail"]
fleet_id = event_detail["fleetId"]
desired_capacity = event_detail["newFleetSize"]
asg_name = f"DeadlineCloudWorker-AutoScalingGroup-{fleet_id}"
auto_scaling_client.set_desired_capacity(
AutoScalingGroupName=asg_name,
DesiredCapacity=desired_capacity,
HonorCooldown=False,
)
return {
'statusCode': 200,
'body': json.dumps(f'Successfully set desired_capacity for {asg_name} to {desired_capacity}')
}
Handler: index.lambda_handler
Role: !GetAtt AutoScalingLambdaServiceRole.Arn
Runtime: python3.11
DependsOn:
- AutoScalingLambdaServiceRoleDefaultPolicy
- AutoScalingLambdaServiceRole
AutoScalingEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.deadline
detail-type:
- Fleet Size Recommendation Change
State: ENABLED
Targets:
- Arn: !GetAtt AutoScalingLambda.Arn
DeadLetterConfig:
Arn: !GetAtt UnprocessedAutoScalingEventQueue.Arn
Id: Target0
RetryPolicy:
MaximumRetryAttempts: 15
AutoScalingEventRuleTargetPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt AutoScalingLambda.Arn
Principal: events.amazonaws.com
SourceArn: !GetAtt AutoScalingEventRule.Arn
AutoScalingLambdaServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: 2012-10-17
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
AutoScalingLambdaServiceRoleDefaultPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Statement:
- Action: autoscaling:SetDesiredCapacity
Effect: Allow
Resource: '*'
Version: 2012-10-17
PolicyName: AutoScalingLambdaServiceRoleDefaultPolicy
Roles:
- !Ref AutoScalingLambdaServiceRole
UnprocessedAutoScalingEventQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: deadline-unprocessed-autoscaling-events
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
UnprocessedAutoScalingEventQueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
PolicyDocument:
Statement:
- Action: sqs:SendMessage
Condition:
ArnEquals:
'aws:SourceArn': !GetAtt AutoScalingEventRule.Arn
Effect: Allow
Principal:
Service: events.amazonaws.com
Resource: !GetAtt UnprocessedAutoScalingEventQueue.Arn
Version: 2012-10-17
Queues:
- !Ref UnprocessedAutoScalingEventQueue
Outputs:
QueueId:
Value: !GetAtt Queue.QueueId
FleetId:
Value: !GetAtt Fleet.FleetId
ImageId:
Value: !Sub '{{resolve:ssm:${ImageParameter}}}'
LicenseEndpointDnsName:
Value: !GetAtt DeadlineLicenseEndpoint.DnsName
開発環境のデプロイ
Farmのスタックをデプロイします
AWSコンソールでCloudFormationを開き、スタックの作成をクリックします
スタック名は何でもよいですが、DevelopmentFarmStackなどとして、Environmentはdevelopmentを選択します。
出力タブにqueueスタックが入力として求めるパラメーターが表示されます。
S3に移動してSoftwareInstallerBucketをさがしてHoudiniのインストールしたいバージョンのインストーラーをアップロードします。
別タブでQueueStackを作成します。Stack名は{ProjectName}DevelopmentQueueStackなどとして、各パラメーター値をFarmStackの出力タブを確認して入力してください。 HoudiniVersionはアップロードしたーインストーラのバージョンと同じものを指定します
イメージビルダーのページからワーカーイメージが構築中であることを確認します。
またログストリームからインストールログが確認できます。
またMonitorも作成しておきます。CloudFormationで書いてもいいですが、Webコンソールから簡単に設定できるためブラウザから設定します
ジョブのサブミット&確認
サブミットについては本記事では詳しく触れませんが、DeadlineCloudサブミッターをインストールしてC:\Users\ユーザー名\Documents\houdini20.0\packages
にjsonファイルを配置します。
{
"env": [
{
"DEADLINE_CLOUD_FOR_HOUDINI": "C:\Users\ユーザー名\DeadlineCloudSubmitter/Submitters/Houdini"
},
{
"PYTHONPATH": "$DEADLINE_CLOUD_FOR_HOUDINI/python"
}
],
"hpath": "$DEADLINE_CLOUD_FOR_HOUDINI"
}
Houdiniでサブミット用のシーンをセットアップしてジョブをサブミットします。
Download Outputからジョブ結果のダウンロードができます
まとめ
以上になります。
GUNCY'SではAWSを利用したクラウドパイプラインの構築・運用のサポートを行っています。
導入に際してのサポートが必要な場合は、ぜひお気軽にご連絡ください。