mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 12:07:47 +00:00
Merge pull request #112957 from mxpv/log-dir
Allow changing pod log directory
This commit is contained in:
commit
dc3f5ec6cc
@ -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,
|
||||||
|
7
pkg/generated/openapi/zz_generated.openapi.go
generated
7
pkg/generated/openapi/zz_generated.openapi.go
generated
@ -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\"",
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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{}{}
|
||||||
|
@ -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")
|
||||||
|
@ -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{}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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{},
|
||||||
|
@ -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{}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user