如何在AWS ECS Fargate单任务多容器环境下获取容器级CPU与内存使用率?
解决ECS Fargate单个容器CPU/内存使用率获取问题
在ECS Fargate环境中,由于任务是serverless隔离的,free/top或你当前使用的mackerelio/go-osstat包只能拿到整个任务的主机级资源数据,要获取单个容器的使用率,推荐以下两种方案:
方法1:使用ECS任务元数据端点(官方推荐)
Fargate平台版本1.4.0及以上支持任务元数据端点v4,可直接获取任务内每个容器的实时资源使用统计。
实现步骤:
- 容器内可通过环境变量
ECS_CONTAINER_METADATA_URI_V4获取元数据服务地址(无需硬编码IP) - 发起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
相关产品推荐
相关产品推荐

