【问题标题】:Schedule AWS ECS Fargate to Start and STOP Tasks安排 AWS ECS Fargate 启动和停止任务
【发布时间】:2019-05-20 11:44:58
【问题描述】:

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

可以从 CloudWatch 事件或 ECS 任务计划程序轻松启用 Fargate 任务的启动。

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

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

【问题讨论】:

  • 你能找到停止fargate任务的本地方法吗?
  • 这令人困惑。 ECS 中的任务是一次性容器。一旦他们完成工作,他们会自动被杀死。另一方面,服务不断旋转任务(以维护任务的 DesiredCount)。您的意思是启动和停止 Fargate 服务吗?

标签: amazon-web-services aws-fargate


【解决方案1】:

这是我的解决方案,它高度基于一位出色的 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。您可以从日志中检查这一点。

【讨论】:

    【解决方案2】:

    下面会找出所有的 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
    

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        【解决方案4】:

        我采用了@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 上运行。

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

        【讨论】:

          【解决方案5】:

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

          • 一个 lambda 函数,通过更新 ECS 服务 DesiredCount 来启动或停止。
          • 计划的 CloudWatch 事件,用于启动 ECS 任务。
          • 计划的 CloudWatch 事件,用于停止 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"}'
          

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-09-10
              • 2021-02-06
              • 2019-09-25
              • 2019-10-07
              • 2021-12-19
              • 2017-01-20
              • 1970-01-01
              相关资源
              最近更新 更多