Skip to content

Commit cb1cdb3

Browse files
committed
feature: add features about stats of cri manager
Signed-off-by: Starnop <[email protected]>
1 parent b58ff0c commit cb1cdb3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+10899
-36
lines changed

cri/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package config
22

3+
const (
4+
// K8sNamespace is the namespace we use to connect containerd when CRI is enabled.
5+
K8sNamespace = "k8s.io"
6+
)
7+
38
// Config defines the CRI configuration.
49
type Config struct {
510
// Listen is the listening address which servers CRI.

cri/v1alpha1/cri.go

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ const (
6161

6262
// resolvConfPath is the abs path of resolv.conf on host or container.
6363
resolvConfPath = "/etc/resolv.conf"
64+
65+
// statsCollectPeriod is the time duration (in time.Second) we sync stats from containerd.
66+
statsCollectPeriod = 10
67+
68+
// defaultSnapshotterName is the default Snapshotter name.
69+
defaultSnapshotterName = "overlayfs"
70+
71+
// snapshotPlugin implements a snapshotter.
72+
snapshotPlugin = "io.containerd.snapshotter.v1"
6473
)
6574

6675
var (
@@ -96,6 +105,12 @@ type CriManager struct {
96105
SandboxImage string
97106
// SandboxStore stores the configuration of sandboxes.
98107
SandboxStore *meta.Store
108+
109+
// SnapshotStore stores information of all snapshots.
110+
SnapshotStore *mgr.SnapshotStore
111+
112+
// ImageFSUUID is the device uuid of image filesystem.
113+
ImageFSUUID string
99114
}
100115

101116
// NewCriManager creates a brand new cri manager.
@@ -112,6 +127,7 @@ func NewCriManager(config *config.Config, ctrMgr mgr.ContainerMgr, imgMgr mgr.Im
112127
StreamServer: streamServer,
113128
SandboxBaseDir: path.Join(config.HomeDir, "sandboxes"),
114129
SandboxImage: config.CriConfig.SandboxImage,
130+
SnapshotStore: mgr.NewSnapshotStore(),
115131
}
116132

117133
c.SandboxStore, err = meta.NewStore(meta.Config{
@@ -128,6 +144,18 @@ func NewCriManager(config *config.Config, ctrMgr mgr.ContainerMgr, imgMgr mgr.Im
128144
return nil, fmt.Errorf("failed to create sandbox meta store: %v", err)
129145
}
130146

147+
imageFSPath := imageFSPath(path.Join(config.HomeDir, "containerd/root"), defaultSnapshotterName)
148+
c.ImageFSUUID, err = getDeviceUUID(imageFSPath)
149+
if err != nil {
150+
return nil, fmt.Errorf("failed to get imagefs uuid of %q: %v", imageFSPath, err)
151+
}
152+
153+
snapshotsSyncer := ctrMgr.NewSnapshotsSyncer(
154+
c.SnapshotStore,
155+
time.Duration(statsCollectPeriod)*time.Second,
156+
)
157+
snapshotsSyncer.Start()
158+
131159
return NewCriWrapper(c), nil
132160
}
133161

@@ -709,12 +737,46 @@ func (c *CriManager) ContainerStatus(ctx context.Context, r *runtime.ContainerSt
709737
// ContainerStats returns stats of the container. If the container does not
710738
// exist, the call returns an error.
711739
func (c *CriManager) ContainerStats(ctx context.Context, r *runtime.ContainerStatsRequest) (*runtime.ContainerStatsResponse, error) {
712-
return nil, fmt.Errorf("ContainerStats Not Implemented Yet")
740+
containerID := r.GetContainerId()
741+
742+
container, err := c.ContainerMgr.Get(ctx, containerID)
743+
if err != nil {
744+
return nil, fmt.Errorf("failed to get container %q with error: %v", containerID, err)
745+
}
746+
747+
cs, err := c.getContainerMetrics(ctx, container)
748+
if err != nil {
749+
return nil, fmt.Errorf("failed to decode container metrics: %v", err)
750+
}
751+
752+
return &runtime.ContainerStatsResponse{Stats: cs}, nil
713753
}
714754

715755
// ListContainerStats returns stats of all running containers.
716756
func (c *CriManager) ListContainerStats(ctx context.Context, r *runtime.ListContainerStatsRequest) (*runtime.ListContainerStatsResponse, error) {
717-
return nil, fmt.Errorf("ListContainerStats Not Implemented Yet")
757+
opts := &mgr.ContainerListOption{All: true}
758+
filter := func(c *mgr.Container) bool {
759+
return true
760+
}
761+
opts.FilterFunc = filter
762+
763+
containers, err := c.ContainerMgr.List(ctx, opts)
764+
if err != nil {
765+
return nil, fmt.Errorf("failed to list containers: %v", err)
766+
}
767+
768+
result := &runtime.ListContainerStatsResponse{}
769+
for _, container := range containers {
770+
cs, err := c.getContainerMetrics(ctx, container)
771+
if err != nil {
772+
logrus.Errorf("failed to decode metrics of container %q: %v", container.ID, err)
773+
continue
774+
}
775+
776+
result.Stats = append(result.Stats, cs)
777+
}
778+
779+
return result, nil
718780
}
719781

720782
// UpdateContainerResources updates ContainerConfig of the container.
@@ -962,5 +1024,25 @@ func (c *CriManager) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequ
9621024

9631025
// ImageFsInfo returns information of the filesystem that is used to store images.
9641026
func (c *CriManager) ImageFsInfo(ctx context.Context, r *runtime.ImageFsInfoRequest) (*runtime.ImageFsInfoResponse, error) {
965-
return nil, fmt.Errorf("ImageFsInfo Not Implemented Yet")
1027+
snapshots := c.SnapshotStore.List()
1028+
timestamp := time.Now().UnixNano()
1029+
var usedBytes, inodesUsed uint64
1030+
for _, sn := range snapshots {
1031+
// Use the oldest timestamp as the timestamp of imagefs info.
1032+
if sn.Timestamp < timestamp {
1033+
timestamp = sn.Timestamp
1034+
}
1035+
usedBytes += sn.Size
1036+
inodesUsed += sn.Inodes
1037+
}
1038+
return &runtime.ImageFsInfoResponse{
1039+
ImageFilesystems: []*runtime.FilesystemUsage{
1040+
{
1041+
Timestamp: timestamp,
1042+
StorageId: &runtime.StorageIdentifier{Uuid: c.ImageFSUUID},
1043+
UsedBytes: &runtime.UInt64Value{Value: usedBytes},
1044+
InodesUsed: &runtime.UInt64Value{Value: inodesUsed},
1045+
},
1046+
},
1047+
}, nil
9661048
}

cri/v1alpha1/cri_utils.go

Lines changed: 163 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,28 @@ import (
77
"io/ioutil"
88
"os"
99
"path"
10+
"path/filepath"
1011
"strconv"
1112
"strings"
13+
"syscall"
1214
"time"
1315

1416
apitypes "github.com/alibaba/pouch/apis/types"
1517
anno "github.com/alibaba/pouch/cri/annotations"
1618
"github.com/alibaba/pouch/daemon/mgr"
1719
"github.com/alibaba/pouch/pkg/utils"
18-
"github.com/go-openapi/strfmt"
1920

21+
"github.com/containerd/cgroups"
22+
containerdmount "github.com/containerd/containerd/mount"
23+
"github.com/containerd/typeurl"
24+
"github.com/go-openapi/strfmt"
2025
"golang.org/x/net/context"
26+
"golang.org/x/sys/unix"
2127
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
2228
)
2329

30+
const uuidDir = "/dev/disk/by-uuid"
31+
2432
func parseUint32(s string) (uint32, error) {
2533
n, err := strconv.ParseUint(s, 10, 32)
2634
if err != nil {
@@ -265,6 +273,10 @@ func makeSandboxPouchConfig(config *runtime.PodSandboxConfig, image string) (*ap
265273
return nil, err
266274
}
267275

276+
// Apply resource options.
277+
if lc := config.GetLinux(); lc != nil {
278+
hc.CgroupParent = lc.CgroupParent
279+
}
268280
return createConfig, nil
269281
}
270282

@@ -284,11 +296,17 @@ func toCriSandbox(c *mgr.Container) (*runtime.PodSandbox, error) {
284296
return nil, err
285297
}
286298
labels, annotations := extractLabels(c.Config.Labels)
299+
300+
createdAt, err := toCriTimestamp(c.Created)
301+
if err != nil {
302+
return nil, fmt.Errorf("failed to parse create timestamp for container %q: %v", c.ID, err)
303+
}
304+
287305
return &runtime.PodSandbox{
288-
Id: c.ID,
289-
Metadata: metadata,
290-
State: state,
291-
// TODO: fill "CreatedAt" when it is appropriate.
306+
Id: c.ID,
307+
Metadata: metadata,
308+
State: state,
309+
CreatedAt: createdAt,
292310
Labels: labels,
293311
Annotations: annotations,
294312
}, nil
@@ -625,15 +643,26 @@ func (c *CriManager) updateCreateConfig(createConfig *apitypes.ContainerCreateCo
625643
}
626644

627645
if lc := config.GetLinux(); lc != nil {
628-
// TODO: resource restriction.
646+
resources := lc.GetResources()
647+
if resources != nil {
648+
createConfig.HostConfig.Resources.CPUPeriod = resources.GetCpuPeriod()
649+
createConfig.HostConfig.Resources.CPUQuota = resources.GetCpuQuota()
650+
createConfig.HostConfig.Resources.CPUShares = resources.GetCpuShares()
651+
createConfig.HostConfig.Resources.Memory = resources.GetMemoryLimitInBytes()
652+
createConfig.HostConfig.Resources.CpusetCpus = resources.GetCpusetCpus()
653+
createConfig.HostConfig.Resources.CpusetMems = resources.GetCpusetMems()
654+
}
629655

630656
// Apply security context.
631657
if err := applyContainerSecurityContext(lc, podSandboxID, &createConfig.ContainerConfig, createConfig.HostConfig); err != nil {
632658
return fmt.Errorf("failed to apply container security context for container %q: %v", config.Metadata.Name, err)
633659
}
634660
}
635661

636-
// TODO: apply cgroupParent derived from the sandbox config.
662+
// Apply cgroupsParent derived from the sandbox config.
663+
if sandboxConfig.GetLinux().GetCgroupParent() != "" {
664+
createConfig.HostConfig.CgroupParent = sandboxConfig.GetLinux().GetCgroupParent()
665+
}
637666

638667
return nil
639668
}
@@ -660,16 +689,20 @@ func toCriContainer(c *mgr.Container) (*runtime.Container, error) {
660689
labels, annotations := extractLabels(c.Config.Labels)
661690
sandboxID := c.Config.Labels[sandboxIDLabelKey]
662691

692+
createdAt, err := toCriTimestamp(c.Created)
693+
if err != nil {
694+
return nil, fmt.Errorf("failed to parse create timestamp for container %q: %v", c.ID, err)
695+
}
663696
return &runtime.Container{
664697
Id: c.ID,
665698
PodSandboxId: sandboxID,
666699
Metadata: metadata,
667700
Image: &runtime.ImageSpec{Image: c.Config.Image},
668701
ImageRef: c.Image,
669702
State: state,
670-
// TODO: fill "CreatedAt" when it is appropriate.
671-
Labels: labels,
672-
Annotations: annotations,
703+
CreatedAt: createdAt,
704+
Labels: labels,
705+
Annotations: annotations,
673706
}, nil
674707
}
675708

@@ -787,3 +820,123 @@ func parseUserFromImageUser(id string) string {
787820
// no group, just return the id
788821
return id
789822
}
823+
824+
func (c *CriManager) getContainerMetrics(ctx context.Context, meta *mgr.Container) (*runtime.ContainerStats, error) {
825+
var usedBytes, inodesUsed uint64
826+
827+
stats, err := c.ContainerMgr.Stats(ctx, meta.ID)
828+
if err != nil {
829+
return nil, fmt.Errorf("failed to get stats of container %q: %v", meta.ID, err)
830+
}
831+
832+
// snapshot key may not equals container ID later
833+
sn, err := c.SnapshotStore.Get(meta.ID)
834+
if err == nil {
835+
usedBytes = sn.Size
836+
inodesUsed = sn.Inodes
837+
}
838+
839+
cs := &runtime.ContainerStats{}
840+
cs.WritableLayer = &runtime.FilesystemUsage{
841+
Timestamp: sn.Timestamp,
842+
StorageId: &runtime.StorageIdentifier{
843+
Uuid: c.ImageFSUUID,
844+
},
845+
UsedBytes: &runtime.UInt64Value{usedBytes},
846+
InodesUsed: &runtime.UInt64Value{inodesUsed},
847+
}
848+
849+
metadata, err := parseContainerName(meta.Name)
850+
if err != nil {
851+
return nil, fmt.Errorf("failed to get metadata of container %q: %v", meta.ID, err)
852+
}
853+
854+
labels, annotations := extractLabels(meta.Config.Labels)
855+
856+
cs.Attributes = &runtime.ContainerAttributes{
857+
Id: meta.ID,
858+
Metadata: metadata,
859+
Labels: labels,
860+
Annotations: annotations,
861+
}
862+
863+
if stats != nil {
864+
s, err := typeurl.UnmarshalAny(stats.Data)
865+
if err != nil {
866+
return nil, fmt.Errorf("failed to extract container metrics: %v", err)
867+
}
868+
metrics := s.(*cgroups.Metrics)
869+
if metrics.CPU != nil && metrics.CPU.Usage != nil {
870+
cs.Cpu = &runtime.CpuUsage{
871+
Timestamp: stats.Timestamp.UnixNano(),
872+
UsageCoreNanoSeconds: &runtime.UInt64Value{metrics.CPU.Usage.Total},
873+
}
874+
}
875+
if metrics.Memory != nil && metrics.Memory.Usage != nil {
876+
cs.Memory = &runtime.MemoryUsage{
877+
Timestamp: stats.Timestamp.UnixNano(),
878+
WorkingSetBytes: &runtime.UInt64Value{metrics.Memory.Usage.Usage},
879+
}
880+
}
881+
}
882+
883+
return cs, nil
884+
}
885+
886+
// imageFSPath returns containerd image filesystem path.
887+
func imageFSPath(rootDir, snapshotter string) string {
888+
return filepath.Join(rootDir, fmt.Sprintf("%s.%s", snapshotPlugin, snapshotter))
889+
}
890+
891+
// getDeviceUUID gets device uuid for a given path.
892+
func getDeviceUUID(path string) (string, error) {
893+
mount, err := lookupMount(path)
894+
if err != nil {
895+
return "", err
896+
}
897+
rdev := unix.Mkdev(uint32(mount.Major), uint32(mount.Minor))
898+
return deviceUUID(rdev)
899+
}
900+
901+
// lookupMount gets mount info of a given path.
902+
func lookupMount(path string) (containerdmount.Info, error) {
903+
return containerdmount.Lookup(path)
904+
}
905+
906+
// deviceUUID gets device uuid of a device. The passed in rdev should
907+
// be linux device number.
908+
func deviceUUID(rdev uint64) (string, error) {
909+
files, err := ioutil.ReadDir(uuidDir)
910+
if err != nil {
911+
return "", err
912+
}
913+
for _, file := range files {
914+
path := filepath.Join(uuidDir, file.Name())
915+
916+
trdev, err := blkrdev(path)
917+
if err != nil {
918+
continue
919+
}
920+
921+
if rdev == trdev {
922+
return file.Name(), nil
923+
}
924+
}
925+
926+
return "", fmt.Errorf("device %d not found", rdev)
927+
}
928+
929+
// blkdev returns the rdev of a block device or an error if not a block device
930+
func blkrdev(device string) (uint64, error) {
931+
info, err := os.Stat(device)
932+
if err != nil {
933+
return 0, err
934+
}
935+
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
936+
if (stat.Mode & syscall.S_IFMT) != syscall.S_IFBLK {
937+
return 0, fmt.Errorf("%s is not a block device", device)
938+
}
939+
return stat.Rdev, nil
940+
}
941+
return 0, fmt.Errorf("cannot get stat of device %s", device)
942+
}

cri/v1alpha1/cri_utils_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
apitypes "github.com/alibaba/pouch/apis/types"
1010
"github.com/alibaba/pouch/daemon/mgr"
11+
1112
"github.com/stretchr/testify/assert"
1213
"golang.org/x/net/context"
1314
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"

0 commit comments

Comments
 (0)