|
| 1 | +# AWS Thinkbox Deadline Construct Library |
| 2 | + |
| 3 | +<!--BEGIN STABILITY BANNER--> |
| 4 | +--- |
| 5 | + |
| 6 | + |
| 7 | + |
| 8 | +--- |
| 9 | +<!--END STABILITY BANNER--> |
| 10 | + |
| 11 | +The `aws-rfdk/deadline` sub-module contains Deadline-specific constructs that can be used to deploy and manage a Deadline render farm in the cloud. |
| 12 | + |
| 13 | +```ts nofixture |
| 14 | +import * as deadline from 'aws-rfdk/deadline'; |
| 15 | +``` |
| 16 | + |
| 17 | +## Repository |
| 18 | + |
| 19 | +The `Repository` contains the central database and file system used by Deadline. An EC2 instance is temporarily created to run the Deadline Repository installer which configures the database and file system. This construct has optional parameters for the database and file system to use, giving you the option to either provide your own resources or to have the construct create its own. Log messages emitted by the construct are forwarded to CloudWatch via a CloudWatch agent. |
| 20 | + |
| 21 | +You can create a `Repository` like this: |
| 22 | + |
| 23 | +```ts |
| 24 | +const repository = new Repository(stack, 'Repository', { |
| 25 | + vpc: props.vpc, |
| 26 | + version: VersionQuery.exactString(stack, 'Version', '1.2.3.4') |
| 27 | +}); |
| 28 | +``` |
| 29 | + |
| 30 | +### Configuring Deadline Client Connections |
| 31 | + |
| 32 | +Deadline Clients can be configured to connect directly to the `Repository`, which will: |
| 33 | +- Allow ingress traffic to database & file system Security Groups |
| 34 | +- Create IAM Permissions for database & file system |
| 35 | +- Mount the Repository file system via [UserData](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) |
| 36 | + |
| 37 | +Deadline Clients can be configured either in ECS or EC2. |
| 38 | + |
| 39 | +#### 1. Configure Deadline Client in ECS |
| 40 | + |
| 41 | +An ECS Container Instance and Task Definition for deploying Deadline Client can be configured to directly connect to the `Repository`. A mapping of environment variables and ECS [`MountPoint`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ecs.MountPoint.html)s are produced which can be used to configure a [`ContainerDefinition`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ecs.ContainerDefinition.html) to connect to the `Repository`. |
| 42 | + |
| 43 | +The example below demonstrates configuration of Deadline Client in ECS: |
| 44 | +```ts |
| 45 | +const taskDefinition = new Ec2TaskDefinition(stack, 'TaskDefinition'); |
| 46 | +const ecsConnection = repository.configureClientECS({ |
| 47 | + containerInstances: /* ... */, |
| 48 | + containers: { |
| 49 | + taskDefinition |
| 50 | + }, |
| 51 | + }); |
| 52 | + |
| 53 | +const containerDefinition = taskDefinition.addContainer('ContainerDefinition', { |
| 54 | + image: /* ... */, |
| 55 | + environment: ecsConnection.containerEnvironment |
| 56 | +}); |
| 57 | +containerDefinition.addMountPoints(ecsConnection.readWriteMountPoint); |
| 58 | +``` |
| 59 | +#### 2. Configure Deadline Client on EC2 |
| 60 | + |
| 61 | +An EC2 instance running Deadline Client can be configured to directly connect to the `Repository`. |
| 62 | + |
| 63 | +The example below demonstrates configuration of Deadline Client in an EC2 instance: |
| 64 | +```ts |
| 65 | +const instance = new Instance(stack, 'Instance', { |
| 66 | + vpc, |
| 67 | + instanceType: new InstanceType(/* ... */), |
| 68 | + machineImage: MachineImage.latestAmazonLinux() |
| 69 | +}); |
| 70 | +repository.configureClientInstance({ |
| 71 | + host: instance, |
| 72 | + mountPoint: '/mnt/repository' |
| 73 | +}); |
| 74 | +``` |
| 75 | + |
| 76 | +## Stage |
| 77 | + |
| 78 | +A stage is a directory that conforms to a [conventional structure](../../docs/DockerImageRecipes.md#stage-directory-convention) that RFDK requires to deploy Deadline. This directory contains the Docker image recipes that RFDK uses to build Docker images. |
| 79 | + |
| 80 | +### Staging Docker Recipes |
| 81 | + |
| 82 | +Docker image recipes required by various constructs in Deadline (e.g. `RenderQueue`, `UsageBasedLicensing`, etc.) must be staged to a local directory that RFDK can consume. For information on what a Docker image recipe is and how it should be organized, see [Docker Image Recipes](../../docs/DockerImageRecipes.md). You can either stage your own recipes or use ones provided by AWS Thinkbox via `ThinkboxDockerRecipes`. |
| 83 | + |
| 84 | +#### Using Thinkbox Docker Recipes |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +_**Note:** The `ThinkboxDockerRecipes` class requires a [multi-stage Dockerfile](https://docs.docker.com/develop/develop-images/multistage-build/), so your version of Docker must meet the minimum version that supports multi-stage builds (version 17.05)._ |
| 89 | + |
| 90 | +_**Note:** Regardless of what language is consuming `aws-rfdk`, the Node.js package is required since the `stage-deadline` script is used by `ThinkboxDockerRecipes` when running `cdk synth` or `cdk deploy`._ |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +AWS Thinkbox provides Docker recipes for use with Deadline constructs. To stage these recipes, use the `stage-deadline` script found in the `bin/` directory (e.g. `node_modules/aws-rfdk/bin/stage-deadline` for npm). The following example shows how to stage version 10.1.7.1 of Deadline: |
| 95 | + |
| 96 | +``` |
| 97 | +npx stage-deadline \ |
| 98 | + --deadlineInstallerURI s3://thinkbox-installers/Deadline/10.1.7.1/Linux/DeadlineClient-10.1.7.1-linux-x64-installer.run \ |
| 99 | + --dockerRecipesURI s3://thinkbox-installers/DeadlineDocker/10.1.7.1/DeadlineDocker-10.1.7.1.tar.gz |
| 100 | +``` |
| 101 | + |
| 102 | +This command will download the Deadline installers and Docker recipes for Deadline version 10.1.7.1 to a local subdirectory `stage`. The Deadline versions in the URIs **must** be equal. For more information, run `stage-deadline --help`. |
| 103 | + |
| 104 | +In your typescript code, you can then create an instance of `ThinkboxDockerRecipes` from this stage directory like this: |
| 105 | + |
| 106 | +```ts |
| 107 | +const recipes = new ThinkboxDockerRecipes(scope, 'DockerRecipes', { |
| 108 | + stage: Stage.fromDirectory(/* <path-to-stage-directory> */), |
| 109 | +}); |
| 110 | +``` |
| 111 | + |
| 112 | +#### Conveniently Run stage-deadline Script |
| 113 | + |
| 114 | +Having to memorize the path conventions used in the URIs of the arguments to the `stage-deadline` can be cumbersome and error-prone. The following recommendations provide a more convenient way to use `stage-deadline`. |
| 115 | + |
| 116 | +**Typescript/Javascript** |
| 117 | + |
| 118 | +We recommend adding a `script` field in your `package.json` that runs the `stage-deadline` script with pre-populated parameters to ease the burden of having to remember the path conventions used in the thinkbox-installers S3 bucket. You can also leverage the built-in support for accessing the values of fields in `package.json` using the `${npm_package_<field1_innerfield1_...>}` syntax. |
| 119 | + |
| 120 | +```json |
| 121 | +{ |
| 122 | + ... |
| 123 | + "config": { |
| 124 | + "deadline_ver": "10.1.7.1", |
| 125 | + "stage_path": "stage" |
| 126 | + }, |
| 127 | + ... |
| 128 | + "scripts": { |
| 129 | + ... |
| 130 | + "stage": "stage-deadline -d s3://thinkbox-installers/Deadline/${npm_package_config_deadline_ver}/Linux/DeadlineClient-${npm_package_config_deadline_ver}-linux-x64-installer.run -c s3://thinkbox-installers/DeadlineDocker/${npm_package_config_deadline_ver}/DeadlineDocker-${npm_package_config_deadline_ver}.tar.gz -o ${npm_package_config_stage_path}", |
| 131 | + }, |
| 132 | + ... |
| 133 | +} |
| 134 | +``` |
| 135 | + |
| 136 | +With this in place, staging the Deadline Docker recipes can be done simply by running `npm run stage`. |
| 137 | + |
| 138 | +## VersionQuery |
| 139 | + |
| 140 | +The `VersionQuery` construct encapsulates a version of Deadline and the location in Amazon S3 to retrieve the installers for that version. Deadline versions follow a `<major>.<minor>.<release>.<patch>` schema (e.g. `1.2.3.4`). Various constructs in this library use `VersionQuery` to determine the version of Deadline to work with. |
| 141 | + |
| 142 | +You can specify a Deadline version as follows: |
| 143 | +```ts |
| 144 | +const version = VersionQuery.exact(stack, 'ExactVersion', { |
| 145 | + majorVersion: '1', |
| 146 | + minorVersion: '2', |
| 147 | + releaseVersion: '3', |
| 148 | + patchVersion: '4' |
| 149 | +}); |
| 150 | +``` |
| 151 | + |
| 152 | +## Worker Fleet |
| 153 | + |
| 154 | +A `WorkerInstanceFleet` represents a fleet of instances that are the render nodes of your render farm. These instances are created in an [`AutoScalingGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-autoscaling.AutoScalingGroup.html) with a provided AMI that should have Deadline Client installed as well as any desired render applications. Each of the instances will configure itself to connect to the specified [`RenderQueue`](#renderqueue) so that they are able to communicate with Deadline to pick up render jobs. Any logs emitted by the workers are sent to CloudWatch via a CloudWatch agent. |
| 155 | + |
| 156 | +You can create a `WorkerInstanceFleet` like this: |
| 157 | +```ts |
| 158 | +const fleet = new WorkerInstanceFleet(stack, 'WorkerFleet', { |
| 159 | + vpc, |
| 160 | + renderQueue, |
| 161 | + workerMachineImage: /* ... */, |
| 162 | +}); |
| 163 | +``` |
| 164 | + |
| 165 | +### Worker Fleet Health Monitoring |
| 166 | + |
| 167 | +The `WorkerInstanceFleet` uses Elastic Load Balancing (ELB) health checks with its `AutoScalingGroup` to ensure the fleet is operating as expected. ELB health checks have two components: |
| 168 | + |
| 169 | +1. **EC2 Status Checks** - Amazon EC2 identifies any hardware or software issues on instances. If a status check fails for an instance, it will be replaced. For more information, see [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-system-instance-status-check.html). |
| 170 | +2. **Load Balancer Health Checks** - Load balancers send periodic pings to instances in the `AutoScalingGroup`. If a ping to an instance fails, the instance is considered unhealthy. For more information, see [here](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-add-elb-healthcheck.html). |
| 171 | + |
| 172 | +EC2 status checks are great for detecting lower level issues with instances and automatically replacing them. If you also want to detect any issues with Deadline on your instances, you can do this by setting up a health monitoring options on the `WorkerInstanceFleet` along with a `HealthMonitor` (see [`aws-rfdk`](../core/README.md)). The `HealthMonitor` will ensure that your `WorkerInstanceFleet` remains healthy by checking that a minimum number of hosts are healthy for a given grace period. If the fleet is found to be unhealthy, its capacity will set to 0, meaning that all instances will be terminated. This is a precaution to save on costs in the case of a misconfigured render farm. |
| 173 | + |
| 174 | +Below is an example of setting up health monitoring in a `WorkerInstanceFleet`. |
| 175 | +```ts |
| 176 | +const healthMonitor = new HealthMonitor(stack, 'HealthMonitor', { |
| 177 | + vpc, |
| 178 | + elbAccountLimits: /* ... */ |
| 179 | +}); |
| 180 | + |
| 181 | +const workerFleet = new WorkerInstanceFleet(stack, 'WorkerFleet', { |
| 182 | + vpc, |
| 183 | + renderQueue: /* ... */, |
| 184 | + workerMachineImage: /* ... */, |
| 185 | + healthMonitor: healthMonitor, |
| 186 | + healthCheckConfig: { |
| 187 | + interval: Duration.minutes(5) |
| 188 | + } |
| 189 | +}); |
| 190 | +``` |
| 191 | + |
| 192 | +## Render Queue |
| 193 | + |
| 194 | +The `RenderQueue` is the central service of a Deadline render farm. It consists of the following components: |
| 195 | + |
| 196 | +- **Deadline Repository** - The repository that initializes the persistent data schema used by Deadline such as job information, connected workers, rendered output files, etc. |
| 197 | +- **Deadline Remote Connection Server (RCS)** - The central server that all Deadline applications connect to. The RCS contains the core business logic to manage the render farm. |
| 198 | + |
| 199 | +The `RenderQueue` construct sets up the RCS and configures it to communicate with the Repository and to listen for requests using the configured protocol (HTTP or HTTPS). Docker container images are used to deploy the `RenderQueue` as a fleet of instances within an Elastic Container Service (ECS) cluster. This fleet of instances is load balanced by an [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html) which has built-in health monitoring functionality that can be configured through this construct. |
| 200 | + |
| 201 | +--- |
| 202 | + |
| 203 | +_**Note:** The number of instances running the Render Queue is currently limited to a maximum of one._ |
| 204 | + |
| 205 | +--- |
| 206 | + |
| 207 | +The following example outlines how to construct a `RenderQueue`: |
| 208 | + |
| 209 | +```ts |
| 210 | +const recipes = new ThinkboxDockerRecipes(stack, 'Recipes', { |
| 211 | + stage: Stage.fromDirectory(/* ... */) |
| 212 | +}); |
| 213 | +const version = VersionQuery.exactString(stack, 'Version', '1.2.3.4'); |
| 214 | +const repository = new Repository(stack, 'Repository', { /* ...*/}); |
| 215 | + |
| 216 | +const renderQueue = new RenderQueue(stack, 'RenderQueue', { |
| 217 | + vpc: vpc, |
| 218 | + images: recipes.renderQueueImages, |
| 219 | + version: version, |
| 220 | + repository: repository, |
| 221 | +}); |
| 222 | +``` |
| 223 | + |
| 224 | +### Render Queue Encryption |
| 225 | + |
| 226 | +The `RenderQueue` provides end-to-end encryption of communications and data at rest. However, it currently does not do any client validation or application authentication due to limitations with Application Load Balancers that made it necessary to disable Deadline Worker TLS certificate authentication. |
| 227 | + |
| 228 | +--- |
| 229 | + |
| 230 | +_**Note:** Be extra careful when setting up security group rules that govern access to the `RenderQueue` and, for the machines that do have access to it, ensure you trust the Operating System as well as any software being used._ |
| 231 | + |
| 232 | +--- |
| 233 | + |
| 234 | +### Render Queue Health Monitoring |
| 235 | + |
| 236 | +The `RenderQueue` construct leverages the built-in health monitoring functionality provided by Application Load Balancers. The health check grace period and interval can be configured by specifying the `healthCheckConfig` property of the construct. For more information, see [Application Load Balancer Health Checks](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html). |
| 237 | + |
| 238 | +### Render Queue Deletion Protection |
| 239 | + |
| 240 | +By default, the Load Balancer in the `RenderQueue` has [deletion protection](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection) enabled to ensure that it does not get accidentally deleted. This also means that it cannot be automatically destroyed by CDK when you destroy your stack and must be done manually (see [here](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection)). |
| 241 | + |
| 242 | +You can specify deletion protection with a property in the `RenderQueue`: |
| 243 | +```ts |
| 244 | +const renderQueue = new RenderQueue(stack, 'RenderQueue', { |
| 245 | + //... |
| 246 | + deletionProtection: false |
| 247 | +}); |
| 248 | +``` |
| 249 | + |
| 250 | +### Render Queue Docker Container Images |
| 251 | + |
| 252 | +The `RenderQueue` currently requires only one Docker container image for the Deadline Remote Connection Server (RCS). An RCS image must satisfy the following criteria to be compatible with RFDK: |
| 253 | + |
| 254 | +- Deadline Client must be installed |
| 255 | +- The port the RCS will be listening on must be exposed |
| 256 | +- The default command must launch the RCS |
| 257 | + |
| 258 | +AWS Thinkbox provides Docker recipes that set these up for you. These can be accessed with the `ThinkboxDockerRecipes` class (see [Staging Docker Recipes](#staging-docker-recipes)). |
| 259 | + |
| 260 | +## Usage-Based Licensing (UBL) |
| 261 | + |
| 262 | +Usage-Based Licensing is an on-demand licensing model (see [Deadline Documentation](https://docs.thinkboxsoftware.com/products/deadline/10.1/1_User%20Manual/manual/licensing-usage-based.html)). The RFDK supports this type of licensing with the `UsageBasedLicensing` construct. This construct contains the following components: |
| 263 | + |
| 264 | +- **Deadline License Forwarder** - Forwards licenses to Deadline Workers that are rendering jobs. |
| 265 | + |
| 266 | +The `UsageBasedLicensing` construct sets up the License Forwarder, configures the defined license limits, and allows communication with the Render Queue. Docker container images are used to deploy the License Forwarder as a fleet of instances within an Elastic Container Service (ECS) cluster. |
| 267 | + |
| 268 | +--- |
| 269 | + |
| 270 | +_**Note:** This construct does not currently implement the Deadline License Forwarder's Web Forwarding functionality._ |
| 271 | + |
| 272 | +_**Note:** This construct is not usable in any China region._ |
| 273 | + |
| 274 | +--- |
| 275 | + |
| 276 | +The following example outlines how to construct `UsageBasedLicensing`: |
| 277 | + |
| 278 | +```ts |
| 279 | +const recipes = new ThinkboxDockerRecipes(stack, 'Recipes', { |
| 280 | + stage: Stage.fromDirectory(/* ... */) |
| 281 | +}); |
| 282 | + |
| 283 | +const ubl = new UsageBasedLicensing(stack, 'UsageBasedLicensing', { |
| 284 | + vpc: vpc, |
| 285 | + renderQueue: renderQueue, |
| 286 | + images: recipes.ublImages, |
| 287 | + licenses: [ UsageBasedLicense.forKrakatoa(/* ... */), /* ... */ ], |
| 288 | + certificateSecret: /* ... */, // This must be a binary secret (see below) |
| 289 | + memoryReservationMiB: /* ... */ |
| 290 | +}); |
| 291 | +``` |
| 292 | + |
| 293 | +#### Uploading Binary Secrets to SecretsManager |
| 294 | + |
| 295 | +The `UsageBasedLicensing` construct expects a `.zip` file containing usage-based licenses stored as a binary secret in SecretsManager. The AWS web console does not provide a way to upload binary secrets to SecretsManager, but this can be done via [AWS CLI](https://aws.amazon.com/cli/). You can use the following command to upload a binary secret: |
| 296 | +``` |
| 297 | +aws secretsmanager create-secret --name <secret-name> --secret-binary fileb://<path-to-file> |
| 298 | +``` |
| 299 | + |
| 300 | +### Usage-Based Licensing Docker Container Images |
| 301 | + |
| 302 | +`UsageBasedLicensing` currently requires only one Docker container image for the Deadline License Forwarder. A License Forwarder image must satisfy the following criteria to be compatible with AWS RFDK: |
| 303 | + |
| 304 | +- Deadline Client must be installed |
| 305 | +- The default command must launch the License Forwarder |
| 306 | + |
| 307 | +AWS Thinkbox provides Docker recipes that sets these up for you. These can be accessed with the `ThinkboxDockerRecipes` class (see [Staging Docker Recipes](#staging-docker-recipes)). |
0 commit comments