簡體   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