DEV Community

Autoscaling using Spot Instances with AWS CDK + TS

If you’re a developer (like me xD), you know the value of running applications in the cloud—the ability to scale up and down with ease, the opportunity to test your app anywhere, and the ability to pay for resources as needed.

AWS EC2 Spot Instances are the best of both worlds—they're just like regular EC2 instances, except you don't need to pay for them up front, and they're cheaper than regular instances.

The main advantage to spot instances is that you only pay when you use them (rather than paying an upfront fee). But with spot instances, you also get more flexibility—you can move them around pretty easily, which means they work out as a great option for short-term projects or testing. In general, if your project isn't going to last longer than a few weeks or months, and you're not concerned with having access to all the features of your regular instance type (such as the ability to scale it up), then this is probably the best way to go!

If you want to know more about spot instances please take a look into this awesome blog post.

Let's get your hands dirty!

Our Architecture:

a vpc with ALB and autoscaling with spot instances


Let's start creating our vpc, piece of cake public and private subnets.

import { IVpc, SubnetType, Vpc } from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";

export default class DefaultVpc extends Construct {
  public readonly vpc: IVpc;
  constructor(scope: Construct, id: string) {
    super(scope, id);
    this.vpc = new Vpc(this, "my-vpc", {
      cidr: "",
      subnetConfiguration: [
          cidrMask: 28,
          name: "public subnet",
          subnetType: SubnetType.PUBLIC,
          cidrMask: 28,
          name: "private subnet",
          subnetType: SubnetType.PRIVATE_WITH_NAT,
Enter fullscreen mode Exit fullscreen mode

Application Load Balancer

In this step we need to create an internet facing load balancer

import { AutoScalingGroup } from "aws-cdk-lib/aws-autoscaling";
import { IVpc } from "aws-cdk-lib/aws-ec2";
import { ApplicationLoadBalancer } from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { Construct } from "constructs";

export default class InternetFacingApplicationLoadBalancer extends Construct {
  constructor(scope: Construct, id: string, resources: { vpc: IVpc, ec2AutoScalingGroup: AutoScalingGroup }) {
    super(scope, id);

    const loadBalancer = new ApplicationLoadBalancer(this, "appLoadBalancer", {
      vpc: resources.vpc,
      internetFacing: true,

    const httpListener = loadBalancer.addListener("httpListener", {
      port: 80,
      open: true,

    httpListener.addTargets('ApplicationSpotFleet', {
        port: 8080,
        targets: [resources.ec2AutoScalingGroup],
Enter fullscreen mode Exit fullscreen mode

AutoScaling Group

Now we create the autoscaling, ec2 instances and the wonderful decision to use spot instances.
We are using t4g.micro instances with latest Amazon Linux images. We are allowing all outbound traffic and the desired capacity of instances is one, while the maximum is 2.
Maximum spot price is set to 0.007, if the sport price goes up, for example to 0.008, then we have no instances at all. There are ways to address this, but for this example I'll only use in this way.

import { Duration } from "aws-cdk-lib";
import { AutoScalingGroup, HealthCheck } from "aws-cdk-lib/aws-autoscaling";
import {
} from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";

export default class ApplicationAutoScalingGroup extends Construct {
  public readonly autoScalingGroup: AutoScalingGroup;
    scope: Construct,
    id: string,
    resources: { vpc: IVpc }
  ) {
    super(scope, id);

    const applicationAutoScalingGroup = new AutoScalingGroup(this, "AutoScalingGroup", {
      vpc: resources.vpc,
      instanceType: InstanceType.of(
      machineImage: new AmazonLinuxImage({
        generation: AmazonLinuxGeneration.AMAZON_LINUX_2,
      allowAllOutbound: true,
      maxCapacity: 2,
      minCapacity: 1,
      desiredCapacity: 1,
      spotPrice: "0.007", // $0.0032 per Hour when writing, $0.0084 per Hour on-demand
      healthCheck: HealthCheck.ec2(),

    applicationAutoScalingGroup.scaleOnCpuUtilization("CpuScaling", {
        targetUtilizationPercent: 50,
        cooldown: Duration.minutes(1),
        estimatedInstanceWarmup: Duration.minutes(1),

    this.autoScalingGroup = applicationAutoScalingGroup;
Enter fullscreen mode Exit fullscreen mode

Finally our stack will be something like that:


import { StackProps, Environment, Stack } from 'aws-cdk-lib'
import { Construct } from 'constructs'
import InternetFacingApplicationLoadBalancer from '../lib/application-load-balancer/internet-facing-application-load-balancer'
import ApplicationAutoScalingGroup from '../lib/ec2/auto-scaling-group'
import DefaultVpc from '../lib/vpc/default-vpc'

export interface IStackProps extends StackProps {
  variables?: any
  env: Environment

export class ApplicationIntegrationStack extends Stack {
  constructor(scope: Construct, id: string, props: IStackProps) {
    super(scope, id, props)

    const { vpc } = new DefaultVpc(this, 'DefaultVpc')
    const { autoScalingGroup } = new ApplicationAutoScalingGroup(this, 'ApplicationAutoScalingGroup', { vpc })
    new InternetFacingApplicationLoadBalancer(this, 'InternetFacingApplicationLoadBalancer', { vpc, ec2AutoScalingGroup: autoScalingGroup })
Enter fullscreen mode Exit fullscreen mode

If you want to take a deep dive into this topic I strongly recommends this re:invent video about spot instances.

That's all folks!

Top comments (2)

gabrielterriaga profile image
Gabriel Terriaga

Amazing bro!!

wakeupmh profile image
Marcos Henrique

thaaaaanks my bro