Skip to content

Commit

Permalink
Merge pull request kubernetes#112957 from mxpv/log-dir
Browse files Browse the repository at this point in the history
Allow changing pod log directory
  • Loading branch information
k8s-ci-robot committed Mar 5, 2024
2 parents 50f4b1e + 8375163 commit dc3f5ec
Show file tree
Hide file tree
Showing 34 changed files with 185 additions and 67 deletions.
3 changes: 2 additions & 1 deletion cmd/kubelet/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import (
logsapi "k8s.io/component-base/logs/api/v1"
"k8s.io/component-base/metrics"
"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/verflag"
nodeutil "k8s.io/component-helpers/node/util"
Expand Down Expand Up @@ -1292,6 +1292,7 @@ func createAndInitKubelet(kubeServer *options.KubeletServer,
kubeServer.CloudProvider,
kubeServer.CertDirectory,
kubeServer.RootDirectory,
kubeServer.PodLogsDir,
kubeServer.ImageCredentialProviderConfigFile,
kubeServer.ImageCredentialProviderBinDir,
kubeServer.RegisterNode,
Expand Down
7 changes: 7 additions & 0 deletions pkg/generated/openapi/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/kubelet/apis/config/fuzzer/fuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
"memory": "50%",
}
obj.OOMScoreAdj = int32(qos.KubeletOOMScoreAdj)
obj.PodLogsDir = "/var/log/pods"
obj.Port = ports.KubeletPort
obj.ReadOnlyPort = ports.KubeletReadOnlyPort
obj.RegistryBurst = 10
Expand Down
1 change: 1 addition & 0 deletions pkg/kubelet/apis/config/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ func KubeletConfigurationPathRefs(kc *KubeletConfiguration) []*string {
paths = append(paths, &kc.TLSPrivateKeyFile)
paths = append(paths, &kc.ResolverConfig)
paths = append(paths, &kc.VolumePluginDir)
paths = append(paths, &kc.PodLogsDir)
return paths
}
1 change: 1 addition & 0 deletions pkg/kubelet/apis/config/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ var (
"TLSCertFile",
"TLSPrivateKeyFile",
"ResolverConfig",
"PodLogsDir",
)

// KubeletConfiguration fields that do not contain file paths.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ nodeStatusMaxImages: 50
nodeStatusReportFrequency: 5m0s
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podLogsDir: /var/log/pods
podPidsLimit: -1
port: 10250
registerNode: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ nodeStatusMaxImages: 50
nodeStatusReportFrequency: 5m0s
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podLogsDir: /var/log/pods
podPidsLimit: -1
port: 10250
registerNode: true
Expand Down
5 changes: 5 additions & 0 deletions pkg/kubelet/apis/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ type KubeletConfiguration struct {
// staticPodPath is the path to the directory containing local (static) pods to
// run, or the path to a single static pod file.
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
// containers and config
SyncFrequency metav1.Duration
Expand Down
5 changes: 4 additions & 1 deletion pkg/kubelet/apis/config/v1beta1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const (
DefaultIPTablesMasqueradeBit = 14
DefaultIPTablesDropBit = 15
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
DefaultMemoryThrottlingFactor = 0.9
)
Expand Down Expand Up @@ -280,4 +280,7 @@ func SetDefaults_KubeletConfiguration(obj *kubeletconfigv1beta1.KubeletConfigura
if obj.ContainerRuntimeEndpoint == "" {
obj.ContainerRuntimeEndpoint = "unix:///run/containerd/containerd.sock"
}
if obj.PodLogsDir == "" {
obj.PodLogsDir = DefaultPodLogsDir
}
}
8 changes: 8 additions & 0 deletions pkg/kubelet/apis/config/v1beta1/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
},
},
{
Expand Down Expand Up @@ -257,6 +258,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(0),
RegisterNode: utilpointer.Bool(false),
LocalStorageCapacityIsolation: utilpointer.Bool(false),
PodLogsDir: "",
},
&v1beta1.KubeletConfiguration{
EnableServer: utilpointer.Bool(false),
Expand Down Expand Up @@ -357,6 +359,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(0),
RegisterNode: utilpointer.Bool(false),
LocalStorageCapacityIsolation: utilpointer.Bool(false),
PodLogsDir: DefaultPodLogsDir,
},
},
{
Expand Down Expand Up @@ -508,6 +511,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(1),
RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: "/custom/path",
},
&v1beta1.KubeletConfiguration{
EnableServer: utilpointer.Bool(true),
Expand Down Expand Up @@ -656,6 +660,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(1),
RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: "/custom/path",
},
},
{
Expand Down Expand Up @@ -747,6 +752,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
},
},
{
Expand Down Expand Up @@ -838,6 +844,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
},
},
{
Expand Down Expand Up @@ -929,6 +936,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
MemoryThrottlingFactor: utilpointer.Float64(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.Bool(true),
LocalStorageCapacityIsolation: utilpointer.Bool(true),
PodLogsDir: DefaultPodLogsDir,
},
},
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/kubelet/apis/config/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions pkg/kubelet/apis/config/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package validation

import (
"fmt"
"path/filepath"
"time"
"unicode"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
Expand Down Expand Up @@ -286,5 +288,26 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration, featur
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"))
}

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)
}
32 changes: 31 additions & 1 deletion pkg/kubelet/apis/config/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var (
EnforceNodeAllocatable: enforceNodeAllocatable,
SystemReservedCgroup: "/system.slice",
KubeReservedCgroup: "/kubelet.service",
PodLogsDir: "/logs",
SystemCgroups: "",
CgroupRoot: "",
EventBurst: 10,
Expand Down Expand Up @@ -569,7 +570,36 @@ func TestValidateKubeletConfiguration(t *testing.T) {
return conf
},
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 {
t.Run(tc.name, func(t *testing.T) {
Expand Down
16 changes: 14 additions & 2 deletions pkg/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package kubelet
import (
"context"
"crypto/tls"
"errors"
"fmt"
"math"
"net"
Expand Down Expand Up @@ -346,6 +347,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
cloudProvider string,
certDirectory string,
rootDirectory string,
podLogsDirectory string,
imageCredentialProviderConfigFile string,
imageCredentialProviderBinDir string,
registerNode bool,
Expand All @@ -369,6 +371,9 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
if 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 {
return nil, fmt.Errorf("invalid sync frequency %d", kubeCfg.SyncFrequency.Duration)
}
Expand Down Expand Up @@ -518,6 +523,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
heartbeatClient: kubeDeps.HeartbeatClient,
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
rootDirectory: filepath.Clean(rootDirectory),
podLogsDirectory: podLogsDirectory,
resyncInterval: kubeCfg.SyncFrequency.Duration,
sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
registerNode: registerNode,
Expand Down Expand Up @@ -648,6 +654,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
klet.readinessManager,
klet.startupManager,
rootDirectory,
podLogsDirectory,
machineInfo,
klet.podWorkers,
kubeDeps.OSInterface,
Expand Down Expand Up @@ -690,7 +697,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
// 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 {
return getEtcHostsPath(klet.getPodDir(podUID))
})
}, podLogsDirectory)
if kubeDeps.useLegacyCadvisorStats {
klet.StatsProvider = stats.NewCadvisorStatsProvider(
klet.cadvisor,
Expand Down Expand Up @@ -952,7 +959,8 @@ type Kubelet struct {
// pods.
mirrorPodClient kubepod.MirrorClient

rootDirectory string
rootDirectory string
podLogsDirectory string

lastObservedNodeAddressesMux sync.RWMutex
lastObservedNodeAddresses []v1.NodeAddress
Expand Down Expand Up @@ -1372,6 +1380,7 @@ func (kl *Kubelet) RlimitStats() (*statsapi.RlimitStats, error) {
// 3. the plugins directory
// 4. the pod-resources directory
// 5. the checkpoint directory
// 6. the pod logs root directory
func (kl *Kubelet) setupDataDirs() error {
if cleanedRoot := filepath.Clean(kl.rootDirectory); cleanedRoot != kl.rootDirectory {
return fmt.Errorf("rootDirectory not in canonical form: expected %s, was %s", cleanedRoot, kl.rootDirectory)
Expand All @@ -1381,6 +1390,9 @@ func (kl *Kubelet) setupDataDirs() error {
if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
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 {
return fmt.Errorf("error configuring root directory: %v", err)
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/kubelet/kubelet_getters.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ func (kl *Kubelet) getRootDir() string {
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
// directories are created.
func (kl *Kubelet) getPodsDir() string {
Expand Down
3 changes: 3 additions & 0 deletions pkg/kubelet/kubelet_getters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func TestKubeletDirs(t *testing.T) {
exp = filepath.Join(root, "pods")
assert.Equal(t, exp, got)

got = kubelet.getPodLogsDir()
assert.Equal(t, kubelet.podLogsDirectory, got)

got = kubelet.getPluginsDir()
exp = filepath.Join(root, "plugins")
assert.Equal(t, exp, got)
Expand Down
12 changes: 4 additions & 8 deletions pkg/kubelet/kubelet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,8 @@ func newTestKubeletWithImageList(
kubelet.nodeName = types.NodeName(testKubeletHostname)
kubelet.runtimeState = newRuntimeState(maxWaitForContainerRuntime)
kubelet.runtimeState.setNetworkState(nil)
if tempDir, err := os.MkdirTemp("", "kubelet_test."); err != nil {
t.Fatalf("can't make a temp rootdir: %v", err)
} else {
kubelet.rootDirectory = tempDir
}
if err := os.MkdirAll(kubelet.rootDirectory, 0750); err != nil {
t.Fatalf("can't mkdir(%q): %v", kubelet.rootDirectory, err)
}
kubelet.rootDirectory = t.TempDir()
kubelet.podLogsDirectory = t.TempDir()
kubelet.sourcesReady = config.NewSourcesReady(func(_ sets.String) bool { return true })
kubelet.serviceLister = testServiceLister{}
kubelet.serviceHasSynced = func() bool { return true }
Expand Down Expand Up @@ -3112,6 +3106,7 @@ func TestNewMainKubeletStandAlone(t *testing.T) {
"external",
"/tmp/cert",
"/tmp/rootdir",
tempDir,
"",
"",
false,
Expand Down Expand Up @@ -3206,6 +3201,7 @@ func TestSyncPodSpans(t *testing.T) {
kubelet.readinessManager,
kubelet.startupManager,
kubelet.rootDirectory,
kubelet.podLogsDirectory,
kubelet.machineInfo,
kubelet.podWorkers,
kubelet.os,
Expand Down

0 comments on commit dc3f5ec

Please sign in to comment.