ListContainerStats returns stats for a list container stats request based on a filter.
( ctx context.Context, r *runtimeapi.ListContainerStatsRequest, )
| 188 | |
| 189 | // ListContainerStats returns stats for a list container stats request based on a filter. |
| 190 | func (ds *dockerService) ListContainerStats( |
| 191 | ctx context.Context, |
| 192 | r *runtimeapi.ListContainerStatsRequest, |
| 193 | ) (*runtimeapi.ListContainerStatsResponse, error) { |
| 194 | start := time.Now() |
| 195 | containerStatsFilter := r.GetFilter() |
| 196 | filter := &runtimeapi.ContainerFilter{} |
| 197 | |
| 198 | if containerStatsFilter != nil { |
| 199 | filter.Id = containerStatsFilter.Id |
| 200 | filter.PodSandboxId = containerStatsFilter.PodSandboxId |
| 201 | filter.LabelSelector = containerStatsFilter.LabelSelector |
| 202 | } |
| 203 | |
| 204 | res, err := ds.ListContainers(ctx, &runtimeapi.ListContainersRequest{Filter: filter}) |
| 205 | if err != nil { |
| 206 | logrus.Errorf("Error listing containers with filter: %+v", filter) |
| 207 | logrus.Errorf("Error listing containers error: %s", err) |
| 208 | return nil, err |
| 209 | } |
| 210 | containers := res.Containers |
| 211 | ds.containerStatsCache.clist <- containers |
| 212 | numContainers := len(containers) |
| 213 | logrus.Debugf("Number of pod containers: %v", numContainers) |
| 214 | if numContainers == 0 { |
| 215 | return &runtimeapi.ListContainerStatsResponse{}, nil |
| 216 | } |
| 217 | |
| 218 | var mu sync.Mutex |
| 219 | results := make([]*runtimeapi.ContainerStats, 0, len(containers)) |
| 220 | |
| 221 | g, ctx := errgroup.WithContext(ctx) |
| 222 | // The `getContainerStats` may take some time. When there are many containers, |
| 223 | // the whole `ListContainerStats` may have long delays if the number of workers is |
| 224 | // small. So we want to set a bigger value for the number of workers to avoid |
| 225 | // too long delays before the issue mentioned in https://github.com/moby/moby/pull/46448 |
| 226 | // is fixed. |
| 227 | // Consider a common node with 8 CPU running dozens of pods, NumCPU() * 6 may be a moderate |
| 228 | // number. |
| 229 | numWorkers := runtime.NumCPU() * 6 |
| 230 | if numWorkers > numContainers { |
| 231 | numWorkers = numContainers |
| 232 | } |
| 233 | g.SetLimit(numWorkers) |
| 234 | |
| 235 | // Collect container stats and send to result channel. |
| 236 | // The concurrency is numWorkers |
| 237 | for _, c := range containers { |
| 238 | c := c |
| 239 | g.Go(func() error { |
| 240 | if ctx.Err() != nil { |
| 241 | return ctx.Err() |
| 242 | } |
| 243 | stats, err := ds.getContainerStats(c) |
| 244 | if err != nil { |
| 245 | logrus.Errorf("error collecting stats for container '%s': %v", c.Metadata.Name, err) |
| 246 | return nil |
| 247 | } |
nothing calls this directly
no test coverage detected