Use runc events --stats for collecting stats
runc `events --stats` now has stable output so we don't need to bind to libcontainer directly to get stats output for the containers. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
c2df6e08cf
commit
9ed8422e8c
4 changed files with 121 additions and 63 deletions
|
@ -17,8 +17,6 @@ import (
|
||||||
"github.com/docker/containerd/runtime"
|
"github.com/docker/containerd/runtime"
|
||||||
"github.com/docker/containerd/specs"
|
"github.com/docker/containerd/specs"
|
||||||
"github.com/docker/containerd/supervisor"
|
"github.com/docker/containerd/supervisor"
|
||||||
"github.com/opencontainers/runc/libcontainer"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/system"
|
"github.com/opencontainers/runc/libcontainer/system"
|
||||||
ocs "github.com/opencontainers/runtime-spec/specs-go"
|
ocs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
@ -368,75 +366,68 @@ func convertToPb(st *runtime.Stat) *types.StatsResponse {
|
||||||
Timestamp: uint64(st.Timestamp.Unix()),
|
Timestamp: uint64(st.Timestamp.Unix()),
|
||||||
CgroupStats: &types.CgroupStats{},
|
CgroupStats: &types.CgroupStats{},
|
||||||
}
|
}
|
||||||
lcSt, ok := st.Data.(*libcontainer.Stats)
|
|
||||||
if !ok {
|
|
||||||
return pbSt
|
|
||||||
}
|
|
||||||
cpuSt := lcSt.CgroupStats.CpuStats
|
|
||||||
systemUsage, _ := getSystemCPUUsage()
|
systemUsage, _ := getSystemCPUUsage()
|
||||||
pbSt.CgroupStats.CpuStats = &types.CpuStats{
|
pbSt.CgroupStats.CpuStats = &types.CpuStats{
|
||||||
CpuUsage: &types.CpuUsage{
|
CpuUsage: &types.CpuUsage{
|
||||||
TotalUsage: cpuSt.CpuUsage.TotalUsage,
|
TotalUsage: st.Cpu.Usage.Total,
|
||||||
PercpuUsage: cpuSt.CpuUsage.PercpuUsage,
|
PercpuUsage: st.Cpu.Usage.Percpu,
|
||||||
UsageInKernelmode: cpuSt.CpuUsage.UsageInKernelmode,
|
UsageInKernelmode: st.Cpu.Usage.Kernel,
|
||||||
UsageInUsermode: cpuSt.CpuUsage.UsageInUsermode,
|
UsageInUsermode: st.Cpu.Usage.User,
|
||||||
},
|
},
|
||||||
ThrottlingData: &types.ThrottlingData{
|
ThrottlingData: &types.ThrottlingData{
|
||||||
Periods: cpuSt.ThrottlingData.Periods,
|
Periods: st.Cpu.Throttling.Periods,
|
||||||
ThrottledPeriods: cpuSt.ThrottlingData.ThrottledPeriods,
|
ThrottledPeriods: st.Cpu.Throttling.ThrottledPeriods,
|
||||||
ThrottledTime: cpuSt.ThrottlingData.ThrottledTime,
|
ThrottledTime: st.Cpu.Throttling.ThrottledTime,
|
||||||
},
|
},
|
||||||
SystemUsage: systemUsage,
|
SystemUsage: systemUsage,
|
||||||
}
|
}
|
||||||
memSt := lcSt.CgroupStats.MemoryStats
|
|
||||||
pbSt.CgroupStats.MemoryStats = &types.MemoryStats{
|
pbSt.CgroupStats.MemoryStats = &types.MemoryStats{
|
||||||
Cache: memSt.Cache,
|
Cache: st.Memory.Cache,
|
||||||
Usage: &types.MemoryData{
|
Usage: &types.MemoryData{
|
||||||
Usage: memSt.Usage.Usage,
|
Usage: st.Memory.Usage.Usage,
|
||||||
MaxUsage: memSt.Usage.MaxUsage,
|
MaxUsage: st.Memory.Usage.Max,
|
||||||
Failcnt: memSt.Usage.Failcnt,
|
Failcnt: st.Memory.Usage.Failcnt,
|
||||||
Limit: memSt.Usage.Limit,
|
Limit: st.Memory.Usage.Limit,
|
||||||
},
|
},
|
||||||
SwapUsage: &types.MemoryData{
|
SwapUsage: &types.MemoryData{
|
||||||
Usage: memSt.SwapUsage.Usage,
|
Usage: st.Memory.Swap.Usage,
|
||||||
MaxUsage: memSt.SwapUsage.MaxUsage,
|
MaxUsage: st.Memory.Swap.Max,
|
||||||
Failcnt: memSt.SwapUsage.Failcnt,
|
Failcnt: st.Memory.Swap.Failcnt,
|
||||||
Limit: memSt.SwapUsage.Limit,
|
Limit: st.Memory.Swap.Limit,
|
||||||
},
|
},
|
||||||
KernelUsage: &types.MemoryData{
|
KernelUsage: &types.MemoryData{
|
||||||
Usage: memSt.KernelUsage.Usage,
|
Usage: st.Memory.Kernel.Usage,
|
||||||
MaxUsage: memSt.KernelUsage.MaxUsage,
|
MaxUsage: st.Memory.Kernel.Max,
|
||||||
Failcnt: memSt.KernelUsage.Failcnt,
|
Failcnt: st.Memory.Kernel.Failcnt,
|
||||||
Limit: memSt.KernelUsage.Limit,
|
Limit: st.Memory.Kernel.Limit,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
blkSt := lcSt.CgroupStats.BlkioStats
|
|
||||||
pbSt.CgroupStats.BlkioStats = &types.BlkioStats{
|
pbSt.CgroupStats.BlkioStats = &types.BlkioStats{
|
||||||
IoServiceBytesRecursive: convertBlkioEntryToPb(blkSt.IoServiceBytesRecursive),
|
IoServiceBytesRecursive: convertBlkioEntryToPb(st.Blkio.IoServiceBytesRecursive),
|
||||||
IoServicedRecursive: convertBlkioEntryToPb(blkSt.IoServicedRecursive),
|
IoServicedRecursive: convertBlkioEntryToPb(st.Blkio.IoServicedRecursive),
|
||||||
IoQueuedRecursive: convertBlkioEntryToPb(blkSt.IoQueuedRecursive),
|
IoQueuedRecursive: convertBlkioEntryToPb(st.Blkio.IoQueuedRecursive),
|
||||||
IoServiceTimeRecursive: convertBlkioEntryToPb(blkSt.IoServiceTimeRecursive),
|
IoServiceTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoServiceTimeRecursive),
|
||||||
IoWaitTimeRecursive: convertBlkioEntryToPb(blkSt.IoWaitTimeRecursive),
|
IoWaitTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoWaitTimeRecursive),
|
||||||
IoMergedRecursive: convertBlkioEntryToPb(blkSt.IoMergedRecursive),
|
IoMergedRecursive: convertBlkioEntryToPb(st.Blkio.IoMergedRecursive),
|
||||||
IoTimeRecursive: convertBlkioEntryToPb(blkSt.IoTimeRecursive),
|
IoTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoTimeRecursive),
|
||||||
SectorsRecursive: convertBlkioEntryToPb(blkSt.SectorsRecursive),
|
SectorsRecursive: convertBlkioEntryToPb(st.Blkio.SectorsRecursive),
|
||||||
}
|
}
|
||||||
pbSt.CgroupStats.HugetlbStats = make(map[string]*types.HugetlbStats)
|
pbSt.CgroupStats.HugetlbStats = make(map[string]*types.HugetlbStats)
|
||||||
for k, st := range lcSt.CgroupStats.HugetlbStats {
|
for k, st := range st.Hugetlb {
|
||||||
pbSt.CgroupStats.HugetlbStats[k] = &types.HugetlbStats{
|
pbSt.CgroupStats.HugetlbStats[k] = &types.HugetlbStats{
|
||||||
Usage: st.Usage,
|
Usage: st.Usage,
|
||||||
MaxUsage: st.MaxUsage,
|
MaxUsage: st.Max,
|
||||||
Failcnt: st.Failcnt,
|
Failcnt: st.Failcnt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pbSt.CgroupStats.PidsStats = &types.PidsStats{
|
pbSt.CgroupStats.PidsStats = &types.PidsStats{
|
||||||
Current: lcSt.CgroupStats.PidsStats.Current,
|
Current: st.Pids.Current,
|
||||||
Limit: lcSt.CgroupStats.PidsStats.Limit,
|
Limit: st.Pids.Limit,
|
||||||
}
|
}
|
||||||
return pbSt
|
return pbSt
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertBlkioEntryToPb(b []cgroups.BlkioStatEntry) []*types.BlkioStatsEntry {
|
func convertBlkioEntryToPb(b []runtime.BlkioEntry) []*types.BlkioStatsEntry {
|
||||||
var pbEs []*types.BlkioStatsEntry
|
var pbEs []*types.BlkioStatsEntry
|
||||||
for _, e := range b {
|
for _, e := range b {
|
||||||
pbEs = append(pbEs, &types.BlkioStatsEntry{
|
pbEs = append(pbEs, &types.BlkioStatsEntry{
|
||||||
|
|
|
@ -523,7 +523,7 @@ func hostIDFromMap(id uint32, mp []ocs.IDMapping) int {
|
||||||
func (c *container) Pids() ([]int, error) {
|
func (c *container) Pids() ([]int, error) {
|
||||||
out, err := exec.Command(c.runtime, "ps", "--format=json", c.id).CombinedOutput()
|
out, err := exec.Command(c.runtime, "ps", "--format=json", c.id).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(string(out))
|
return nil, fmt.Errorf("%s", out)
|
||||||
}
|
}
|
||||||
var pids []int
|
var pids []int
|
||||||
if err := json.Unmarshal(out, &pids); err != nil {
|
if err := json.Unmarshal(out, &pids); err != nil {
|
||||||
|
@ -533,19 +533,19 @@ func (c *container) Pids() ([]int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *container) Stats() (*Stat, error) {
|
func (c *container) Stats() (*Stat, error) {
|
||||||
container, err := c.getLibctContainer()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
stats, err := container.Stats()
|
out, err := exec.Command(c.runtime, "events", "--stats", c.id).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s", out)
|
||||||
|
}
|
||||||
|
s := struct {
|
||||||
|
Data *Stat `json:"data"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(out, &s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Stat{
|
s.Data.Timestamp = now
|
||||||
Timestamp: now,
|
return s.Data, nil
|
||||||
Data: stats,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *container) OOM() (OOM, error) {
|
func (c *container) OOM() (OOM, error) {
|
||||||
|
@ -575,7 +575,7 @@ func (c *container) Status() (State, error) {
|
||||||
|
|
||||||
out, err := exec.Command(c.runtime, args...).CombinedOutput()
|
out, err := exec.Command(c.runtime, args...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(string(out))
|
return "", fmt.Errorf("%s", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only require the runtime json output to have a top level Status field.
|
// We only require the runtime json output to have a top level Status field.
|
||||||
|
|
|
@ -97,13 +97,3 @@ type ProcessState struct {
|
||||||
|
|
||||||
PlatformProcessState
|
PlatformProcessState
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stat struct {
|
|
||||||
// Timestamp is the time that the statistics where collected
|
|
||||||
Timestamp time.Time
|
|
||||||
// Data is the raw stats
|
|
||||||
// TODO: it is currently an interface because we don't know what type of exec drivers
|
|
||||||
// we will have or what the structure should look like at the moment os the containers
|
|
||||||
// can return what they want and we could marshal to json or whatever.
|
|
||||||
Data interface{}
|
|
||||||
}
|
|
||||||
|
|
77
runtime/stats.go
Normal file
77
runtime/stats.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Stat struct {
|
||||||
|
// Timestamp is the time that the statistics where collected
|
||||||
|
Timestamp time.Time
|
||||||
|
Cpu Cpu `json:"cpu"`
|
||||||
|
Memory Memory `json:"memory"`
|
||||||
|
Pids Pids `json:"pids"`
|
||||||
|
Blkio Blkio `json:"blkio"`
|
||||||
|
Hugetlb map[string]Hugetlb `json:"hugetlb"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hugetlb struct {
|
||||||
|
Usage uint64 `json:"usage,omitempty"`
|
||||||
|
Max uint64 `json:"max,omitempty"`
|
||||||
|
Failcnt uint64 `json:"failcnt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlkioEntry struct {
|
||||||
|
Major uint64 `json:"major,omitempty"`
|
||||||
|
Minor uint64 `json:"minor,omitempty"`
|
||||||
|
Op string `json:"op,omitempty"`
|
||||||
|
Value uint64 `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Blkio struct {
|
||||||
|
IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"`
|
||||||
|
IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"`
|
||||||
|
IoQueuedRecursive []BlkioEntry `json:"ioQueueRecursive,omitempty"`
|
||||||
|
IoServiceTimeRecursive []BlkioEntry `json:"ioServiceTimeRecursive,omitempty"`
|
||||||
|
IoWaitTimeRecursive []BlkioEntry `json:"ioWaitTimeRecursive,omitempty"`
|
||||||
|
IoMergedRecursive []BlkioEntry `json:"ioMergedRecursive,omitempty"`
|
||||||
|
IoTimeRecursive []BlkioEntry `json:"ioTimeRecursive,omitempty"`
|
||||||
|
SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pids struct {
|
||||||
|
Current uint64 `json:"current,omitempty"`
|
||||||
|
Limit uint64 `json:"limit,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Throttling struct {
|
||||||
|
Periods uint64 `json:"periods,omitempty"`
|
||||||
|
ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"`
|
||||||
|
ThrottledTime uint64 `json:"throttledTime,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CpuUsage struct {
|
||||||
|
// Units: nanoseconds.
|
||||||
|
Total uint64 `json:"total,omitempty"`
|
||||||
|
Percpu []uint64 `json:"percpu,omitempty"`
|
||||||
|
Kernel uint64 `json:"kernel"`
|
||||||
|
User uint64 `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cpu struct {
|
||||||
|
Usage CpuUsage `json:"usage,omitempty"`
|
||||||
|
Throttling Throttling `json:"throttling,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemoryEntry struct {
|
||||||
|
Limit uint64 `json:"limit"`
|
||||||
|
Usage uint64 `json:"usage,omitempty"`
|
||||||
|
Max uint64 `json:"max,omitempty"`
|
||||||
|
Failcnt uint64 `json:"failcnt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Memory struct {
|
||||||
|
Cache uint64 `json:"cache,omitempty"`
|
||||||
|
Usage MemoryEntry `json:"usage,omitempty"`
|
||||||
|
Swap MemoryEntry `json:"swap,omitempty"`
|
||||||
|
Kernel MemoryEntry `json:"kernel,omitempty"`
|
||||||
|
KernelTCP MemoryEntry `json:"kernelTCP,omitempty"`
|
||||||
|
Raw map[string]uint64 `json:"raw,omitempty"`
|
||||||
|
}
|
Loading…
Reference in a new issue