123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- //go:build !windows
- package daemon // import "github.com/docker/docker/daemon"
- import (
- "context"
- "strings"
- statsV1 "github.com/containerd/cgroups/v3/cgroup1/stats"
- statsV2 "github.com/containerd/cgroups/v3/cgroup2/stats"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/container"
- "github.com/pkg/errors"
- )
- func copyBlkioEntry(entries []*statsV1.BlkIOEntry) []types.BlkioStatEntry {
- out := make([]types.BlkioStatEntry, len(entries))
- for i, re := range entries {
- out[i] = types.BlkioStatEntry{
- Major: re.Major,
- Minor: re.Minor,
- Op: re.Op,
- Value: re.Value,
- }
- }
- return out
- }
- func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
- c.Lock()
- task, err := c.GetRunningTask()
- c.Unlock()
- if err != nil {
- return nil, err
- }
- cs, err := task.Stats(context.Background())
- if err != nil {
- if strings.Contains(err.Error(), "container not found") {
- return nil, containerNotFound(c.ID)
- }
- return nil, err
- }
- s := &types.StatsJSON{}
- s.Read = cs.Read
- stats := cs.Metrics
- switch t := stats.(type) {
- case *statsV1.Metrics:
- return daemon.statsV1(s, t)
- case *statsV2.Metrics:
- return daemon.statsV2(s, t)
- default:
- return nil, errors.Errorf("unexpected type of metrics %+v", t)
- }
- }
- func (daemon *Daemon) statsV1(s *types.StatsJSON, stats *statsV1.Metrics) (*types.StatsJSON, error) {
- if stats.Blkio != nil {
- s.BlkioStats = types.BlkioStats{
- IoServiceBytesRecursive: copyBlkioEntry(stats.Blkio.IoServiceBytesRecursive),
- IoServicedRecursive: copyBlkioEntry(stats.Blkio.IoServicedRecursive),
- IoQueuedRecursive: copyBlkioEntry(stats.Blkio.IoQueuedRecursive),
- IoServiceTimeRecursive: copyBlkioEntry(stats.Blkio.IoServiceTimeRecursive),
- IoWaitTimeRecursive: copyBlkioEntry(stats.Blkio.IoWaitTimeRecursive),
- IoMergedRecursive: copyBlkioEntry(stats.Blkio.IoMergedRecursive),
- IoTimeRecursive: copyBlkioEntry(stats.Blkio.IoTimeRecursive),
- SectorsRecursive: copyBlkioEntry(stats.Blkio.SectorsRecursive),
- }
- }
- if stats.CPU != nil {
- s.CPUStats = types.CPUStats{
- CPUUsage: types.CPUUsage{
- TotalUsage: stats.CPU.Usage.Total,
- PercpuUsage: stats.CPU.Usage.PerCPU,
- UsageInKernelmode: stats.CPU.Usage.Kernel,
- UsageInUsermode: stats.CPU.Usage.User,
- },
- ThrottlingData: types.ThrottlingData{
- Periods: stats.CPU.Throttling.Periods,
- ThrottledPeriods: stats.CPU.Throttling.ThrottledPeriods,
- ThrottledTime: stats.CPU.Throttling.ThrottledTime,
- },
- }
- }
- if stats.Memory != nil {
- raw := map[string]uint64{
- "cache": stats.Memory.Cache,
- "rss": stats.Memory.RSS,
- "rss_huge": stats.Memory.RSSHuge,
- "mapped_file": stats.Memory.MappedFile,
- "dirty": stats.Memory.Dirty,
- "writeback": stats.Memory.Writeback,
- "pgpgin": stats.Memory.PgPgIn,
- "pgpgout": stats.Memory.PgPgOut,
- "pgfault": stats.Memory.PgFault,
- "pgmajfault": stats.Memory.PgMajFault,
- "inactive_anon": stats.Memory.InactiveAnon,
- "active_anon": stats.Memory.ActiveAnon,
- "inactive_file": stats.Memory.InactiveFile,
- "active_file": stats.Memory.ActiveFile,
- "unevictable": stats.Memory.Unevictable,
- "hierarchical_memory_limit": stats.Memory.HierarchicalMemoryLimit,
- "hierarchical_memsw_limit": stats.Memory.HierarchicalSwapLimit,
- "total_cache": stats.Memory.TotalCache,
- "total_rss": stats.Memory.TotalRSS,
- "total_rss_huge": stats.Memory.TotalRSSHuge,
- "total_mapped_file": stats.Memory.TotalMappedFile,
- "total_dirty": stats.Memory.TotalDirty,
- "total_writeback": stats.Memory.TotalWriteback,
- "total_pgpgin": stats.Memory.TotalPgPgIn,
- "total_pgpgout": stats.Memory.TotalPgPgOut,
- "total_pgfault": stats.Memory.TotalPgFault,
- "total_pgmajfault": stats.Memory.TotalPgMajFault,
- "total_inactive_anon": stats.Memory.TotalInactiveAnon,
- "total_active_anon": stats.Memory.TotalActiveAnon,
- "total_inactive_file": stats.Memory.TotalInactiveFile,
- "total_active_file": stats.Memory.TotalActiveFile,
- "total_unevictable": stats.Memory.TotalUnevictable,
- }
- if stats.Memory.Usage != nil {
- s.MemoryStats = types.MemoryStats{
- Stats: raw,
- Usage: stats.Memory.Usage.Usage,
- MaxUsage: stats.Memory.Usage.Max,
- Limit: stats.Memory.Usage.Limit,
- Failcnt: stats.Memory.Usage.Failcnt,
- }
- } else {
- s.MemoryStats = types.MemoryStats{
- Stats: raw,
- }
- }
- // if the container does not set memory limit, use the machineMemory
- if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
- s.MemoryStats.Limit = daemon.machineMemory
- }
- }
- if stats.Pids != nil {
- s.PidsStats = types.PidsStats{
- Current: stats.Pids.Current,
- Limit: stats.Pids.Limit,
- }
- }
- return s, nil
- }
- func (daemon *Daemon) statsV2(s *types.StatsJSON, stats *statsV2.Metrics) (*types.StatsJSON, error) {
- if stats.Io != nil {
- var isbr []types.BlkioStatEntry
- for _, re := range stats.Io.Usage {
- isbr = append(isbr,
- types.BlkioStatEntry{
- Major: re.Major,
- Minor: re.Minor,
- Op: "read",
- Value: re.Rbytes,
- },
- types.BlkioStatEntry{
- Major: re.Major,
- Minor: re.Minor,
- Op: "write",
- Value: re.Wbytes,
- },
- )
- }
- s.BlkioStats = types.BlkioStats{
- IoServiceBytesRecursive: isbr,
- // Other fields are unsupported
- }
- }
- if stats.CPU != nil {
- s.CPUStats = types.CPUStats{
- CPUUsage: types.CPUUsage{
- TotalUsage: stats.CPU.UsageUsec * 1000,
- // PercpuUsage is not supported
- UsageInKernelmode: stats.CPU.SystemUsec * 1000,
- UsageInUsermode: stats.CPU.UserUsec * 1000,
- },
- ThrottlingData: types.ThrottlingData{
- Periods: stats.CPU.NrPeriods,
- ThrottledPeriods: stats.CPU.NrThrottled,
- ThrottledTime: stats.CPU.ThrottledUsec * 1000,
- },
- }
- }
- if stats.Memory != nil {
- s.MemoryStats = types.MemoryStats{
- // Stats is not compatible with v1
- Stats: map[string]uint64{
- "anon": stats.Memory.Anon,
- "file": stats.Memory.File,
- "kernel_stack": stats.Memory.KernelStack,
- "slab": stats.Memory.Slab,
- "sock": stats.Memory.Sock,
- "shmem": stats.Memory.Shmem,
- "file_mapped": stats.Memory.FileMapped,
- "file_dirty": stats.Memory.FileDirty,
- "file_writeback": stats.Memory.FileWriteback,
- "anon_thp": stats.Memory.AnonThp,
- "inactive_anon": stats.Memory.InactiveAnon,
- "active_anon": stats.Memory.ActiveAnon,
- "inactive_file": stats.Memory.InactiveFile,
- "active_file": stats.Memory.ActiveFile,
- "unevictable": stats.Memory.Unevictable,
- "slab_reclaimable": stats.Memory.SlabReclaimable,
- "slab_unreclaimable": stats.Memory.SlabUnreclaimable,
- "pgfault": stats.Memory.Pgfault,
- "pgmajfault": stats.Memory.Pgmajfault,
- "workingset_refault": stats.Memory.WorkingsetRefault,
- "workingset_activate": stats.Memory.WorkingsetActivate,
- "workingset_nodereclaim": stats.Memory.WorkingsetNodereclaim,
- "pgrefill": stats.Memory.Pgrefill,
- "pgscan": stats.Memory.Pgscan,
- "pgsteal": stats.Memory.Pgsteal,
- "pgactivate": stats.Memory.Pgactivate,
- "pgdeactivate": stats.Memory.Pgdeactivate,
- "pglazyfree": stats.Memory.Pglazyfree,
- "pglazyfreed": stats.Memory.Pglazyfreed,
- "thp_fault_alloc": stats.Memory.ThpFaultAlloc,
- "thp_collapse_alloc": stats.Memory.ThpCollapseAlloc,
- },
- Usage: stats.Memory.Usage,
- // MaxUsage is not supported
- Limit: stats.Memory.UsageLimit,
- }
- // if the container does not set memory limit, use the machineMemory
- if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
- s.MemoryStats.Limit = daemon.machineMemory
- }
- if stats.MemoryEvents != nil {
- // Failcnt is set to the "oom" field of the "memory.events" file.
- // See https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
- s.MemoryStats.Failcnt = stats.MemoryEvents.Oom
- }
- }
- if stats.Pids != nil {
- s.PidsStats = types.PidsStats{
- Current: stats.Pids.Current,
- Limit: stats.Pids.Limit,
- }
- }
- return s, nil
- }
- // Resolve Network SandboxID in case the container reuse another container's network stack
- func (daemon *Daemon) getNetworkSandboxID(c *container.Container) (string, error) {
- curr := c
- for curr.HostConfig.NetworkMode.IsContainer() {
- containerID := curr.HostConfig.NetworkMode.ConnectedContainer()
- connected, err := daemon.GetContainer(containerID)
- if err != nil {
- return "", errors.Wrapf(err, "Could not get container for %s", containerID)
- }
- curr = connected
- }
- return curr.NetworkSettings.SandboxID, nil
- }
- func (daemon *Daemon) getNetworkStats(c *container.Container) (map[string]types.NetworkStats, error) {
- sandboxID, err := daemon.getNetworkSandboxID(c)
- if err != nil {
- return nil, err
- }
- sb, err := daemon.netController.SandboxByID(sandboxID)
- if err != nil {
- return nil, err
- }
- lnstats, err := sb.Statistics()
- if err != nil {
- return nil, err
- }
- stats := make(map[string]types.NetworkStats)
- // Convert libnetwork nw stats into api stats
- for ifName, ifStats := range lnstats {
- stats[ifName] = types.NetworkStats{
- RxBytes: ifStats.RxBytes,
- RxPackets: ifStats.RxPackets,
- RxErrors: ifStats.RxErrors,
- RxDropped: ifStats.RxDropped,
- TxBytes: ifStats.TxBytes,
- TxPackets: ifStats.TxPackets,
- TxErrors: ifStats.TxErrors,
- TxDropped: ifStats.TxDropped,
- }
- }
- return stats, nil
- }
|