Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Schedule AWS ECS Fargate to Start and STOP Tasks

Per AWS documentation they say: "Fargate supports scheduling tasks in response to CloudWatch Events. You can easily launch and stop Fargate tasks that you only need to run at certain times"

Start of Fargate Tasks can easily be enabled from CloudWatch Events or ECS Task Scheduler.

But STOP of Fargate Tasks I cannot find. Is it possible that need to use Lambda and not native Fargate feature to stop tasks?

My goal is to run ECS Container between 8ap-5pm Only!

like image 782
ADV-IT Avatar asked Dec 19 '18 23:12

ADV-IT


3 Answers

answer by @Francesco Grotta is right. By we can create the following resources, to trigger this action on schedule:

  • A lambda function, to start or stop by update the ECS service DesiredCount.
  • A scheduled CloudWatch Events, to start the ECS tasks.
  • A scheduled CloudWatch Events, to stop the ECS tasks.

Lambda Function that will start or stop the ECS service based on the input from CloudWatch Events:

    if(event.status == 'stop'){
        var params = {
            cluster: process.env.ECS_CLUSTER,
            service: process.env.ECS_SERVICE_NAME,
            desiredCount: 0
        };
    }
    else{
        var params = {
            cluster: process.env.ECS_CLUSTER,
            service: process.env.ECS_SERVICE_NAME,
            desiredCount: 1
        };
    }

    var ecs = new AWS.ECS();
    ecs.updateService(params, function (err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else console.log(data);           // successful response
    });

In Cloudformation template, create resources that will invoke the Lambda Function on a schedule:

  StartEcsLambdaSchedule:
    Type: AWS::Events::Rule
    Properties:
      Description: >
        A schedule for the Lambda function to start ECS service during office hours.
      ScheduleExpression: !Ref StartEcsLambdaScheduleExpression
      State: ENABLED
      Targets:
        - Arn: !Sub ${EcsTaskScheduleLambdaFunction.Arn}
          Id: StartEcsLambdaScheduleV1
          Input: '{"status": "start"}'

  StopEcsLambdaSchedule:
    Type: AWS::Events::Rule
    Properties:
      Description: >
        A schedule for the Lambda function to stop ECS service after office hours.
      ScheduleExpression: !Ref StopEcsLambdaScheduleExpression
      State: ENABLED
      Targets:
        - Arn: !Sub ${EcsTaskScheduleLambdaFunction.Arn}
          Id: StopEcsLambdaScheduleV1
          Input: '{"status": "stop"}'
like image 135
Mr3381 Avatar answered Nov 17 '22 22:11

Mr3381


I've taken the code @Mr3381 proposed and made some improvements:

interface EventLambda {
  status: string,
  services: string[]
}

interface UpdateServiceParams {
  cluster: string
  service: string
  desiredCount: number
}

// Load AWS SDK for Node.js
import AWS from 'aws-sdk';

export const handler = async (event: EventLambda): Promise<string[]> => {
  const ecs = new AWS.ECS({region: 'sa-east-1'});
  const promises = new Array<Promise<any>>();
  const desiredCount = event.status == 'start' ? 1 : 0

  event.services.forEach(service => {
      var params: UpdateServiceParams = {
        cluster: process.env.ECS_CLUSTER!,
        service,
        desiredCount
      };
      promises.push(updateService(ecs, params, desiredCount))
    }
  )
  return Promise.all(promises)
};

function updateService(ecs: AWS.ECS, params: UpdateServiceParams, desiredCount: number): Promise<string> {
  return new Promise((resolve, reject) => {
    ecs.updateService(params, function(err, data) {
      if (err) {
        console.log(err, err.stack); // An error occurred
        resolve(`${params.service} not updated`);
      }
      else {
        console.log(data); // Successful response
        resolve(`${params.service} updated => Desired count: ${desiredCount}`)
      }
    });
  })
}

It's now in TypeScript and supports an array of services as an input.

There's only the need to transpile it to JavaScript to be able to run on AWS.

Make sure to have the required permissions to execute the function and update your services. This can be achieved by attaching the policies describeServices and updateServices from ECS to your Lambda function IAM Role.

like image 44
manuelnucci Avatar answered Nov 17 '22 23:11

manuelnucci


I believe this is the best solution for your office hours problem.

Just schedule a local cron job in the EC2 instance with the below command to update desired count according the timestamp and you are good to go.

$ aws ecs update-service --cluster <cluster-name> --service <service-name> --desired-count x

Do let me know in case this helped you.

like image 1
Nitin Garg Avatar answered Nov 17 '22 22:11

Nitin Garg