You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AWS ECS Fargate单任务多容器环境下获取容器级CPU与内存使用率?

解决ECS Fargate单个容器CPU/内存使用率获取问题

在ECS Fargate环境中,由于任务是serverless隔离的,free/top或你当前使用的mackerelio/go-osstat包只能拿到整个任务的主机级资源数据,要获取单个容器的使用率,推荐以下两种方案:

方法1:使用ECS任务元数据端点(官方推荐)

Fargate平台版本1.4.0及以上支持任务元数据端点v4,可直接获取任务内每个容器的实时资源使用统计。

实现步骤:

  1. 容器内可通过环境变量ECS_CONTAINER_METADATA_URI_V4获取元数据服务地址(无需硬编码IP)
  2. 发起HTTP GET请求到该地址,返回的JSON数据中Containers数组包含所有容器信息,每个容器的Stats字段包含CPU、内存等使用数据

Go代码示例:

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

type TaskMetadata struct {
	Containers []Container `json:"Containers"`
}

type Container struct {
	Name  string `json:"Name"`
	Stats Stats  `json:"Stats"`
}

type Stats struct {
	CPUUsage    CPUUsage    `json:"CPUUsage"`
	MemoryUsage MemoryUsage `json:"MemoryUsage"`
}

type CPUUsage struct {
	TotalUsage uint64 `json:"TotalUsage"`
}

type MemoryUsage struct {
	Usage uint64 `json:"Usage"`
}

func main() {
	metadataURI := os.Getenv("ECS_CONTAINER_METADATA_URI_V4")
	if metadataURI == "" {
		fmt.Println("ECS_CONTAINER_METADATA_URI_V4环境变量未设置")
		os.Exit(1)
	}

	// 首次获取CPU累计使用量
	resp, err := http.Get(metadataURI)
	if err != nil {
		fmt.Printf("获取元数据失败: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		os.Exit(1)
	}

	var taskMeta TaskMetadata
	err = json.Unmarshal(body, &taskMeta)
	if err != nil {
		fmt.Printf("解析JSON失败: %v\n", err)
		os.Exit(1)
	}

	var firstCPUUsage uint64
	for _, container := range taskMeta.Containers {
		if container.Name == "A" {
			firstCPUUsage = container.Stats.CPUUsage.TotalUsage
			break
		}
	}

	// 等待1秒后再次获取
	time.Sleep(1 * time.Second)
	resp, err = http.Get(metadataURI)
	if err != nil {
		fmt.Printf("再次获取元数据失败: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		os.Exit(1)
	}

	err = json.Unmarshal(body, &taskMeta)
	if err != nil {
		fmt.Printf("解析JSON失败: %v\n", err)
		os.Exit(1)
	}

	// 计算并输出容器A的资源使用率
	for _, container := range taskMeta.Containers {
		if container.Name == "A" {
			// CPU使用率计算:1vCPU对应每秒10^9纳秒能力
			cpuDiff := container.Stats.CPUUsage.TotalUsage - firstCPUUsage
			cpuUsagePercent := float64(cpuDiff) / 1000000000 * 100
			fmt.Printf("容器A CPU使用率: %.2f%%\n", cpuUsagePercent)

			// 内存使用率计算:预留2GB=2147483648字节
			reservedMemory := uint64(2 * 1024 * 1024 * 1024)
			memoryUsagePercent := float64(container.Stats.MemoryUsage.Usage) / float64(reservedMemory) * 100
			fmt.Printf("容器A内存使用率: %.2f%% (已使用: %d字节)\n", memoryUsagePercent, container.Stats.MemoryUsage.Usage)
			break
		}
	}
}

方法2:读取容器内的cgroup文件

Fargate的容器通过cgroup实现资源隔离,可直接读取容器内的cgroup统计文件获取单个容器的资源使用数据。

CPU使用率获取示例:

package main

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"time"
)

func readCPUAcctUsage() (uint64, error) {
	data, err := ioutil.ReadFile("/sys/fs/cgroup/cpu/cpuacct.usage")
	if err != nil {
		return 0, err
	}
	usage, err := strconv.ParseUint(string(data[:len(data)-1]), 10, 64)
	if err != nil {
		return 0, err
	}
	return usage, nil
}

func main() {
	firstUsage, err := readCPUAcctUsage()
	if err != nil {
		fmt.Printf("获取CPU使用量失败: %v\n", err)
		return
	}
	firstTime := time.Now()

	time.Sleep(1 * time.Second)

	secondUsage, err := readCPUAcctUsage()
	if err != nil {
		fmt.Printf("获取CPU使用量失败: %v\n", err)
		return
	}
	timeDiff := secondTime.Sub(firstTime).Nanoseconds()

	// 计算使用率:(差值纳秒数 / 时间差纳秒数) * 100%
	usagePercent := float64(secondUsage-firstUsage) / float64(timeDiff) * 100
	fmt.Printf("容器CPU使用率: %.2f%%\n", usagePercent)
}

内存使用率获取示例:

package main

import (
	"fmt"
	"io/ioutil"
	"strconv"
)

func main() {
	data, err := ioutil.ReadFile("/sys/fs/cgroup/memory/memory.usage_in_bytes")
	if err != nil {
		fmt.Printf("获取内存使用量失败: %v\n", err)
		return
	}
	usage, err := strconv.ParseUint(string(data[:len(data)-1]), 10, 64)
	if err != nil {
		fmt.Printf("解析内存使用量失败: %v\n", err)
		return
	}

	reservedMemory := uint64(2 * 1024 * 1024 * 1024)
	usagePercent := float64(usage) / float64(reservedMemory) * 100
	fmt.Printf("容器内存使用率: %.2f%% (已使用: %d字节)\n", usagePercent, usage)
}

内容的提问来源于stack exchange,提问作者Gowthaman Thangavel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:50:37