mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-20 09:05:26 +00:00
Merge pull request #115133 from ffromani/podresources-windows
node: create podresources endpoint also on windows
This commit is contained in:
commit
0c969ad660
@ -861,10 +861,6 @@ function construct-windows-kubelet-flags {
|
|||||||
# Turn off kernel memory cgroup notification.
|
# Turn off kernel memory cgroup notification.
|
||||||
flags+=" --kernel-memcg-notification=false"
|
flags+=" --kernel-memcg-notification=false"
|
||||||
|
|
||||||
# TODO(#78628): Re-enable KubeletPodResources when the issue is fixed.
|
|
||||||
# Force disable KubeletPodResources feature on Windows until #78628 is fixed.
|
|
||||||
flags+=" --feature-gates=KubeletPodResources=false"
|
|
||||||
|
|
||||||
WINDOWS_CONTAINER_RUNTIME_ENDPOINT=${KUBE_WINDOWS_CONTAINER_RUNTIME_ENDPOINT:-npipe:////./pipe/containerd-containerd}
|
WINDOWS_CONTAINER_RUNTIME_ENDPOINT=${KUBE_WINDOWS_CONTAINER_RUNTIME_ENDPOINT:-npipe:////./pipe/containerd-containerd}
|
||||||
flags+=" --container-runtime-endpoint=${WINDOWS_CONTAINER_RUNTIME_ENDPOINT}"
|
flags+=" --container-runtime-endpoint=${WINDOWS_CONTAINER_RUNTIME_ENDPOINT}"
|
||||||
|
|
||||||
|
@ -123,7 +123,6 @@ e2e test configuration for the latest environment variables.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
KUBE_GCE_ENABLE_IP_ALIASES=true KUBERNETES_NODE_PLATFORM=windows \
|
KUBE_GCE_ENABLE_IP_ALIASES=true KUBERNETES_NODE_PLATFORM=windows \
|
||||||
KUBELET_TEST_ARGS=--feature-gates=KubeletPodResources=false \
|
|
||||||
LOGGING_STACKDRIVER_RESOURCE_TYPES=new NUM_NODES=2 \
|
LOGGING_STACKDRIVER_RESOURCE_TYPES=new NUM_NODES=2 \
|
||||||
NUM_WINDOWS_NODES=3 WINDOWS_NODE_OS_DISTRIBUTION=win2019 \
|
NUM_WINDOWS_NODES=3 WINDOWS_NODE_OS_DISTRIBUTION=win2019 \
|
||||||
./hack/e2e-internal/e2e-up.sh
|
./hack/e2e-internal/e2e-up.sh
|
||||||
|
@ -2805,7 +2805,7 @@ func (kl *Kubelet) ListenAndServeReadOnly(address net.IP, port uint) {
|
|||||||
|
|
||||||
// ListenAndServePodResources runs the kubelet podresources grpc service
|
// ListenAndServePodResources runs the kubelet podresources grpc service
|
||||||
func (kl *Kubelet) ListenAndServePodResources() {
|
func (kl *Kubelet) ListenAndServePodResources() {
|
||||||
socket, err := util.LocalEndpoint(kl.getPodResourcesDir(), podresources.Socket)
|
endpoint, err := util.LocalEndpoint(kl.getPodResourcesDir(), podresources.Socket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(2).InfoS("Failed to get local endpoint for PodResources endpoint", "err", err)
|
klog.V(2).InfoS("Failed to get local endpoint for PodResources endpoint", "err", err)
|
||||||
return
|
return
|
||||||
@ -2819,7 +2819,7 @@ func (kl *Kubelet) ListenAndServePodResources() {
|
|||||||
DynamicResources: kl.containerManager,
|
DynamicResources: kl.containerManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
server.ListenAndServePodResources(socket, providers)
|
server.ListenAndServePodResources(endpoint, providers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the eligible dead container instances in a pod. Depending on the configuration, the latest dead containers may be kept around.
|
// Delete the eligible dead container instances in a pod. Depending on the configuration, the latest dead containers may be kept around.
|
||||||
|
@ -218,18 +218,19 @@ type PodResourcesProviders struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServePodResources initializes a gRPC server to serve the PodResources service
|
// ListenAndServePodResources initializes a gRPC server to serve the PodResources service
|
||||||
func ListenAndServePodResources(socket string, providers podresources.PodResourcesProviders) {
|
func ListenAndServePodResources(endpoint string, providers podresources.PodResourcesProviders) {
|
||||||
server := grpc.NewServer(podresourcesgrpc.WithRateLimiter(podresourcesgrpc.DefaultQPS, podresourcesgrpc.DefaultBurstTokens))
|
server := grpc.NewServer(podresourcesgrpc.WithRateLimiter(podresourcesgrpc.DefaultQPS, podresourcesgrpc.DefaultBurstTokens))
|
||||||
|
|
||||||
podresourcesapiv1alpha1.RegisterPodResourcesListerServer(server, podresources.NewV1alpha1PodResourcesServer(providers))
|
podresourcesapiv1alpha1.RegisterPodResourcesListerServer(server, podresources.NewV1alpha1PodResourcesServer(providers))
|
||||||
podresourcesapi.RegisterPodResourcesListerServer(server, podresources.NewV1PodResourcesServer(providers))
|
podresourcesapi.RegisterPodResourcesListerServer(server, podresources.NewV1PodResourcesServer(providers))
|
||||||
|
|
||||||
l, err := util.CreateListener(socket)
|
l, err := util.CreateListener(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.ErrorS(err, "Failed to create listener for podResources endpoint")
|
klog.ErrorS(err, "Failed to create listener for podResources endpoint")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
klog.InfoS("Starting to serve the podresources API", "endpoint", endpoint)
|
||||||
if err := server.Serve(l); err != nil {
|
if err := server.Serve(l); err != nil {
|
||||||
klog.ErrorS(err, "Failed to serve")
|
klog.ErrorS(err, "Failed to serve")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -117,9 +118,27 @@ func parseEndpoint(endpoint string) (string, string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalEndpoint empty implementation
|
// LocalEndpoint returns the full path to a named pipe at the given endpoint - unlike on unix, we can't use sockets.
|
||||||
func LocalEndpoint(path, file string) (string, error) {
|
func LocalEndpoint(path, file string) (string, error) {
|
||||||
return "", fmt.Errorf("LocalEndpoints are unsupported in this build")
|
// extract the podresources config name from the path. We only need this on windows because the preferred layout of pipes,
|
||||||
|
// this is why we have the extra logic in here instead of changing the function signature. Join the file to make sure the
|
||||||
|
// last path component is a file, so the operation chain works..
|
||||||
|
podResourcesDir := filepath.Base(filepath.Dir(filepath.Join(path, file)))
|
||||||
|
if podResourcesDir == "" {
|
||||||
|
// should not happen because the user can configure a root directory, and we expected a subdirectory inside
|
||||||
|
// the user supplied root directory named like "pod-resources" or so.
|
||||||
|
return "", fmt.Errorf("cannot infer the podresources directory from path %q", path)
|
||||||
|
}
|
||||||
|
// windows pipes are expected to use forward slashes: https://learn.microsoft.com/windows/win32/ipc/pipe-names
|
||||||
|
// so using `url` like we do on unix gives us unclear benefits - see https://github.com/kubernetes/kubernetes/issues/78628
|
||||||
|
// So we just construct the path from scratch.
|
||||||
|
// Format: \\ServerName\pipe\PipeName
|
||||||
|
// Where where ServerName is either the name of a remote computer or a period, to specify the local computer.
|
||||||
|
// We only consider PipeName as regular windows path, while the pipe path components are fixed, hence we use constants.
|
||||||
|
serverPart := `\\.`
|
||||||
|
pipePart := "pipe"
|
||||||
|
pipeName := "kubelet-" + podResourcesDir
|
||||||
|
return npipeProtocol + "://" + filepath.Join(serverPart, pipePart, pipeName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")
|
var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")
|
||||||
|
@ -277,3 +277,48 @@ func TestNormalizePath(t *testing.T) {
|
|||||||
assert.Equal(t, test.normalizedPath, NormalizePath(test.originalpath))
|
assert.Equal(t, test.normalizedPath, NormalizePath(test.originalpath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocalEndpoint(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
path string
|
||||||
|
file string
|
||||||
|
expectError bool
|
||||||
|
expectedFullPath string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
path: "/var/lib/kubelet/pod-resources",
|
||||||
|
file: "kube.sock", // this is not the default, but it's not relevant here
|
||||||
|
expectError: false,
|
||||||
|
expectedFullPath: `npipe://\\.\pipe\kubelet-pod-resources`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
fullPath, err := LocalEndpoint(test.path, test.file)
|
||||||
|
if test.expectError {
|
||||||
|
assert.NotNil(t, err, "expected error")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
assert.Nil(t, err, "expected no error")
|
||||||
|
assert.Equal(t, test.expectedFullPath, fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocalEndpointRoundTrip(t *testing.T) {
|
||||||
|
npipeDialPointer := reflect.ValueOf(npipeDial).Pointer()
|
||||||
|
expectedDialerName := runtime.FuncForPC(npipeDialPointer).Name()
|
||||||
|
expectedAddress := "//./pipe/kubelet-pod-resources"
|
||||||
|
|
||||||
|
fullPath, err := LocalEndpoint(`pod-resources`, "kubelet")
|
||||||
|
require.NoErrorf(t, err, "Failed to create the local endpoint path")
|
||||||
|
|
||||||
|
address, dialer, err := GetAddressAndDialer(fullPath)
|
||||||
|
require.NoErrorf(t, err, "Failed to parse the endpoint path and get back address and dialer (path=%q)", fullPath)
|
||||||
|
|
||||||
|
dialerPointer := reflect.ValueOf(dialer).Pointer()
|
||||||
|
actualDialerName := runtime.FuncForPC(dialerPointer).Name()
|
||||||
|
|
||||||
|
assert.Equalf(t, npipeDialPointer, dialerPointer,
|
||||||
|
"Expected dialer %s, but get %s", expectedDialerName, actualDialerName)
|
||||||
|
|
||||||
|
assert.Equal(t, expectedAddress, address)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user