mirror of https://github.com/k3s-io/k3s
Merge pull request #14395 from vishh/kubelet-init
Require cpu and memory cgroups to be mountedpull/6/head
commit
7e42781d40
|
@ -35,7 +35,9 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
"k8s.io/kubernetes/pkg/util/errors"
|
"k8s.io/kubernetes/pkg/util/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
"k8s.io/kubernetes/pkg/util/oom"
|
"k8s.io/kubernetes/pkg/util/oom"
|
||||||
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -70,75 +72,62 @@ func newSystemContainer(containerName string) *systemContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nodeConfig struct {
|
||||||
|
dockerDaemonContainerName string
|
||||||
|
systemContainerName string
|
||||||
|
kubeletContainerName string
|
||||||
|
}
|
||||||
|
|
||||||
type containerManagerImpl struct {
|
type containerManagerImpl struct {
|
||||||
|
cadvisorInterface cadvisor.Interface
|
||||||
|
mountUtil mount.Interface
|
||||||
|
nodeConfig
|
||||||
// External containers being managed.
|
// External containers being managed.
|
||||||
systemContainers []*systemContainer
|
systemContainers []*systemContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ containerManager = &containerManagerImpl{}
|
var _ containerManager = &containerManagerImpl{}
|
||||||
|
|
||||||
|
// checks if the required cgroups subsystems are mounted.
|
||||||
|
// As of now, only 'cpu' and 'memory' are required.
|
||||||
|
func validateSystemRequirements(mountUtil mount.Interface) error {
|
||||||
|
const (
|
||||||
|
cgroupMountType = "cgroup"
|
||||||
|
localErr = "system validation failed"
|
||||||
|
)
|
||||||
|
mountPoints, err := mountUtil.List()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s - %v", localErr, err)
|
||||||
|
}
|
||||||
|
expectedCgroups := sets.NewString("cpu", "cpuacct", "cpuset", "memory")
|
||||||
|
for _, mountPoint := range mountPoints {
|
||||||
|
if mountPoint.Type == cgroupMountType {
|
||||||
|
for _, opt := range mountPoint.Opts {
|
||||||
|
if expectedCgroups.Has(opt) {
|
||||||
|
expectedCgroups.Delete(opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if expectedCgroups.Len() > 0 {
|
||||||
|
return fmt.Errorf("%s - Following Cgroup subsystem not mounted: %v", localErr, expectedCgroups.List())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(vmarmol): Add limits to the system containers.
|
// TODO(vmarmol): Add limits to the system containers.
|
||||||
// Takes the absolute name of the specified containers.
|
// Takes the absolute name of the specified containers.
|
||||||
// Empty container name disables use of the specified container.
|
// Empty container name disables use of the specified container.
|
||||||
func newContainerManager(cadvisorInterface cadvisor.Interface, dockerDaemonContainerName, systemContainerName, kubeletContainerName string) (containerManager, error) {
|
func newContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.Interface, dockerDaemonContainerName, systemContainerName, kubeletContainerName string) (containerManager, error) {
|
||||||
systemContainers := []*systemContainer{}
|
|
||||||
|
|
||||||
if dockerDaemonContainerName != "" {
|
|
||||||
cont := newSystemContainer(dockerDaemonContainerName)
|
|
||||||
|
|
||||||
info, err := cadvisorInterface.MachineInfo()
|
|
||||||
var capacity = api.ResourceList{}
|
|
||||||
if err != nil {
|
|
||||||
} else {
|
|
||||||
capacity = CapacityFromMachineInfo(info)
|
|
||||||
}
|
|
||||||
memoryLimit := (int64(capacity.Memory().Value() * DockerMemoryLimitThresholdPercent / 100))
|
|
||||||
if memoryLimit < MinDockerMemoryLimit {
|
|
||||||
glog.Warningf("Memory limit %d for container %s is too small, reset it to %d", memoryLimit, dockerDaemonContainerName, MinDockerMemoryLimit)
|
|
||||||
memoryLimit = MinDockerMemoryLimit
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(2).Infof("Configure resource-only container %s with memory limit: %d", dockerDaemonContainerName, memoryLimit)
|
|
||||||
|
|
||||||
dockerContainer := &fs.Manager{
|
|
||||||
Cgroups: &configs.Cgroup{
|
|
||||||
Name: dockerDaemonContainerName,
|
|
||||||
Memory: memoryLimit,
|
|
||||||
MemorySwap: -1,
|
|
||||||
AllowAllDevices: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cont.ensureStateFunc = func(manager *fs.Manager) error {
|
|
||||||
return ensureDockerInContainer(cadvisorInterface, -900, dockerContainer)
|
|
||||||
}
|
|
||||||
systemContainers = append(systemContainers, cont)
|
|
||||||
}
|
|
||||||
|
|
||||||
if systemContainerName != "" {
|
|
||||||
if systemContainerName == "/" {
|
|
||||||
return nil, fmt.Errorf("system container cannot be root (\"/\")")
|
|
||||||
}
|
|
||||||
|
|
||||||
rootContainer := &fs.Manager{
|
|
||||||
Cgroups: &configs.Cgroup{
|
|
||||||
Name: "/",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
manager := createManager(systemContainerName)
|
|
||||||
|
|
||||||
err := ensureSystemContainer(rootContainer, manager)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
systemContainers = append(systemContainers, newSystemContainer(systemContainerName))
|
|
||||||
}
|
|
||||||
|
|
||||||
if kubeletContainerName != "" {
|
|
||||||
systemContainers = append(systemContainers, newSystemContainer(kubeletContainerName))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &containerManagerImpl{
|
return &containerManagerImpl{
|
||||||
systemContainers: systemContainers,
|
cadvisorInterface: cadvisorInterface,
|
||||||
|
mountUtil: mountUtil,
|
||||||
|
nodeConfig: nodeConfig{
|
||||||
|
dockerDaemonContainerName: dockerDaemonContainerName,
|
||||||
|
systemContainerName: systemContainerName,
|
||||||
|
kubeletContainerName: kubeletContainerName,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +141,73 @@ func createManager(containerName string) *fs.Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cm *containerManagerImpl) setupNode() error {
|
||||||
|
if err := validateSystemRequirements(cm.mountUtil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
systemContainers := []*systemContainer{}
|
||||||
|
if cm.dockerDaemonContainerName != "" {
|
||||||
|
cont := newSystemContainer(cm.dockerDaemonContainerName)
|
||||||
|
|
||||||
|
info, err := cm.cadvisorInterface.MachineInfo()
|
||||||
|
var capacity = api.ResourceList{}
|
||||||
|
if err != nil {
|
||||||
|
} else {
|
||||||
|
capacity = CapacityFromMachineInfo(info)
|
||||||
|
}
|
||||||
|
memoryLimit := (int64(capacity.Memory().Value() * DockerMemoryLimitThresholdPercent / 100))
|
||||||
|
if memoryLimit < MinDockerMemoryLimit {
|
||||||
|
glog.Warningf("Memory limit %d for container %s is too small, reset it to %d", memoryLimit, cm.dockerDaemonContainerName, MinDockerMemoryLimit)
|
||||||
|
memoryLimit = MinDockerMemoryLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(2).Infof("Configure resource-only container %s with memory limit: %d", cm.dockerDaemonContainerName, memoryLimit)
|
||||||
|
|
||||||
|
dockerContainer := &fs.Manager{
|
||||||
|
Cgroups: &configs.Cgroup{
|
||||||
|
Name: cm.dockerDaemonContainerName,
|
||||||
|
Memory: memoryLimit,
|
||||||
|
MemorySwap: -1,
|
||||||
|
AllowAllDevices: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cont.ensureStateFunc = func(manager *fs.Manager) error {
|
||||||
|
return ensureDockerInContainer(cm.cadvisorInterface, -900, dockerContainer)
|
||||||
|
}
|
||||||
|
systemContainers = append(systemContainers, cont)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cm.systemContainerName != "" {
|
||||||
|
if cm.systemContainerName == "/" {
|
||||||
|
return fmt.Errorf("system container cannot be root (\"/\")")
|
||||||
|
}
|
||||||
|
|
||||||
|
rootContainer := &fs.Manager{
|
||||||
|
Cgroups: &configs.Cgroup{
|
||||||
|
Name: "/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
manager := createManager(cm.systemContainerName)
|
||||||
|
|
||||||
|
err := ensureSystemContainer(rootContainer, manager)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
systemContainers = append(systemContainers, newSystemContainer(cm.systemContainerName))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cm.kubeletContainerName != "" {
|
||||||
|
systemContainers = append(systemContainers, newSystemContainer(cm.kubeletContainerName))
|
||||||
|
}
|
||||||
|
cm.systemContainers = systemContainers
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (cm *containerManagerImpl) Start() error {
|
func (cm *containerManagerImpl) Start() error {
|
||||||
|
// Setup the node
|
||||||
|
if err := cm.setupNode(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Don't run a background thread if there are no ensureStateFuncs.
|
// Don't run a background thread if there are no ensureStateFuncs.
|
||||||
numEnsureStateFuncs := 0
|
numEnsureStateFuncs := 0
|
||||||
for _, cont := range cm.systemContainers {
|
for _, cont := range cm.systemContainers {
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package kubelet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeMountInterface struct {
|
||||||
|
mountPoints []mount.MountPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mi *fakeMountInterface) Mount(source string, target string, fstype string, options []string) error {
|
||||||
|
return fmt.Errorf("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mi *fakeMountInterface) Unmount(target string) error {
|
||||||
|
return fmt.Errorf("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mi *fakeMountInterface) List() ([]mount.MountPoint, error) {
|
||||||
|
return mi.mountPoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mi *fakeMountInterface) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||||
|
return false, fmt.Errorf("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakeContainerMgrMountInt() mount.Interface {
|
||||||
|
return &fakeMountInterface{
|
||||||
|
[]mount.MountPoint{
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpuset"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpu"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "memory"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCgroupMountValidationSuccess(t *testing.T) {
|
||||||
|
assert.Nil(t, validateSystemRequirements(fakeContainerMgrMountInt()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCgroupMountValidationMemoryMissing(t *testing.T) {
|
||||||
|
mountInt := &fakeMountInterface{
|
||||||
|
[]mount.MountPoint{
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpuset"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpu"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Error(t, validateSystemRequirements(mountInt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCgroupMountValidationMultipleSubsytem(t *testing.T) {
|
||||||
|
mountInt := &fakeMountInterface{
|
||||||
|
[]mount.MountPoint{
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpuset", "memory"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpu"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Device: "cgroup",
|
||||||
|
Type: "cgroup",
|
||||||
|
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Nil(t, validateSystemRequirements(mountInt))
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import (
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||||
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
type unsupportedContainerManager struct {
|
type unsupportedContainerManager struct {
|
||||||
|
@ -38,6 +39,6 @@ func (unsupportedContainerManager) SystemContainersLimit() api.ResourceList {
|
||||||
return api.ResourceList{}
|
return api.ResourceList{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContainerManager(cadvisorInterface cadvisor.Interface, dockerDaemonContainer, systemContainer, kubeletContainer string) (containerManager, error) {
|
func newContainerManager(mounter mount.Interface, cadvisorInterface cadvisor.Interface, dockerDaemonContainer, systemContainer, kubeletContainer string) (containerManager, error) {
|
||||||
return &unsupportedContainerManager{}, nil
|
return &unsupportedContainerManager{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -362,7 +362,7 @@ func NewMainKubelet(
|
||||||
|
|
||||||
// Setup container manager, can fail if the devices hierarchy is not mounted
|
// Setup container manager, can fail if the devices hierarchy is not mounted
|
||||||
// (it is required by Docker however).
|
// (it is required by Docker however).
|
||||||
containerManager, err := newContainerManager(cadvisorInterface, dockerDaemonContainer, systemContainer, resourceContainer)
|
containerManager, err := newContainerManager(mounter, cadvisorInterface, dockerDaemonContainer, systemContainer, resourceContainer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create the Container Manager: %v", err)
|
return nil, fmt.Errorf("failed to create the Container Manager: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -758,6 +758,7 @@ func (kl *Kubelet) Run(updates <-chan PodUpdate) {
|
||||||
|
|
||||||
// Move Kubelet to a container.
|
// Move Kubelet to a container.
|
||||||
if kl.resourceContainer != "" {
|
if kl.resourceContainer != "" {
|
||||||
|
// Fixme: I need to reside inside ContainerManager interface.
|
||||||
err := util.RunInResourceContainer(kl.resourceContainer)
|
err := util.RunInResourceContainer(kl.resourceContainer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("Failed to move Kubelet to container %q: %v", kl.resourceContainer, err)
|
glog.Warningf("Failed to move Kubelet to container %q: %v", kl.resourceContainer, err)
|
||||||
|
|
|
@ -131,7 +131,7 @@ func newTestKubelet(t *testing.T) *TestKubelet {
|
||||||
t: t,
|
t: t,
|
||||||
}
|
}
|
||||||
kubelet.volumeManager = newVolumeManager()
|
kubelet.volumeManager = newVolumeManager()
|
||||||
kubelet.containerManager, _ = newContainerManager(mockCadvisor, "", "", "")
|
kubelet.containerManager, _ = newContainerManager(fakeContainerMgrMountInt(), mockCadvisor, "", "", "")
|
||||||
kubelet.networkConfigured = true
|
kubelet.networkConfigured = true
|
||||||
fakeClock := &util.FakeClock{Time: time.Now()}
|
fakeClock := &util.FakeClock{Time: time.Now()}
|
||||||
kubelet.backOff = util.NewBackOff(time.Second, time.Minute)
|
kubelet.backOff = util.NewBackOff(time.Second, time.Minute)
|
||||||
|
|
|
@ -51,7 +51,7 @@ func TestRunOnce(t *testing.T) {
|
||||||
diskSpaceManager: diskSpaceManager,
|
diskSpaceManager: diskSpaceManager,
|
||||||
containerRuntime: fakeRuntime,
|
containerRuntime: fakeRuntime,
|
||||||
}
|
}
|
||||||
kb.containerManager, _ = newContainerManager(cadvisor, "", "", "")
|
kb.containerManager, _ = newContainerManager(fakeContainerMgrMountInt(), cadvisor, "", "", "")
|
||||||
|
|
||||||
kb.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
|
kb.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
|
||||||
if err := kb.setupDataDirs(); err != nil {
|
if err := kb.setupDataDirs(); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue