Merge pull request #112957 from mxpv/log-dir

Allow changing pod log directory
This commit is contained in:
Kubernetes Prow Robot 2024-03-04 21:07:06 -08:00 committed by GitHub
commit dc3f5ec6cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 185 additions and 67 deletions

View File

@ -77,7 +77,7 @@ import (
logsapi "k8s.io/component-base/logs/api/v1" logsapi "k8s.io/component-base/logs/api/v1"
"k8s.io/component-base/metrics" "k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry" "k8s.io/component-base/metrics/legacyregistry"
tracing "k8s.io/component-base/tracing" "k8s.io/component-base/tracing"
"k8s.io/component-base/version" "k8s.io/component-base/version"
"k8s.io/component-base/version/verflag" "k8s.io/component-base/version/verflag"
nodeutil "k8s.io/component-helpers/node/util" nodeutil "k8s.io/component-helpers/node/util"
@ -1292,6 +1292,7 @@ func createAndInitKubelet(kubeServer *options.KubeletServer,
kubeServer.CloudProvider, kubeServer.CloudProvider,
kubeServer.CertDirectory, kubeServer.CertDirectory,
kubeServer.RootDirectory, kubeServer.RootDirectory,
kubeServer.PodLogsDir,
kubeServer.ImageCredentialProviderConfigFile, kubeServer.ImageCredentialProviderConfigFile,
kubeServer.ImageCredentialProviderBinDir, kubeServer.ImageCredentialProviderBinDir,
kubeServer.RegisterNode, kubeServer.RegisterNode,

View File

@ -58613,6 +58613,13 @@ func schema_k8sio_kubelet_config_v1beta1_KubeletConfiguration(ref common.Referen
Format: "", Format: "",
}, },
}, },
"podLogsDir": {
SchemaProps: spec.SchemaProps{
Description: "podLogsDir is a custom root directory path kubelet will use to place pod's log files. Default: \"/var/log/pods/\" Note: it is not recommended to use the temp folder as a log directory as it may cause unexpected behavior in many places.",
Type: []string{"string"},
Format: "",
},
},
"syncFrequency": { "syncFrequency": {
SchemaProps: spec.SchemaProps{ SchemaProps: spec.SchemaProps{
Description: "syncFrequency is the max period between synchronizing running containers and config. Default: \"1m\"", Description: "syncFrequency is the max period between synchronizing running containers and config. Default: \"1m\"",

View File

@ -83,6 +83,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
"memory": "50%", "memory": "50%",
} }
obj.OOMScoreAdj = int32(qos.KubeletOOMScoreAdj) obj.OOMScoreAdj = int32(qos.KubeletOOMScoreAdj)
obj.PodLogsDir = "/var/log/pods"
obj.Port = ports.KubeletPort obj.Port = ports.KubeletPort
obj.ReadOnlyPort = ports.KubeletReadOnlyPort obj.ReadOnlyPort = ports.KubeletReadOnlyPort
obj.RegistryBurst = 10 obj.RegistryBurst = 10

View File

@ -27,5 +27,6 @@ func KubeletConfigurationPathRefs(kc *KubeletConfiguration) []*string {
paths = append(paths, &kc.TLSPrivateKeyFile) paths = append(paths, &kc.TLSPrivateKeyFile)
paths = append(paths, &kc.ResolverConfig) paths = append(paths, &kc.ResolverConfig)
paths = append(paths, &kc.VolumePluginDir) paths = append(paths, &kc.VolumePluginDir)
paths = append(paths, &kc.PodLogsDir)
return paths return paths
} }

View File

@ -156,6 +156,7 @@ var (
"TLSCertFile", "TLSCertFile",
"TLSPrivateKeyFile", "TLSPrivateKeyFile",
"ResolverConfig", "ResolverConfig",
"PodLogsDir",
) )
// KubeletConfiguration fields that do not contain file paths. // KubeletConfiguration fields that do not contain file paths.

View File

@ -73,6 +73,7 @@ nodeStatusMaxImages: 50
nodeStatusReportFrequency: 5m0s nodeStatusReportFrequency: 5m0s
nodeStatusUpdateFrequency: 10s nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999 oomScoreAdj: -999
podLogsDir: /var/log/pods
podPidsLimit: -1 podPidsLimit: -1
port: 10250 port: 10250
registerNode: true registerNode: true

View File

@ -73,6 +73,7 @@ nodeStatusMaxImages: 50
nodeStatusReportFrequency: 5m0s nodeStatusReportFrequency: 5m0s
nodeStatusUpdateFrequency: 10s nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999 oomScoreAdj: -999
podLogsDir: /var/log/pods
podPidsLimit: -1 podPidsLimit: -1
port: 10250 port: 10250
registerNode: true registerNode: true

View File

@ -88,6 +88,11 @@ type KubeletConfiguration struct {
// staticPodPath is the path to the directory containing local (static) pods to // staticPodPath is the path to the directory containing local (static) pods to
// run, or the path to a single static pod file. // run, or the path to a single static pod file.
StaticPodPath string StaticPodPath string
// podLogsDir is a custom root directory path kubelet will use to place pod's log files.
// Default: "/var/log/pods/"
// Note: it is not recommended to use the temp folder as a log directory as it may cause
// unexpected behavior in many places.
PodLogsDir string
// syncFrequency is the max period between synchronizing running // syncFrequency is the max period between synchronizing running
// containers and config // containers and config
SyncFrequency metav1.Duration SyncFrequency metav1.Duration

View File

@ -36,7 +36,7 @@ const (
DefaultIPTablesMasqueradeBit = 14 DefaultIPTablesMasqueradeBit = 14
DefaultIPTablesDropBit = 15 DefaultIPTablesDropBit = 15
DefaultVolumePluginDir = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/" DefaultVolumePluginDir = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/"
DefaultPodLogsDir = "/var/log/pods"
// See https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2570-memory-qos // See https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2570-memory-qos
DefaultMemoryThrottlingFactor = 0.9 DefaultMemoryThrottlingFactor = 0.9
) )
@ -280,4 +280,7 @@ func SetDefaults_KubeletConfiguration(obj *kubeletconfigv1beta1.KubeletConfigura
if obj.ContainerRuntimeEndpoint == "" { if obj.ContainerRuntimeEndpoint == "" {
obj.ContainerRuntimeEndpoint = "unix:///run/containerd/containerd.sock" obj.ContainerRuntimeEndpoint = "unix:///run/containerd/containerd.sock"
} }
if obj.PodLogsDir == "" {
obj.PodLogsDir = DefaultPodLogsDir
}
} }

View File

@ -128,6 +128,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(DefaultMemoryThrottlingFactor), MemoryThrottlingFactor: utilpointer.Float64(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true), RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true), LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
}, },
}, },
{ {
@ -257,6 +258,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(0), MemoryThrottlingFactor: utilpointer.Float64(0),
RegisterNode: utilpointer.Bool(false), RegisterNode: utilpointer.Bool(false),
LocalStorageCapacityIsolation: utilpointer.Bool(false), LocalStorageCapacityIsolation: utilpointer.Bool(false),
PodLogsDir: "",
}, },
&v1beta1.KubeletConfiguration{ &v1beta1.KubeletConfiguration{
EnableServer: utilpointer.Bool(false), EnableServer: utilpointer.Bool(false),
@ -357,6 +359,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(0), MemoryThrottlingFactor: utilpointer.Float64(0),
RegisterNode: utilpointer.Bool(false), RegisterNode: utilpointer.Bool(false),
LocalStorageCapacityIsolation: utilpointer.Bool(false), LocalStorageCapacityIsolation: utilpointer.Bool(false),
PodLogsDir: DefaultPodLogsDir,
}, },
}, },
{ {
@ -508,6 +511,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(1), MemoryThrottlingFactor: utilpointer.Float64(1),
RegisterNode: utilpointer.Bool(true), RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true), LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: "/custom/path",
}, },
&v1beta1.KubeletConfiguration{ &v1beta1.KubeletConfiguration{
EnableServer: utilpointer.Bool(true), EnableServer: utilpointer.Bool(true),
@ -656,6 +660,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(1), MemoryThrottlingFactor: utilpointer.Float64(1),
RegisterNode: utilpointer.Bool(true), RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true), LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: "/custom/path",
}, },
}, },
{ {
@ -747,6 +752,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor), MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true), RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true), LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
}, },
}, },
{ {
@ -838,6 +844,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor), MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true), RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true), LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
}, },
}, },
{ {
@ -929,6 +936,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(DefaultMemoryThrottlingFactor), MemoryThrottlingFactor: utilpointer.Float64(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true), RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true), LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
}, },
}, },
} }

View File

@ -346,6 +346,7 @@ func autoConvert_v1beta1_KubeletConfiguration_To_config_KubeletConfiguration(in
return err return err
} }
out.StaticPodPath = in.StaticPodPath out.StaticPodPath = in.StaticPodPath
out.PodLogsDir = in.PodLogsDir
out.SyncFrequency = in.SyncFrequency out.SyncFrequency = in.SyncFrequency
out.FileCheckFrequency = in.FileCheckFrequency out.FileCheckFrequency = in.FileCheckFrequency
out.HTTPCheckFrequency = in.HTTPCheckFrequency out.HTTPCheckFrequency = in.HTTPCheckFrequency
@ -538,6 +539,7 @@ func autoConvert_config_KubeletConfiguration_To_v1beta1_KubeletConfiguration(in
return err return err
} }
out.StaticPodPath = in.StaticPodPath out.StaticPodPath = in.StaticPodPath
out.PodLogsDir = in.PodLogsDir
out.SyncFrequency = in.SyncFrequency out.SyncFrequency = in.SyncFrequency
out.FileCheckFrequency = in.FileCheckFrequency out.FileCheckFrequency = in.FileCheckFrequency
out.HTTPCheckFrequency = in.HTTPCheckFrequency out.HTTPCheckFrequency = in.HTTPCheckFrequency

View File

@ -18,7 +18,9 @@ package validation
import ( import (
"fmt" "fmt"
"path/filepath"
"time" "time"
"unicode"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
@ -286,5 +288,26 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration, featur
if kc.ContainerLogMonitorInterval.Duration.Seconds() < 3 { if kc.ContainerLogMonitorInterval.Duration.Seconds() < 3 {
allErrors = append(allErrors, fmt.Errorf("invalid configuration: containerLogMonitorInterval must be a positive time duration greater than or equal to 3s")) allErrors = append(allErrors, fmt.Errorf("invalid configuration: containerLogMonitorInterval must be a positive time duration greater than or equal to 3s"))
} }
if kc.PodLogsDir == "" {
allErrors = append(allErrors, fmt.Errorf("invalid configuration: podLogsDir was not specified"))
}
if !filepath.IsAbs(kc.PodLogsDir) {
allErrors = append(allErrors, fmt.Errorf("invalid configuration: pod logs path %q must be absolute path", kc.PodLogsDir))
}
if filepath.Clean(kc.PodLogsDir) != kc.PodLogsDir {
allErrors = append(allErrors, fmt.Errorf("invalid configuration: pod logs path %q must be normalized", kc.PodLogsDir))
}
// Since pod logs path is used in metrics, make sure it contains only ASCII characters.
for _, c := range kc.PodLogsDir {
if c > unicode.MaxASCII {
allErrors = append(allErrors, fmt.Errorf("invalid configuration: pod logs path %q mut contains ASCII characters only", kc.PodLogsDir))
break
}
}
return utilerrors.NewAggregate(allErrors) return utilerrors.NewAggregate(allErrors)
} }

View File

@ -38,6 +38,7 @@ var (
EnforceNodeAllocatable: enforceNodeAllocatable, EnforceNodeAllocatable: enforceNodeAllocatable,
SystemReservedCgroup: "/system.slice", SystemReservedCgroup: "/system.slice",
KubeReservedCgroup: "/kubelet.service", KubeReservedCgroup: "/kubelet.service",
PodLogsDir: "/logs",
SystemCgroups: "", SystemCgroups: "",
CgroupRoot: "", CgroupRoot: "",
EventBurst: 10, EventBurst: 10,
@ -569,7 +570,36 @@ func TestValidateKubeletConfiguration(t *testing.T) {
return conf return conf
}, },
errMsg: "invalid configuration: containerLogMonitorInterval must be a positive time duration greater than or equal to 3s", errMsg: "invalid configuration: containerLogMonitorInterval must be a positive time duration greater than or equal to 3s",
}} }, {
name: "pod logs path must be not empty",
configure: func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
config.PodLogsDir = ""
return config
},
errMsg: "invalid configuration: podLogsDir was not specified",
}, {
name: "pod logs path must be absolute",
configure: func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
config.PodLogsDir = "./test"
return config
},
errMsg: `invalid configuration: pod logs path "./test" must be absolute path`,
}, {
name: "pod logs path must be normalized",
configure: func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
config.PodLogsDir = "/path/../"
return config
},
errMsg: `invalid configuration: pod logs path "/path/../" must be normalized`,
}, {
name: "pod logs path is ascii only",
configure: func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
config.PodLogsDir = "/🧪"
return config
},
errMsg: `invalid configuration: pod logs path "/🧪" mut contains ASCII characters only`,
},
}
for _, tc := range cases { for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

View File

@ -19,6 +19,7 @@ package kubelet
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"math" "math"
"net" "net"
@ -346,6 +347,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
cloudProvider string, cloudProvider string,
certDirectory string, certDirectory string,
rootDirectory string, rootDirectory string,
podLogsDirectory string,
imageCredentialProviderConfigFile string, imageCredentialProviderConfigFile string,
imageCredentialProviderBinDir string, imageCredentialProviderBinDir string,
registerNode bool, registerNode bool,
@ -369,6 +371,9 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
if rootDirectory == "" { if rootDirectory == "" {
return nil, fmt.Errorf("invalid root directory %q", rootDirectory) return nil, fmt.Errorf("invalid root directory %q", rootDirectory)
} }
if podLogsDirectory == "" {
return nil, errors.New("pod logs root directory is empty")
}
if kubeCfg.SyncFrequency.Duration <= 0 { if kubeCfg.SyncFrequency.Duration <= 0 {
return nil, fmt.Errorf("invalid sync frequency %d", kubeCfg.SyncFrequency.Duration) return nil, fmt.Errorf("invalid sync frequency %d", kubeCfg.SyncFrequency.Duration)
} }
@ -518,6 +523,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
heartbeatClient: kubeDeps.HeartbeatClient, heartbeatClient: kubeDeps.HeartbeatClient,
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure, onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
rootDirectory: filepath.Clean(rootDirectory), rootDirectory: filepath.Clean(rootDirectory),
podLogsDirectory: podLogsDirectory,
resyncInterval: kubeCfg.SyncFrequency.Duration, resyncInterval: kubeCfg.SyncFrequency.Duration,
sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources), sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
registerNode: registerNode, registerNode: registerNode,
@ -648,6 +654,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
klet.readinessManager, klet.readinessManager,
klet.startupManager, klet.startupManager,
rootDirectory, rootDirectory,
podLogsDirectory,
machineInfo, machineInfo,
klet.podWorkers, klet.podWorkers,
kubeDeps.OSInterface, kubeDeps.OSInterface,
@ -690,7 +697,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
// common provider to get host file system usage associated with a pod managed by kubelet // common provider to get host file system usage associated with a pod managed by kubelet
hostStatsProvider := stats.NewHostStatsProvider(kubecontainer.RealOS{}, func(podUID types.UID) string { hostStatsProvider := stats.NewHostStatsProvider(kubecontainer.RealOS{}, func(podUID types.UID) string {
return getEtcHostsPath(klet.getPodDir(podUID)) return getEtcHostsPath(klet.getPodDir(podUID))
}) }, podLogsDirectory)
if kubeDeps.useLegacyCadvisorStats { if kubeDeps.useLegacyCadvisorStats {
klet.StatsProvider = stats.NewCadvisorStatsProvider( klet.StatsProvider = stats.NewCadvisorStatsProvider(
klet.cadvisor, klet.cadvisor,
@ -953,6 +960,7 @@ type Kubelet struct {
mirrorPodClient kubepod.MirrorClient mirrorPodClient kubepod.MirrorClient
rootDirectory string rootDirectory string
podLogsDirectory string
lastObservedNodeAddressesMux sync.RWMutex lastObservedNodeAddressesMux sync.RWMutex
lastObservedNodeAddresses []v1.NodeAddress lastObservedNodeAddresses []v1.NodeAddress
@ -1372,6 +1380,7 @@ func (kl *Kubelet) RlimitStats() (*statsapi.RlimitStats, error) {
// 3. the plugins directory // 3. the plugins directory
// 4. the pod-resources directory // 4. the pod-resources directory
// 5. the checkpoint directory // 5. the checkpoint directory
// 6. the pod logs root directory
func (kl *Kubelet) setupDataDirs() error { func (kl *Kubelet) setupDataDirs() error {
if cleanedRoot := filepath.Clean(kl.rootDirectory); cleanedRoot != kl.rootDirectory { if cleanedRoot := filepath.Clean(kl.rootDirectory); cleanedRoot != kl.rootDirectory {
return fmt.Errorf("rootDirectory not in canonical form: expected %s, was %s", cleanedRoot, kl.rootDirectory) return fmt.Errorf("rootDirectory not in canonical form: expected %s, was %s", cleanedRoot, kl.rootDirectory)
@ -1381,6 +1390,9 @@ func (kl *Kubelet) setupDataDirs() error {
if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil { if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
return fmt.Errorf("error creating root directory: %v", err) return fmt.Errorf("error creating root directory: %v", err)
} }
if err := os.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
return fmt.Errorf("error creating pod logs root directory %q: %w", kl.getPodLogsDir(), err)
}
if err := kl.hostutil.MakeRShared(kl.getRootDir()); err != nil { if err := kl.hostutil.MakeRShared(kl.getRootDir()); err != nil {
return fmt.Errorf("error configuring root directory: %v", err) return fmt.Errorf("error configuring root directory: %v", err)
} }

View File

@ -48,6 +48,13 @@ func (kl *Kubelet) getRootDir() string {
return kl.rootDirectory return kl.rootDirectory
} }
// getPodLogsDir returns the full path to the directory that kubelet can use
// to store pod's log files. This defaults to /var/log/pods if not specified
// otherwise in the config file.
func (kl *Kubelet) getPodLogsDir() string {
return kl.podLogsDirectory
}
// getPodsDir returns the full path to the directory under which pod // getPodsDir returns the full path to the directory under which pod
// directories are created. // directories are created.
func (kl *Kubelet) getPodsDir() string { func (kl *Kubelet) getPodsDir() string {

View File

@ -36,6 +36,9 @@ func TestKubeletDirs(t *testing.T) {
exp = filepath.Join(root, "pods") exp = filepath.Join(root, "pods")
assert.Equal(t, exp, got) assert.Equal(t, exp, got)
got = kubelet.getPodLogsDir()
assert.Equal(t, kubelet.podLogsDirectory, got)
got = kubelet.getPluginsDir() got = kubelet.getPluginsDir()
exp = filepath.Join(root, "plugins") exp = filepath.Join(root, "plugins")
assert.Equal(t, exp, got) assert.Equal(t, exp, got)

View File

@ -206,14 +206,8 @@ func newTestKubeletWithImageList(
kubelet.nodeName = types.NodeName(testKubeletHostname) kubelet.nodeName = types.NodeName(testKubeletHostname)
kubelet.runtimeState = newRuntimeState(maxWaitForContainerRuntime) kubelet.runtimeState = newRuntimeState(maxWaitForContainerRuntime)
kubelet.runtimeState.setNetworkState(nil) kubelet.runtimeState.setNetworkState(nil)
if tempDir, err := os.MkdirTemp("", "kubelet_test."); err != nil { kubelet.rootDirectory = t.TempDir()
t.Fatalf("can't make a temp rootdir: %v", err) kubelet.podLogsDirectory = t.TempDir()
} else {
kubelet.rootDirectory = tempDir
}
if err := os.MkdirAll(kubelet.rootDirectory, 0750); err != nil {
t.Fatalf("can't mkdir(%q): %v", kubelet.rootDirectory, err)
}
kubelet.sourcesReady = config.NewSourcesReady(func(_ sets.String) bool { return true }) kubelet.sourcesReady = config.NewSourcesReady(func(_ sets.String) bool { return true })
kubelet.serviceLister = testServiceLister{} kubelet.serviceLister = testServiceLister{}
kubelet.serviceHasSynced = func() bool { return true } kubelet.serviceHasSynced = func() bool { return true }
@ -3112,6 +3106,7 @@ func TestNewMainKubeletStandAlone(t *testing.T) {
"external", "external",
"/tmp/cert", "/tmp/cert",
"/tmp/rootdir", "/tmp/rootdir",
tempDir,
"", "",
"", "",
false, false,
@ -3206,6 +3201,7 @@ func TestSyncPodSpans(t *testing.T) {
kubelet.readinessManager, kubelet.readinessManager,
kubelet.startupManager, kubelet.startupManager,
kubelet.rootDirectory, kubelet.rootDirectory,
kubelet.podLogsDirectory,
kubelet.machineInfo, kubelet.machineInfo,
kubelet.podWorkers, kubelet.podWorkers,
kubelet.os, kubelet.os,

View File

@ -46,6 +46,8 @@ const (
fakeNodeAllocatableMemory = "32Gi" fakeNodeAllocatableMemory = "32Gi"
fakeNodeAllocatableCPU = "16" fakeNodeAllocatableCPU = "16"
fakePodLogsDirectory = "/var/log/pods"
) )
type fakeHTTP struct { type fakeHTTP struct {
@ -115,6 +117,7 @@ func newFakeKubeRuntimeManager(runtimeService internalapi.RuntimeService, imageS
logReduction: logreduction.NewLogReduction(identicalErrorDelay), logReduction: logreduction.NewLogReduction(identicalErrorDelay),
logManager: logManager, logManager: logManager,
memoryThrottlingFactor: 0.9, memoryThrottlingFactor: 0.9,
podLogsDirectory: fakePodLogsDirectory,
} }
typedVersion, err := runtimeService.Version(ctx, kubeRuntimeAPIVersion) typedVersion, err := runtimeService.Version(ctx, kubeRuntimeAPIVersion)

View File

@ -188,13 +188,13 @@ func buildContainerLogsPath(containerName string, restartCount int) string {
} }
// BuildContainerLogsDirectory builds absolute log directory path for a container in pod. // BuildContainerLogsDirectory builds absolute log directory path for a container in pod.
func BuildContainerLogsDirectory(podNamespace, podName string, podUID types.UID, containerName string) string { func BuildContainerLogsDirectory(podLogsDir, podNamespace, podName string, podUID types.UID, containerName string) string {
return filepath.Join(BuildPodLogsDirectory(podNamespace, podName, podUID), containerName) return filepath.Join(BuildPodLogsDirectory(podLogsDir, podNamespace, podName, podUID), containerName)
} }
// BuildPodLogsDirectory builds absolute log directory path for a pod sandbox. // BuildPodLogsDirectory builds absolute log directory path for a pod sandbox.
func BuildPodLogsDirectory(podNamespace, podName string, podUID types.UID) string { func BuildPodLogsDirectory(podLogsDir, podNamespace, podName string, podUID types.UID) string {
return filepath.Join(podLogsRootDirectory, strings.Join([]string{podNamespace, podName, return filepath.Join(podLogsDir, strings.Join([]string{podNamespace, podName,
string(podUID)}, logPathDelimiter)) string(podUID)}, logPathDelimiter))
} }

View File

@ -219,7 +219,7 @@ func (m *kubeGenericRuntimeManager) startContainer(ctx context.Context, podSandb
// We are checking to see if the log directory exists, and find // We are checking to see if the log directory exists, and find
// the latest restartCount by checking the log name - // the latest restartCount by checking the log name -
// {restartCount}.log - and adding 1 to it. // {restartCount}.log - and adding 1 to it.
logDir := BuildContainerLogsDirectory(pod.Namespace, pod.Name, pod.UID, container.Name) logDir := BuildContainerLogsDirectory(m.podLogsDirectory, pod.Namespace, pod.Name, pod.UID, container.Name)
restartCount, err = calcRestartCountByLogDir(logDir) restartCount, err = calcRestartCountByLogDir(logDir)
if err != nil { if err != nil {
klog.InfoS("Cannot calculate restartCount from the log directory", "logDir", logDir, "err", err) klog.InfoS("Cannot calculate restartCount from the log directory", "logDir", logDir, "err", err)
@ -334,7 +334,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(ctx context.Context,
} }
command, args := kubecontainer.ExpandContainerCommandAndArgs(container, opts.Envs) command, args := kubecontainer.ExpandContainerCommandAndArgs(container, opts.Envs)
logDir := BuildContainerLogsDirectory(pod.Namespace, pod.Name, pod.UID, container.Name) logDir := BuildContainerLogsDirectory(m.podLogsDirectory, pod.Namespace, pod.Name, pod.UID, container.Name)
err = m.osInterface.MkdirAll(logDir, 0755) err = m.osInterface.MkdirAll(logDir, 0755)
if err != nil { if err != nil {
return nil, cleanupAction, fmt.Errorf("create container log directory for container %s failed: %v", container.Name, err) return nil, cleanupAction, fmt.Errorf("create container log directory for container %s failed: %v", container.Name, err)

View File

@ -78,8 +78,9 @@ func TestRemoveContainer(t *testing.T) {
pattern = strings.Replace(pattern, "\\", "\\\\", -1) pattern = strings.Replace(pattern, "\\", "\\\\", -1)
return regexp.MustCompile(pattern).MatchString(path) return regexp.MustCompile(pattern).MatchString(path)
} }
expectedContainerLogPath := filepath.Join(podLogsRootDirectory, "new_bar_12345678", "foo", "0.log") podLogsDirectory := "/var/log/pods"
expectedContainerLogPathRotated := filepath.Join(podLogsRootDirectory, "new_bar_12345678", "foo", "0.log.20060102-150405") expectedContainerLogPath := filepath.Join(podLogsDirectory, "new_bar_12345678", "foo", "0.log")
expectedContainerLogPathRotated := filepath.Join(podLogsDirectory, "new_bar_12345678", "foo", "0.log.20060102-150405")
expectedContainerLogSymlink := legacyLogSymlink(containerID, "foo", "bar", "new") expectedContainerLogSymlink := legacyLogSymlink(containerID, "foo", "bar", "new")
fakeOS.Create(expectedContainerLogPath) fakeOS.Create(expectedContainerLogPath)

View File

@ -327,11 +327,12 @@ func (cgc *containerGC) evictSandboxes(ctx context.Context, evictNonDeletedPods
// are evictable if there are no corresponding pods. // are evictable if there are no corresponding pods.
func (cgc *containerGC) evictPodLogsDirectories(ctx context.Context, allSourcesReady bool) error { func (cgc *containerGC) evictPodLogsDirectories(ctx context.Context, allSourcesReady bool) error {
osInterface := cgc.manager.osInterface osInterface := cgc.manager.osInterface
podLogsDirectory := cgc.manager.podLogsDirectory
if allSourcesReady { if allSourcesReady {
// Only remove pod logs directories when all sources are ready. // Only remove pod logs directories when all sources are ready.
dirs, err := osInterface.ReadDir(podLogsRootDirectory) dirs, err := osInterface.ReadDir(podLogsDirectory)
if err != nil { if err != nil {
return fmt.Errorf("failed to read podLogsRootDirectory %q: %v", podLogsRootDirectory, err) return fmt.Errorf("failed to read podLogsDirectory %q: %w", podLogsDirectory, err)
} }
for _, dir := range dirs { for _, dir := range dirs {
name := dir.Name() name := dir.Name()
@ -340,7 +341,7 @@ func (cgc *containerGC) evictPodLogsDirectories(ctx context.Context, allSourcesR
continue continue
} }
klog.V(4).InfoS("Removing pod logs", "podUID", podUID) klog.V(4).InfoS("Removing pod logs", "podUID", podUID)
err := osInterface.RemoveAll(filepath.Join(podLogsRootDirectory, name)) err := osInterface.RemoveAll(filepath.Join(podLogsDirectory, name))
if err != nil { if err != nil {
klog.ErrorS(err, "Failed to remove pod logs directory", "path", name) klog.ErrorS(err, "Failed to remove pod logs directory", "path", name)
} }

View File

@ -430,10 +430,11 @@ func TestPodLogDirectoryGC(t *testing.T) {
// pod log directories without corresponding pods should be removed. // pod log directories without corresponding pods should be removed.
files := []string{"123", "456", "789", "012", "name_namespace_321", "name_namespace_654"} files := []string{"123", "456", "789", "012", "name_namespace_321", "name_namespace_654"}
podLogsDirectory := "/var/log/pods"
removed := []string{ removed := []string{
filepath.Join(podLogsRootDirectory, "789"), filepath.Join(podLogsDirectory, "789"),
filepath.Join(podLogsRootDirectory, "012"), filepath.Join(podLogsDirectory, "012"),
filepath.Join(podLogsRootDirectory, "name_namespace_654"), filepath.Join(podLogsDirectory, "name_namespace_654"),
} }
podStateProvider.removed["012"] = struct{}{} podStateProvider.removed["012"] = struct{}{}
podStateProvider.removed["789"] = struct{}{} podStateProvider.removed["789"] = struct{}{}

View File

@ -70,8 +70,6 @@ import (
const ( const (
// The api version of kubelet runtime api // The api version of kubelet runtime api
kubeRuntimeAPIVersion = "0.1.0" kubeRuntimeAPIVersion = "0.1.0"
// The root directory for pod logs
podLogsRootDirectory = "/var/log/pods"
// A minimal shutdown window for avoiding unnecessary SIGKILLs // A minimal shutdown window for avoiding unnecessary SIGKILLs
minimumGracePeriodInSeconds = 2 minimumGracePeriodInSeconds = 2
@ -169,6 +167,9 @@ type kubeGenericRuntimeManager struct {
// Memory throttling factor for MemoryQoS // Memory throttling factor for MemoryQoS
memoryThrottlingFactor float64 memoryThrottlingFactor float64
// Root directory used to store pod logs
podLogsDirectory string
} }
// KubeGenericRuntime is a interface contains interfaces for container runtime and command. // KubeGenericRuntime is a interface contains interfaces for container runtime and command.
@ -185,6 +186,7 @@ func NewKubeGenericRuntimeManager(
readinessManager proberesults.Manager, readinessManager proberesults.Manager,
startupManager proberesults.Manager, startupManager proberesults.Manager,
rootDirectory string, rootDirectory string,
podLogsDirectory string,
machineInfo *cadvisorapi.MachineInfo, machineInfo *cadvisorapi.MachineInfo,
podStateProvider podStateProvider, podStateProvider podStateProvider,
osInterface kubecontainer.OSInterface, osInterface kubecontainer.OSInterface,
@ -237,6 +239,7 @@ func NewKubeGenericRuntimeManager(
memorySwapBehavior: memorySwapBehavior, memorySwapBehavior: memorySwapBehavior,
getNodeAllocatable: getNodeAllocatable, getNodeAllocatable: getNodeAllocatable,
memoryThrottlingFactor: memoryThrottlingFactor, memoryThrottlingFactor: memoryThrottlingFactor,
podLogsDirectory: podLogsDirectory,
} }
typedVersion, err := kubeRuntimeManager.getTypedVersion(ctx) typedVersion, err := kubeRuntimeManager.getTypedVersion(ctx)
@ -260,15 +263,6 @@ func NewKubeGenericRuntimeManager(
"version", typedVersion.RuntimeVersion, "version", typedVersion.RuntimeVersion,
"apiVersion", typedVersion.RuntimeApiVersion) "apiVersion", typedVersion.RuntimeApiVersion)
// If the container logs directory does not exist, create it.
// TODO: create podLogsRootDirectory at kubelet.go when kubelet is refactored to
// new runtime interface
if _, err := osInterface.Stat(podLogsRootDirectory); os.IsNotExist(err) {
if err := osInterface.MkdirAll(podLogsRootDirectory, 0755); err != nil {
klog.ErrorS(err, "Failed to create pod log directory", "path", podLogsRootDirectory)
}
}
if imageCredentialProviderConfigFile != "" || imageCredentialProviderBinDir != "" { if imageCredentialProviderConfigFile != "" || imageCredentialProviderBinDir != "" {
if err := plugin.RegisterCredentialProviderPlugins(imageCredentialProviderConfigFile, imageCredentialProviderBinDir); err != nil { if err := plugin.RegisterCredentialProviderPlugins(imageCredentialProviderConfigFile, imageCredentialProviderBinDir); err != nil {
klog.ErrorS(err, "Failed to register CRI auth plugins") klog.ErrorS(err, "Failed to register CRI auth plugins")

View File

@ -111,7 +111,7 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *v1.Pod, attemp
podSandboxConfig.Hostname = podHostname podSandboxConfig.Hostname = podHostname
} }
logDir := BuildPodLogsDirectory(pod.Namespace, pod.Name, pod.UID) logDir := BuildPodLogsDirectory(m.podLogsDirectory, pod.Namespace, pod.Name, pod.UID)
podSandboxConfig.LogDirectory = logDir podSandboxConfig.LogDirectory = logDir
portMappings := []*runtimeapi.PortMapping{} portMappings := []*runtimeapi.PortMapping{}

View File

@ -37,12 +37,14 @@ import (
"k8s.io/utils/pointer" "k8s.io/utils/pointer"
) )
const testPodLogsDirectory = "/var/log/pods"
func TestGeneratePodSandboxConfig(t *testing.T) { func TestGeneratePodSandboxConfig(t *testing.T) {
_, _, m, err := createTestRuntimeManager() _, _, m, err := createTestRuntimeManager()
require.NoError(t, err) require.NoError(t, err)
pod := newTestPod() pod := newTestPod()
expectedLogDirectory := filepath.Join(podLogsRootDirectory, pod.Namespace+"_"+pod.Name+"_12345678") expectedLogDirectory := filepath.Join(testPodLogsDirectory, pod.Namespace+"_"+pod.Name+"_12345678")
expectedLabels := map[string]string{ expectedLabels := map[string]string{
"io.kubernetes.pod.name": pod.Name, "io.kubernetes.pod.name": pod.Name,
"io.kubernetes.pod.namespace": pod.Namespace, "io.kubernetes.pod.namespace": pod.Namespace,
@ -78,7 +80,7 @@ func TestCreatePodSandbox(t *testing.T) {
fakeOS := m.osInterface.(*containertest.FakeOS) fakeOS := m.osInterface.(*containertest.FakeOS)
fakeOS.MkdirAllFn = func(path string, perm os.FileMode) error { fakeOS.MkdirAllFn = func(path string, perm os.FileMode) error {
// Check pod logs root directory is created. // Check pod logs root directory is created.
assert.Equal(t, filepath.Join(podLogsRootDirectory, pod.Namespace+"_"+pod.Name+"_12345678"), path) assert.Equal(t, filepath.Join(testPodLogsDirectory, pod.Namespace+"_"+pod.Name+"_12345678"), path)
assert.Equal(t, os.FileMode(0755), perm) assert.Equal(t, os.FileMode(0755), perm)
return nil return nil
} }

View File

@ -84,6 +84,7 @@ func TestRunOnce(t *testing.T) {
defer os.RemoveAll(basePath) defer os.RemoveAll(basePath)
kb := &Kubelet{ kb := &Kubelet{
rootDirectory: filepath.Clean(basePath), rootDirectory: filepath.Clean(basePath),
podLogsDirectory: filepath.Join(basePath, "pod-logs"),
recorder: &record.FakeRecorder{}, recorder: &record.FakeRecorder{},
cadvisor: cadvisor, cadvisor: cadvisor,
nodeLister: testNodeLister{}, nodeLister: testNodeLister{},

View File

@ -706,8 +706,8 @@ func TestCadvisorListPodStatsWhenContainerLogFound(t *testing.T) {
containerLogStats0 := makeFakeLogStats(0) containerLogStats0 := makeFakeLogStats(0)
containerLogStats1 := makeFakeLogStats(0) containerLogStats1 := makeFakeLogStats(0)
fakeStats := map[string]*volume.Metrics{ fakeStats := map[string]*volume.Metrics{
kuberuntime.BuildContainerLogsDirectory(prf0.Namespace, prf0.Name, types.UID(prf0.UID), cName00): containerLogStats0, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, prf0.Namespace, prf0.Name, types.UID(prf0.UID), cName00): containerLogStats0,
kuberuntime.BuildContainerLogsDirectory(prf0.Namespace, prf0.Name, types.UID(prf0.UID), cName01): containerLogStats1, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, prf0.Namespace, prf0.Name, types.UID(prf0.UID), cName01): containerLogStats1,
} }
fakeStatsSlice := []*volume.Metrics{containerLogStats0, containerLogStats1} fakeStatsSlice := []*volume.Metrics{containerLogStats0, containerLogStats1}
fakeOS := &containertest.FakeOS{} fakeOS := &containertest.FakeOS{}

View File

@ -26,7 +26,7 @@ import (
"testing" "testing"
"time" "time"
gomock "github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
cadvisorfs "github.com/google/cadvisor/fs" cadvisorfs "github.com/google/cadvisor/fs"
cadvisorapiv2 "github.com/google/cadvisor/info/v2" cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -89,6 +89,8 @@ const (
cName9 = "container9-name" cName9 = "container9-name"
) )
const testPodLogDirectory = "/var/log/kube/pods/" // Use non-default path to ensure stats are collected properly
func TestCRIListPodStats(t *testing.T) { func TestCRIListPodStats(t *testing.T) {
ctx := context.Background() ctx := context.Background()
var ( var (
@ -204,14 +206,14 @@ func TestCRIListPodStats(t *testing.T) {
} }
fakeStats := map[string]*volume.Metrics{ fakeStats := map[string]*volume.Metrics{
kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName0): containerLogStats0, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName0): containerLogStats0,
kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName1): containerLogStats1, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName1): containerLogStats1,
kuberuntime.BuildContainerLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid"), cName2): containerLogStats2, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid"), cName2): containerLogStats2,
kuberuntime.BuildContainerLogsDirectory("sandbox2-ns", "sandbox2-name", types.UID("sandbox2-uid"), cName3): containerLogStats4, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox2-ns", "sandbox2-name", types.UID("sandbox2-uid"), cName3): containerLogStats4,
kuberuntime.BuildContainerLogsDirectory("sandbox3-ns", "sandbox3-name", types.UID("sandbox3-uid"), cName5): containerLogStats5, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox3-ns", "sandbox3-name", types.UID("sandbox3-uid"), cName5): containerLogStats5,
kuberuntime.BuildContainerLogsDirectory("sandbox3-ns", "sandbox3-name", types.UID("sandbox3-uid"), cName8): containerLogStats8, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox3-ns", "sandbox3-name", types.UID("sandbox3-uid"), cName8): containerLogStats8,
filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")), podLogName0): podLogStats0, filepath.Join(kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")), podLogName0): podLogStats0,
filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")), podLogName1): podLogStats1, filepath.Join(kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")), podLogName1): podLogStats1,
} }
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
@ -222,9 +224,9 @@ func TestCRIListPodStats(t *testing.T) {
var dirEntries []os.DirEntry var dirEntries []os.DirEntry
mockDE := kubecontainertest.NewMockDirEntry(ctrl) mockDE := kubecontainertest.NewMockDirEntry(ctrl)
switch path { switch path {
case kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")): case kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")):
mockDE.EXPECT().Name().Return(podLogName0) mockDE.EXPECT().Name().Return(podLogName0)
case kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")): case kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")):
mockDE.EXPECT().Name().Return(podLogName1) mockDE.EXPECT().Name().Return(podLogName1)
default: default:
return nil, nil return nil, nil
@ -431,11 +433,11 @@ func TestListPodStatsStrictlyFromCRI(t *testing.T) {
PersistentVolumes: persistentVolumes, PersistentVolumes: persistentVolumes,
} }
fakeStats := map[string]*volume.Metrics{ fakeStats := map[string]*volume.Metrics{
kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName0): containerLogStats0, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName0): containerLogStats0,
kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName1): containerLogStats1, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName1): containerLogStats1,
kuberuntime.BuildContainerLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid"), cName2): containerLogStats2, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid"), cName2): containerLogStats2,
filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")), podLogName0): podLogStats0, filepath.Join(kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")), podLogName0): podLogStats0,
filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")), podLogName1): podLogStats1, filepath.Join(kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")), podLogName1): podLogStats1,
} }
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
@ -444,9 +446,9 @@ func TestListPodStatsStrictlyFromCRI(t *testing.T) {
var dirEntries []os.DirEntry var dirEntries []os.DirEntry
mockDE := kubecontainertest.NewMockDirEntry(ctrl) mockDE := kubecontainertest.NewMockDirEntry(ctrl)
switch path { switch path {
case kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")): case kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")):
mockDE.EXPECT().Name().Return(podLogName0) mockDE.EXPECT().Name().Return(podLogName0)
case kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")): case kuberuntime.BuildPodLogsDirectory(testPodLogDirectory, "sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")):
mockDE.EXPECT().Name().Return(podLogName1) mockDE.EXPECT().Name().Return(podLogName1)
default: default:
return nil, nil return nil, nil

View File

@ -455,7 +455,7 @@ func Test_criStatsProvider_makeWinContainerStats(t *testing.T) {
InodesUsed: resource.NewQuantity(int64(logStatsInodesUsed), resource.BinarySI), InodesUsed: resource.NewQuantity(int64(logStatsInodesUsed), resource.BinarySI),
} }
fakeStats := map[string]*volume.Metrics{ fakeStats := map[string]*volume.Metrics{
kuberuntime.BuildContainerLogsDirectory("sb0-ns", "sb0-name", types.UID("sb0-uid"), "c0"): c0LogStats, kuberuntime.BuildContainerLogsDirectory(testPodLogDirectory, "sb0-ns", "sb0-name", types.UID("sb0-uid"), "c0"): c0LogStats,
} }
fakeOS := &kubecontainertest.FakeOS{} fakeOS := &kubecontainertest.FakeOS{}
fakeHostStatsProvider := NewFakeHostStatsProviderWithData(fakeStats, fakeOS) fakeHostStatsProvider := NewFakeHostStatsProviderWithData(fakeStats, fakeOS)

View File

@ -51,13 +51,16 @@ type hostStatsProvider struct {
osInterface kubecontainer.OSInterface osInterface kubecontainer.OSInterface
// podEtcHostsPathFunc fetches a pod etc hosts path by uid. // podEtcHostsPathFunc fetches a pod etc hosts path by uid.
podEtcHostsPathFunc PodEtcHostsPathFunc podEtcHostsPathFunc PodEtcHostsPathFunc
// podLogsDirectory is the root directory path for pod logs.
podLogsDirectory string
} }
// NewHostStatsProvider returns a new HostStatsProvider type struct. // NewHostStatsProvider returns a new HostStatsProvider type struct.
func NewHostStatsProvider(osInterface kubecontainer.OSInterface, podEtcHostsPathFunc PodEtcHostsPathFunc) HostStatsProvider { func NewHostStatsProvider(osInterface kubecontainer.OSInterface, podEtcHostsPathFunc PodEtcHostsPathFunc, podLogsDirectory string) HostStatsProvider {
return hostStatsProvider{ return hostStatsProvider{
osInterface: osInterface, osInterface: osInterface,
podEtcHostsPathFunc: podEtcHostsPathFunc, podEtcHostsPathFunc: podEtcHostsPathFunc,
podLogsDirectory: podLogsDirectory,
} }
} }
@ -102,12 +105,12 @@ func (h hostStatsProvider) getPodEtcHostsStats(podUID types.UID, rootFsInfo *cad
} }
func (h hostStatsProvider) podLogMetrics(podNamespace, podName string, podUID types.UID) (metricsProviderByPath, error) { func (h hostStatsProvider) podLogMetrics(podNamespace, podName string, podUID types.UID) (metricsProviderByPath, error) {
podLogsDirectoryPath := kuberuntime.BuildPodLogsDirectory(podNamespace, podName, podUID) podLogsDirectoryPath := kuberuntime.BuildPodLogsDirectory(h.podLogsDirectory, podNamespace, podName, podUID)
return h.fileMetricsByDir(podLogsDirectoryPath) return h.fileMetricsByDir(podLogsDirectoryPath)
} }
func (h hostStatsProvider) podContainerLogMetrics(podNamespace, podName string, podUID types.UID, containerName string) (metricsProviderByPath, error) { func (h hostStatsProvider) podContainerLogMetrics(podNamespace, podName string, podUID types.UID, containerName string) (metricsProviderByPath, error) {
podContainerLogsDirectoryPath := kuberuntime.BuildContainerLogsDirectory(podNamespace, podName, podUID, containerName) podContainerLogsDirectoryPath := kuberuntime.BuildContainerLogsDirectory(h.podLogsDirectory, podNamespace, podName, podUID, containerName)
return h.fileMetricsByDir(podContainerLogsDirectoryPath) return h.fileMetricsByDir(podContainerLogsDirectoryPath)
} }

View File

@ -50,7 +50,7 @@ func NewFakeHostStatsProviderWithData(fakeStats map[string]*volume.Metrics, osIn
} }
func (f *fakeHostStatsProvider) getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { func (f *fakeHostStatsProvider) getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
path := kuberuntime.BuildPodLogsDirectory(podNamespace, podName, podUID) path := kuberuntime.BuildPodLogsDirectory("/var/log/kube/pods/", podNamespace, podName, podUID)
files, err := f.osInterface.ReadDir(path) files, err := f.osInterface.ReadDir(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -68,7 +68,7 @@ func (f *fakeHostStatsProvider) getPodLogStats(podNamespace, podName string, pod
} }
func (f *fakeHostStatsProvider) getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) { func (f *fakeHostStatsProvider) getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
path := kuberuntime.BuildContainerLogsDirectory(podNamespace, podName, podUID, containerName) path := kuberuntime.BuildContainerLogsDirectory("/var/log/kube/pods/", podNamespace, podName, podUID, containerName)
metricsProvider := NewFakeMetricsDu(path, f.fakeStats[path]) metricsProvider := NewFakeMetricsDu(path, f.fakeStats[path])
return fakeMetricsProvidersToStats([]volume.MetricsProvider{metricsProvider}, rootFsInfo) return fakeMetricsProvidersToStats([]volume.MetricsProvider{metricsProvider}, rootFsInfo)
} }

View File

@ -152,6 +152,7 @@ type HollowKubeletOptions struct {
func GetHollowKubeletConfig(opt *HollowKubeletOptions) (*options.KubeletFlags, *kubeletconfig.KubeletConfiguration) { func GetHollowKubeletConfig(opt *HollowKubeletOptions) (*options.KubeletFlags, *kubeletconfig.KubeletConfiguration) {
testRootDir := utils.MakeTempDirOrDie("hollow-kubelet.", "") testRootDir := utils.MakeTempDirOrDie("hollow-kubelet.", "")
podFilePath := utils.MakeTempDirOrDie("static-pods", testRootDir) podFilePath := utils.MakeTempDirOrDie("static-pods", testRootDir)
podLogsPath := utils.MakeTempDirOrDie("pod-logs", testRootDir)
klog.Infof("Using %s as root dir for hollow-kubelet", testRootDir) klog.Infof("Using %s as root dir for hollow-kubelet", testRootDir)
// Flags struct // Flags struct
@ -210,6 +211,7 @@ func GetHollowKubeletConfig(opt *HollowKubeletOptions) (*options.KubeletFlags, *
c.RegisterWithTaints = opt.RegisterWithTaints c.RegisterWithTaints = opt.RegisterWithTaints
c.RegisterNode = true c.RegisterNode = true
c.LocalStorageCapacityIsolation = true c.LocalStorageCapacityIsolation = true
c.PodLogsDir = podLogsPath
return f, c return f, c
} }

View File

@ -98,6 +98,12 @@ type KubeletConfiguration struct {
// Default: "" // Default: ""
// +optional // +optional
StaticPodPath string `json:"staticPodPath,omitempty"` StaticPodPath string `json:"staticPodPath,omitempty"`
// podLogsDir is a custom root directory path kubelet will use to place pod's log files.
// Default: "/var/log/pods/"
// Note: it is not recommended to use the temp folder as a log directory as it may cause
// unexpected behavior in many places.
// +optional
PodLogsDir string `json:"podLogsDir,omitempty"`
// syncFrequency is the max period between synchronizing running // syncFrequency is the max period between synchronizing running
// containers and config. // containers and config.
// Default: "1m" // Default: "1m"