1
16
17 package kubemark
18
19 import (
20 "fmt"
21 "time"
22
23 "go.opentelemetry.io/otel/trace"
24 v1 "k8s.io/api/core/v1"
25 "k8s.io/klog/v2"
26 "k8s.io/mount-utils"
27
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 clientset "k8s.io/client-go/kubernetes"
30 "k8s.io/client-go/tools/record"
31 internalapi "k8s.io/cri-api/pkg/apis"
32 kubeletapp "k8s.io/kubernetes/cmd/kubelet/app"
33 "k8s.io/kubernetes/cmd/kubelet/app/options"
34 "k8s.io/kubernetes/pkg/kubelet"
35 kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
36 "k8s.io/kubernetes/pkg/kubelet/cadvisor"
37 "k8s.io/kubernetes/pkg/kubelet/cm"
38 containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
39 probetest "k8s.io/kubernetes/pkg/kubelet/prober/testing"
40 kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
41 kubeletutil "k8s.io/kubernetes/pkg/kubelet/util"
42 "k8s.io/kubernetes/pkg/util/oom"
43 "k8s.io/kubernetes/pkg/volume"
44 "k8s.io/kubernetes/pkg/volume/cephfs"
45 "k8s.io/kubernetes/pkg/volume/configmap"
46 "k8s.io/kubernetes/pkg/volume/csi"
47 "k8s.io/kubernetes/pkg/volume/downwardapi"
48 "k8s.io/kubernetes/pkg/volume/emptydir"
49 "k8s.io/kubernetes/pkg/volume/fc"
50 "k8s.io/kubernetes/pkg/volume/git_repo"
51 "k8s.io/kubernetes/pkg/volume/hostpath"
52 "k8s.io/kubernetes/pkg/volume/iscsi"
53 "k8s.io/kubernetes/pkg/volume/local"
54 "k8s.io/kubernetes/pkg/volume/nfs"
55 "k8s.io/kubernetes/pkg/volume/portworx"
56 "k8s.io/kubernetes/pkg/volume/projected"
57 "k8s.io/kubernetes/pkg/volume/rbd"
58 "k8s.io/kubernetes/pkg/volume/secret"
59 "k8s.io/kubernetes/pkg/volume/util/hostutil"
60 "k8s.io/kubernetes/pkg/volume/util/subpath"
61 "k8s.io/kubernetes/test/utils"
62 )
63
64 type HollowKubelet struct {
65 KubeletFlags *options.KubeletFlags
66 KubeletConfiguration *kubeletconfig.KubeletConfiguration
67 KubeletDeps *kubelet.Dependencies
68 }
69
70 func volumePlugins() []volume.VolumePlugin {
71 allPlugins := []volume.VolumePlugin{}
72 allPlugins = append(allPlugins, emptydir.ProbeVolumePlugins()...)
73 allPlugins = append(allPlugins, git_repo.ProbeVolumePlugins()...)
74 allPlugins = append(allPlugins, hostpath.FakeProbeVolumePlugins(volume.VolumeConfig{})...)
75 allPlugins = append(allPlugins, nfs.ProbeVolumePlugins(volume.VolumeConfig{})...)
76 allPlugins = append(allPlugins, secret.ProbeVolumePlugins()...)
77 allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
78 allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
79 allPlugins = append(allPlugins, cephfs.ProbeVolumePlugins()...)
80 allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...)
81 allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
82 allPlugins = append(allPlugins, configmap.ProbeVolumePlugins()...)
83 allPlugins = append(allPlugins, projected.ProbeVolumePlugins()...)
84 allPlugins = append(allPlugins, portworx.ProbeVolumePlugins()...)
85 allPlugins = append(allPlugins, local.ProbeVolumePlugins()...)
86 allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
87 return allPlugins
88 }
89
90 func NewHollowKubelet(
91 flags *options.KubeletFlags,
92 config *kubeletconfig.KubeletConfiguration,
93 client *clientset.Clientset,
94 heartbeatClient *clientset.Clientset,
95 cadvisorInterface cadvisor.Interface,
96 imageService internalapi.ImageManagerService,
97 runtimeService internalapi.RuntimeService,
98 containerManager cm.ContainerManager) *HollowKubelet {
99 d := &kubelet.Dependencies{
100 KubeClient: client,
101 HeartbeatClient: heartbeatClient,
102 ProbeManager: probetest.FakeManager{},
103 RemoteRuntimeService: runtimeService,
104 RemoteImageService: imageService,
105 CAdvisorInterface: cadvisorInterface,
106 Cloud: nil,
107 OSInterface: &containertest.FakeOS{},
108 ContainerManager: containerManager,
109 VolumePlugins: volumePlugins(),
110 TLSOptions: nil,
111 OOMAdjuster: oom.NewFakeOOMAdjuster(),
112 Mounter: &mount.FakeMounter{},
113 Subpather: &subpath.FakeSubpath{},
114 HostUtil: hostutil.NewFakeHostUtil(nil),
115 PodStartupLatencyTracker: kubeletutil.NewPodStartupLatencyTracker(),
116 NodeStartupLatencyTracker: kubeletutil.NewNodeStartupLatencyTracker(),
117 TracerProvider: trace.NewNoopTracerProvider(),
118 Recorder: &record.FakeRecorder{},
119 }
120
121 return &HollowKubelet{
122 KubeletFlags: flags,
123 KubeletConfiguration: config,
124 KubeletDeps: d,
125 }
126 }
127
128
129 func (hk *HollowKubelet) Run() {
130 if err := kubeletapp.RunKubelet(&options.KubeletServer{
131 KubeletFlags: *hk.KubeletFlags,
132 KubeletConfiguration: *hk.KubeletConfiguration,
133 }, hk.KubeletDeps, false); err != nil {
134 klog.Fatalf("Failed to run HollowKubelet: %v. Exiting.", err)
135 }
136 select {}
137 }
138
139
140 type HollowKubeletOptions struct {
141 NodeName string
142 KubeletPort int
143 KubeletReadOnlyPort int
144 MaxPods int
145 PodsPerCore int
146 NodeLabels map[string]string
147 RegisterWithTaints []v1.Taint
148 }
149
150
151
152 func GetHollowKubeletConfig(opt *HollowKubeletOptions) (*options.KubeletFlags, *kubeletconfig.KubeletConfiguration) {
153 testRootDir := utils.MakeTempDirOrDie("hollow-kubelet.", "")
154 podFilePath := utils.MakeTempDirOrDie("static-pods", testRootDir)
155 podLogsPath := utils.MakeTempDirOrDie("pod-logs", testRootDir)
156 klog.Infof("Using %s as root dir for hollow-kubelet", testRootDir)
157
158
159 f := options.NewKubeletFlags()
160 f.RootDirectory = testRootDir
161 f.HostnameOverride = opt.NodeName
162 f.MinimumGCAge = metav1.Duration{Duration: 1 * time.Minute}
163 f.MaxContainerCount = 100
164 f.MaxPerPodContainerCount = 2
165 f.NodeLabels = opt.NodeLabels
166 f.RegisterSchedulable = true
167
168
169 c, err := options.NewKubeletConfiguration()
170 if err != nil {
171 panic(err)
172 }
173
174 c.ImageServiceEndpoint = "unix:///run/containerd/containerd.sock"
175 c.StaticPodURL = ""
176 c.EnableServer = true
177 c.Address = "0.0.0.0"
178 c.Port = int32(opt.KubeletPort)
179 c.ReadOnlyPort = int32(opt.KubeletReadOnlyPort)
180 c.StaticPodPath = podFilePath
181 c.FileCheckFrequency.Duration = 20 * time.Second
182 c.HTTPCheckFrequency.Duration = 20 * time.Second
183 c.NodeStatusUpdateFrequency.Duration = 10 * time.Second
184 c.NodeStatusReportFrequency.Duration = 5 * time.Minute
185 c.SyncFrequency.Duration = 10 * time.Second
186 c.EvictionPressureTransitionPeriod.Duration = 5 * time.Minute
187 c.MaxPods = int32(opt.MaxPods)
188 c.PodsPerCore = int32(opt.PodsPerCore)
189 c.ClusterDNS = []string{}
190 c.ImageGCHighThresholdPercent = 90
191 c.ImageGCLowThresholdPercent = 80
192 c.ProviderID = fmt.Sprintf("kubemark://%v", opt.NodeName)
193 c.VolumeStatsAggPeriod.Duration = time.Minute
194 c.CgroupRoot = ""
195 c.CPUCFSQuota = true
196 c.EnableControllerAttachDetach = false
197 c.EnableDebuggingHandlers = true
198 c.CgroupsPerQOS = false
199
200
201
202 c.HairpinMode = kubeletconfig.HairpinVeth
203 c.MaxOpenFiles = 1024
204 c.RegistryBurst = 10
205 c.RegistryPullQPS = 5.0
206 c.ResolverConfig = kubetypes.ResolvConfDefault
207 c.KubeletCgroups = "/kubelet"
208 c.SerializeImagePulls = true
209 c.SystemCgroups = ""
210 c.ProtectKernelDefaults = false
211 c.RegisterWithTaints = opt.RegisterWithTaints
212 c.RegisterNode = true
213 c.LocalStorageCapacityIsolation = true
214 c.PodLogsDir = podLogsPath
215
216 return f, c
217 }
218
View as plain text