Skip to content

Adds whitelisting of docker labels [#1730] #1735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions container/docker/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ type dockerFactory struct {

dockerAPIVersion []int

enforceLabelWhitelist bool
labelWhitelist []string

ignoreMetrics container.MetricSet

thinPoolName string
Expand Down Expand Up @@ -145,6 +148,8 @@ func (self *dockerFactory) NewContainerHandler(name string, inHostNamespace bool
self.thinPoolName,
self.thinPoolWatcher,
self.zfsWatcher,
self.enforceLabelWhitelist,
self.labelWhitelist,
)
return
}
Expand Down Expand Up @@ -309,7 +314,7 @@ func ensureThinLsKernelVersion(kernelVersion string) error {
}

// Register root container before running this function!
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet, enforceLabelWhitelist bool, labelWhiteList []string) error {
client, err := Client()
if err != nil {
return fmt.Errorf("unable to communicate with docker daemon: %v", err)
Expand Down Expand Up @@ -354,18 +359,20 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c

glog.Infof("Registering Docker factory")
f := &dockerFactory{
cgroupSubsystems: cgroupSubsystems,
client: client,
dockerVersion: dockerVersion,
dockerAPIVersion: dockerAPIVersion,
fsInfo: fsInfo,
machineInfoFactory: factory,
storageDriver: storageDriver(dockerInfo.Driver),
storageDir: RootDir(),
ignoreMetrics: ignoreMetrics,
thinPoolName: thinPoolName,
thinPoolWatcher: thinPoolWatcher,
zfsWatcher: zfsWatcher,
cgroupSubsystems: cgroupSubsystems,
client: client,
dockerVersion: dockerVersion,
dockerAPIVersion: dockerAPIVersion,
enforceLabelWhitelist: enforceLabelWhitelist,
labelWhitelist: labelWhiteList,
fsInfo: fsInfo,
machineInfoFactory: factory,
storageDriver: storageDriver(dockerInfo.Driver),
storageDir: RootDir(),
ignoreMetrics: ignoreMetrics,
thinPoolName: thinPoolName,
thinPoolWatcher: thinPoolWatcher,
zfsWatcher: zfsWatcher,
}

container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
Expand Down
84 changes: 62 additions & 22 deletions container/docker/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ type dockerContainerHandler struct {
// Time at which this container was created.
creationTime time.Time

// indicates whether labels should be collected
enforceLabelWhitelist bool

// labels whitelisted for collection
labelWhitelist []string

// Metadata associated with the container.
labels map[string]string
envs map[string]string
Expand Down Expand Up @@ -153,6 +159,8 @@ func newDockerContainerHandler(
thinPoolName string,
thinPoolWatcher *devicemapper.ThinPoolWatcher,
zfsWatcher *zfs.ZfsWatcher,
enforceLabelWhitelist bool,
labelWhitelist []string,
) (container.ContainerHandler, error) {
// Create the cgroup paths.
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
Expand Down Expand Up @@ -208,23 +216,25 @@ func newDockerContainerHandler(

// TODO: extract object mother method
handler := &dockerContainerHandler{
id: id,
client: client,
name: name,
machineInfoFactory: machineInfoFactory,
cgroupPaths: cgroupPaths,
cgroupManager: cgroupManager,
storageDriver: storageDriver,
fsInfo: fsInfo,
rootFs: rootFs,
poolName: thinPoolName,
zfsFilesystem: zfsFilesystem,
rootfsStorageDir: rootfsStorageDir,
envs: make(map[string]string),
ignoreMetrics: ignoreMetrics,
thinPoolWatcher: thinPoolWatcher,
zfsWatcher: zfsWatcher,
zfsParent: zfsParent,
id: id,
client: client,
name: name,
machineInfoFactory: machineInfoFactory,
cgroupPaths: cgroupPaths,
cgroupManager: cgroupManager,
storageDriver: storageDriver,
enforceLabelWhitelist: enforceLabelWhitelist,
labelWhitelist: labelWhitelist,
fsInfo: fsInfo,
rootFs: rootFs,
poolName: thinPoolName,
zfsFilesystem: zfsFilesystem,
rootfsStorageDir: rootfsStorageDir,
envs: make(map[string]string),
ignoreMetrics: ignoreMetrics,
thinPoolWatcher: thinPoolWatcher,
zfsWatcher: zfsWatcher,
zfsParent: zfsParent,
}

// We assume that if Inspect fails then the container is not known to docker.
Expand All @@ -242,7 +252,14 @@ func newDockerContainerHandler(

// Add the name and bare ID as aliases of the container.
handler.aliases = append(handler.aliases, strings.TrimPrefix(ctnr.Name, "/"), id)
handler.labels = ctnr.Config.Labels

if enforceLabelWhitelist {
handler.labels = map[string]string{}
} else {
handler.labels = ctnr.Config.Labels
}

handler.labelWhitelist = labelWhitelist
handler.image = ctnr.Config.Image
handler.networkMode = ctnr.HostConfig.NetworkMode
handler.deviceID = ctnr.GraphDriver.Data["DeviceId"]
Expand Down Expand Up @@ -274,6 +291,15 @@ func newDockerContainerHandler(
}
}

// retrieve desired labels
for _, exposedLabel := range labelWhitelist {
labelValue, present := ctnr.Config.Labels[exposedLabel]
if !present {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: condense this
if labelValue, present := ctnr.Config.Labels[exposedLabel]; present {
handler.labels[exposedLabel] = labelValue
}

continue
}
handler.labels[exposedLabel] = labelValue
}

// split env vars to get metadata map.
for _, exposedEnv := range metadataEnvs {
for _, envVar := range ctnr.Config.Env {
Expand Down Expand Up @@ -382,13 +408,27 @@ func (self *dockerContainerHandler) GetSpec() (info.ContainerSpec, error) {
spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, self.needNet(), hasFilesystem)

spec.Labels = self.labels
// Only adds restartcount label if it's greater than 0
if self.restartCount > 0 {
spec.Labels["restartcount"] = strconv.Itoa(self.restartCount)
}
spec.Envs = self.envs
spec.Image = self.image

// Only adds restartcount label if it's greater than 0 and is
// a whitelisted label in case enforceWhitelist is set.
if self.restartCount < 1 {
return spec, err
}

if self.enforceLabelWhitelist {
for _, label := range self.labelWhitelist {
if label != "restartCount" {
continue
}

spec.Labels["restartcount"] = strconv.Itoa(self.restartCount)
}
} else {
spec.Labels["restartcount"] = strconv.Itoa(self.restartCount)
}

return spec, err
}

Expand Down
20 changes: 13 additions & 7 deletions container/rkt/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ type rktFactory struct {

cgroupSubsystems *libcontainer.CgroupSubsystems

enforceLabelWhitelist bool

labelWhitelist []string

fsInfo fs.FsInfo

ignoreMetrics container.MetricSet
Expand All @@ -54,7 +58,7 @@ func (self *rktFactory) NewContainerHandler(name string, inHostNamespace bool) (
if !inHostNamespace {
rootFs = "/rootfs"
}
return newRktContainerHandler(name, client, self.rktPath, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, rootFs, self.ignoreMetrics)
return newRktContainerHandler(name, client, self.rktPath, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, rootFs, self.ignoreMetrics, self.enforceLabelWhitelist, self.labelWhitelist)
}

func (self *rktFactory) CanHandleAndAccept(name string) (bool, bool, error) {
Expand All @@ -67,7 +71,7 @@ func (self *rktFactory) DebugInfo() map[string][]string {
return map[string][]string{}
}

func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet, enforceLabelWhitelist bool, labelWhiteList []string) error {
_, err := Client()
if err != nil {
return fmt.Errorf("unable to communicate with Rkt api service: %v", err)
Expand All @@ -88,11 +92,13 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, igno

glog.Infof("Registering Rkt factory")
factory := &rktFactory{
machineInfoFactory: machineInfoFactory,
fsInfo: fsInfo,
cgroupSubsystems: &cgroupSubsystems,
ignoreMetrics: ignoreMetrics,
rktPath: rktPath,
machineInfoFactory: machineInfoFactory,
fsInfo: fsInfo,
enforceLabelWhitelist: enforceLabelWhitelist,
labelWhitelist: labelWhiteList,
cgroupSubsystems: &cgroupSubsystems,
ignoreMetrics: ignoreMetrics,
rktPath: rktPath,
}
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Rkt})
return nil
Expand Down
26 changes: 21 additions & 5 deletions container/rkt/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type rktContainerHandler struct {
apiPod *rktapi.Pod
}

func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPath string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, rootFs string, ignoreMetrics container.MetricSet) (container.ContainerHandler, error) {
func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPath string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, rootFs string, ignoreMetrics container.MetricSet, enforceLabelWhitelist bool, labelWhitelist []string) (container.ContainerHandler, error) {
aliases := make([]string, 1)
isPod := false

Expand Down Expand Up @@ -110,7 +110,8 @@ func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPa
pid = int(resp.Pod.Pid)
apiPod = resp.Pod
}
labels = createLabels(annotations)

labels = createLabels(annotations, enforceLabelWhitelist, labelWhitelist)

cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)

Expand Down Expand Up @@ -164,10 +165,25 @@ func findAnnotations(apps []*rktapi.App, container string) ([]*rktapi.KeyValue,
return nil, false
}

func createLabels(annotations []*rktapi.KeyValue) map[string]string {
labels := make(map[string]string)
func createLabels(annotations []*rktapi.KeyValue, enforceLabelWhitelist bool, labelWhitelist []string) map[string]string {
containerLabels := make(map[string]string)

for _, kv := range annotations {
labels[kv.Key] = kv.Value
containerLabels[kv.Key] = kv.Value
}

if !enforceLabelWhitelist {
return containerLabels
}

labels := make(map[string]string)
for _, whitelistedLabel := range labelWhitelist {
label, present := containerLabels[whitelistedLabel]
if !present {
continue
}

labels[whitelistedLabel] = label
}

return labels
Expand Down
10 changes: 10 additions & 0 deletions docs/runtime_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ From [glog](https://github.com/golang/glog) here are some flags we find useful:
--vmodule=: comma-separated list of pattern=N settings for file-filtered logging
```

## Labels

Both Docker and Rkt labels support restricting the amount of labels collected by `cadvisor`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would omit runtimes here as well: " cadvisor can restrict the set of labels it collects from containers. This can be useful in ensuring metrics have a consistent set of labels."


```
--enforce_label_whitelist=false: whether or not to enforce whitelisting of labels
--label_whitelist="": comma-separated list of label keys that are allowed to be collected
```


## Docker

```
Expand Down
8 changes: 6 additions & 2 deletions manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ import (

var globalHousekeepingInterval = flag.Duration("global_housekeeping_interval", 1*time.Minute, "Interval between global housekeepings")
var logCadvisorUsage = flag.Bool("log_cadvisor_usage", false, "Whether to log the usage of the cAdvisor container")
var enforceLabelWhitelist = flag.Bool("enforce_label_whitelist", false, "enforces label whitelisting")
var labelWhitelist = flag.String("label_whitelist", "", "comma-separated list of label keys that are allowed to be collected for docker and rkt containers")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont specify the runtime here: ... "collected for containers"

var eventStorageAgeLimit = flag.String("event_storage_age_limit", "default=24h", "Max length of time for which to store events (per type). Value is a comma separated list of key values, where the keys are event types (e.g.: creation, oom) or \"default\" and the value is a duration. Default is applied to all non-specified event types")
var eventStorageEventLimit = flag.String("event_storage_event_limit", "default=100000", "Max number of events to store (per type). Value is a comma separated list of key values, where the keys are event types (e.g.: creation, oom) or \"default\" and the value is an integer. Default is applied to all non-specified event types")
var applicationMetricsCountLimit = flag.Int("application_metrics_count_limit", 100, "Max number of application metrics to store (per container)")
Expand Down Expand Up @@ -255,12 +257,14 @@ type manager struct {

// Start the container manager.
func (self *manager) Start() error {
err := docker.Register(self, self.fsInfo, self.ignoreMetrics)
labelsWhiteList := strings.Split(*labelWhitelist, ",")

err := docker.Register(self, self.fsInfo, self.ignoreMetrics, *enforceLabelWhitelist, labelsWhiteList)
if err != nil {
glog.Warningf("Docker container factory registration failed: %v.", err)
}

err = rkt.Register(self, self.fsInfo, self.ignoreMetrics)
err = rkt.Register(self, self.fsInfo, self.ignoreMetrics, *enforceLabelWhitelist, labelsWhiteList)
if err != nil {
glog.Warningf("Registration of the rkt container factory failed: %v", err)
} else {
Expand Down