[英]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.