aws-rfdk
aws-rfdk copied to clipboard
Add construct for Deadline Webservice
I would like to have as well a Deadline web service running in my render farm.
Use Case
I use deadline web service to submit jobs via HTTP api programatically. As well read info about jobs/taks for monitoring.
Proposed Solution
Implement a construct to add Deadline Webservice into the service stack.
We are looking for requirements to help drive the design of this feature. In addition to the use-case @koenverwimp has already specified (programatically submitting jobs), we're looking for any additional input into the design requirements. Here are a couple of guiding questions that we'd like input on:
- What features of the Deadline Web Service are you interested in using? The Web Service provides the following features and we are interested to hear which features users intend to use:
- an HTTP REST API for querying and interacting with Deadline resources
- HTTP endpoints for proxying deadline commands
- Ability to write custom HTTP endpoints using custom python scripts
- What infrastructure would you like to be able to connect to the web service? Some examples that we've identified so far:
- Other AWS services (e.g. Lambda/CodeBuild)
- CDK/CloudFormation custom resources to interact with Deadline resources during CDK deployment
- What kind of resource load (CPU/memory) you'd typically provision for the web service for your particular use-case. We’re interested in this to determine the default EC2 instance type that would be set by RFDK when deploying the Web Service.
- Other feedback – anything else that I might be missing that should be considered for RFDK support of the Deadline Web Service
Was this ever accomplished? I would like to have access to the Deadline webservice for all three of the scenarios listed above with an instance stood up using RFDK.
I too would also like to request this feature.
Requirements gathering
To provide you some feedback @jusiskin to your questions:
- The HTTP REST API is our only need
- Combination of Lambdas and/or also custom developed business services running in a container (ECS/Fargate, App Runner)
- Our load requirements are low because it is a private internal API that is not bound to any public facing traffic. So it will be queried either on a schedule or in response to a queue of jobs coming into existense coming from somewhere (which can be rate limited). Currently using a
t2.small
and this is working fine for us.
Workaround for those in need now
I have developed the stack below that I can add quickly to any RFDK stack. This deploys a Deadline WebService behind a non-public App Load Balancer and takes advantage of the various "automagic" Deadline configuration features of the RFDK.
To access the web service, find the App Load Balancer DNS name and add the /api
suffix followed by the REST resource you need:
http://<APP_LOAD_BALANCER_DNS_ADDRESS>/api
Example:
http://internal-xxxxxx-12345678.eu-west-1.elb.amazonaws.com/api/jobs
deadline-api-stack.ts
import { Duration, Stack, StackProps } from "aws-cdk-lib";
import {
InstanceClass,
InstanceSize,
InstanceType,
MachineImage,
Peer,
Port,
SubnetType,
Vpc,
} from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";
import { RenderQueue } from "aws-rfdk/deadline";
import {
AutoScalingGroup,
HealthCheck,
Signals,
} from "aws-cdk-lib/aws-autoscaling";
import {
ApplicationLoadBalancer,
ApplicationProtocol,
} from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { DeadlineStack } from "./deadline-stack";
import { SessionManagerHelper } from "aws-rfdk";
export interface RestApiStackProps extends StackProps {
vpc: Vpc;
renderQueue: RenderQueue;
}
export class RestApiStack extends Stack {
constructor(scope: Construct, id: string, props: RestApiStackProps) {
super(scope, id, props);
// Web server
const webServerAsg = new AutoScalingGroup(this, "RestApiFleet", {
vpc: props.vpc,
vpcSubnets: {
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
},
instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.SMALL),
machineImage: MachineImage.genericLinux({
[this.region]: DeadlineStack.DEADLINE_WORKER_AMI,
}),
minCapacity: 1,
maxCapacity: 1,
signals: Signals.waitForMinCapacity({
timeout: Duration.minutes(10),
}),
healthCheck: HealthCheck.elb({
grace: Duration.minutes(1),
}),
});
webServerAsg.userData.addSignalOnExitCommand(webServerAsg);
SessionManagerHelper.grantPermissionsTo(webServerAsg);
// Configure it as a worker for convenience
props.renderQueue.configureClientInstance({
host: webServerAsg,
});
// Start the Deadline Web Service as background process
webServerAsg.userData.addCommands(
"/opt/Thinkbox/Deadline10/bin/deadlinewebservice &",
);
// Create an ALB so that we have a stable DNS address for the web server, independent of
// auto-scaling group changes
const appLb = new ApplicationLoadBalancer(this, "RestApiAlb", {
vpc: props.vpc,
internetFacing: false,
vpcSubnets: {
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
},
deletionProtection: false,
});
// Using port 80 for simplicity since this is only accessible inside of the private VPC
// Update this to use HTTPS and using certs generated from the RenderFarm RootCA certificate
// if you want to make it public or encrypted in transit
const listener = appLb.addListener("ApiListener", {
port: 80,
});
listener.addTargets("WebServer", {
port: 8081,
protocol: ApplicationProtocol.HTTP,
targets: [webServerAsg],
});
webServerAsg.connections.allowFrom(
appLb,
Port.tcp(8081),
"Allow traffic from ALB",
);
// Allow traffic from anywhere in the VPC
appLb.connections.allowFrom(
Peer.ipv4("10.0.0.0/16"),
Port.tcp(80),
"Allow Web API access from VPC",
);
}
}
Note:
- For simplicity this doesn't use TLS traffic on the App Load Balancer. In my use case this is fine because access is only within a private VPC. Should you need public access, you can use the RFDK.
- I am using
DEADLINE_WORKER_AMI = "ami-0d38a90c495cd61e5"
;