[英]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 的回答是对的。 通过我们可以创建以下资源,以按时触发此操作:
DesiredCount
来启动或停止。将根据来自 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 中的策略describeServices和updateServices附加到您的 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.