繁体   English   中英

安排 AWS ECS Fargate 启动和停止任务

[英]Schedule AWS ECS Fargate to Start and STOP Tasks

根据 AWS 文档,他们说:“ Fargate 支持调度任务以响应 CloudWatch Events。您可以轻松启动和停止只需要在特定时间运行的 Fargate 任务

可以从CloudWatch Events 或 ECS Task Scheduler 轻松启用 Fargate 任务的启动。

但是我找不到 Fargate 任务的 STOP。 是否可能需要使用 Lambda 而不是本机 Fargate 功能来停止任务?

我的目标是只在晚上 8 点到下午 5 点之间运行 ECS 容器!

@Francesco Grotta 的回答是对的。 通过我们可以创建以下资源,以按时触发此操作:

  • 一个 lambda 函数,通过更新 ECS 服务DesiredCount来启动或停止。
  • 计划的 CloudWatch Events,用于启动 ECS 任务。
  • 计划的 CloudWatch Events,用于停止 ECS 任务。

将根据来自 CloudWatch Events 的输入启动或停止 ECS 服务的 Lambda 函数:

    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
    });

在 Cloudformation 模板中,创建将按计划调用 Lambda 函数的资源:

  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"}'

我采用了@Mr3381 提出的代码并进行了一些改进:

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}`)
      }
    });
  })
}

它现在在 TypeScript 中并支持将一系列服务作为输入。

只需将其转换为 JavaScript 即可在 AWS 上运行。

确保拥有执行函数和更新服务所需的权限。 这可以通过将 ECS 中的策略describeServicesupdateServices附加到您的 Lambda 函数 IAM 角色来实现。

我相信这是您办公时间问题的最佳解决方案。

只需使用以下命令在 EC2 实例中安排本地 cron 作业,即可根据时间戳更新所需的计数,您就可以开始了。

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

如果这对您有帮助,请告诉我。

与开始相同,但您需要将“所需任务”指定为 0。我的问题是调度程序需要任务定义,所以如果我升级它,我还需要更改调度程序。 是否存在一些服务、lambda 或项目来处理它? 我的需要是停止 Fargate 容器集群。

下面将找出所有的 qa、uat 或 dev 集群(前提是它们的名称中有字符串 qa、uat 或 dev),然后将它们下所有服务的任务数设置为 0。只需 cron 这个脚本和如果要启动所有非生产环境,请为--desired-count 1创建另一个 cron。 创建 /tmp/ecs-stop.log 文件以按原样使用脚本。 确保文件是可写的,并且脚本对于 cron 是可执行的,以便能够运行脚本并写入日志文件。

#!/bin/bash
export AWS_PAGER="" # Doesnt ask user to press q for paginated outputs
export AWS_PROFILE=default
d=$(date +%Y-%m-%d)
for cluster in $(/usr/local/bin/aws ecs list-clusters --output text | awk '{print $2}' | egrep -i 'qa|uat|dev'  )
do 
    echo -e "Cluster ==> $cluster"
    for service in $(/usr/local/bin/aws ecs list-services --cluster $cluster --output text | awk '{print $2}')
    do
        echo "Service ==> Stopping $service..."
        /usr/local/bin/aws ecs update-service --cluster $cluster --service $service --desired-count 0 > /dev/null 2>&1
    done
echo
done
echo "Stopped all non-prod ECS services."
echo "The script ran on $d" >> /tmp/ecs-stop.log

这是我的解决方案,它高度基于一位出色的 AWS 员工 (Alfredo J)。

首先,您需要创建一个Lambda函数并添加以下 Python 脚本:

import json
import boto3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

client = boto3.client('ecs')

def lambda_handler(event, context):
    cluster = event["cluster"]
    service_names = event["service_names"]
    service_desired_count = int(event["service_desired_count"])

    for service_name in service_names.split(","):
        response = client.update_service(
            cluster=cluster,
            service=service_name,
            desiredCount=service_desired_count
            )

        logger.info("Updated {0} service in {1} cluster with desire count set to {2} tasks".format(service_name, cluster, service_desired_count))
        
    return {
        'statusCode': 200,
        'new_desired_count': service_desired_count
    }

该脚本需要 JSON 格式的以下变量:

{
  "cluster": "clusterName",
  "service_names": "service1,service2",
  "service_desired_count": "0"
}

在哪里:

  • cluster是您要修改的集群的名称。
  • service_names是一个用于服务集合的数组。
  • service_desired_count是所需服务的数量。 0 是停止服务/秒,任何其他数字是启动服务/秒。

创建完所有内容后,您需要在 Amazon EventBridge(以前称为 CloudWatch Events)中创建一些规则。 在这里,您可以根据预期的计划定义要触发的事件。

如果出现问题,您需要仔细检查创建的 IAM 角色是否具有所需的策略,例如: ecs:UpdateService 您可以从日志中检查这一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM