Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Windows support to kruise-daemon #1909

Merged
merged 13 commits into from
Mar 7, 2025
11 changes: 11 additions & 0 deletions Dockerfile_windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Build Windows image for kruise-daemon

# Using Windows HostProcess container base image: https://github.com/microsoft/windows-host-process-containers-base-image
ARG BASE_IMAGE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image
ARG BASE_IMAGE_VERSION=v1.0.0
FROM ${BASE_IMAGE}:${BASE_IMAGE_VERSION}

WORKDIR /
COPY ./bin/kruise-daemon.exe .

ENTRYPOINT ["kruise-daemon.exe"]
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Image URL to use all building/pushing image targets
IMG ?= openkruise/kruise-manager:test
HOOK_IMG ?= openkruise/kruise-helm-hook:test
WIN_DAEMON_IMG ?= openkruise/kruise-daemon-win:test
# Platforms to build the image for
PLATFORMS ?= linux/amd64,linux/arm64,linux/ppc64le
WIN_PLATFORMS ?= windows/amd64
CRD_OPTIONS ?= "crd:crdVersions=v1"

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
Expand Down Expand Up @@ -72,6 +74,9 @@ endif
build: generate fmt vet manifests ## Build manager binary.
go build -o bin/manager main.go

build-win-daemon: ## Build Windows daemon binary.
GOOS=windows go build -o bin/kruise-daemon.exe ./cmd/daemon/main.go

run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go

Expand All @@ -81,6 +86,9 @@ docker-build: ## Build docker image with the manager.
docker-push: ## Push docker image with the manager.
docker push ${IMG}

docker-win-daemon: # Build Windows docker image with the daemon
docker buildx build -f ./Dockerfile_windows --pull --no-cache --platform=$(WIN_PLATFORMS) . -t $(WIN_DAEMON_IMG)

# Build and push the multiarchitecture docker images and manifest.
docker-multiarch:
docker buildx build -f ./Dockerfile_multiarch --pull --no-cache --platform=$(PLATFORMS) --push . -t $(IMG)
Expand Down
84 changes: 84 additions & 0 deletions hack/daemon/daemon-windows.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
control-plane: daemon
name: kruise-daemon-win
namespace: kruise-system
spec:
selector:
matchLabels:
control-plane: daemon
template:
metadata:
labels:
control-plane: daemon
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: NotIn
values:
- virtual-kubelet
containers:
- args:
- --logtostderr=true
- --v=5
- --addr=:10221
- --feature-gates=ImagePullJobGate=true
- --enable-pprof=true
- --pprof-addr=localhost:10222
workingDir: "$env:CONTAINER_SANDBOX_MOUNT_POINT/"
command:
- $env:CONTAINER_SANDBOX_MOUNT_POINT/kruise-daemon.exe
env:
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: openkruise/kruise-daemon-win:test # Replace with the actual image
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10221
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: daemon
resources:
limits:
cpu: 50m
memory: 128Mi
requests:
cpu: "0"
memory: "0"
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
windowsOptions:
hostProcess: true
runAsUserName: "NT AUTHORITY\\SYSTEM"
serviceAccount: kruise-daemon
serviceAccountName: kruise-daemon
terminationGracePeriodSeconds: 10
tolerations:
- operator: Exists
nodeSelector:
kubernetes.io/os: windows
updateStrategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 10%
type: RollingUpdate
90 changes: 3 additions & 87 deletions pkg/daemon/criruntime/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,14 @@

import (
"context"
"flag"
"fmt"
"os"
"time"

oteltrace "go.opentelemetry.io/otel/trace"
criapi "k8s.io/cri-api/pkg/apis"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
"k8s.io/klog/v2"
criremote "k8s.io/kubernetes/pkg/kubelet/cri/remote"
kubeletutil "k8s.io/kubernetes/pkg/kubelet/util"

runtimeimage "github.com/openkruise/kruise/pkg/daemon/criruntime/imageruntime"
daemonutil "github.com/openkruise/kruise/pkg/daemon/util"
Expand All @@ -38,10 +35,6 @@
kubeRuntimeAPIVersion = "0.1.0"
)

var (
CRISocketFileName = flag.String("socket-file", "", "The name of CRI socket file, and it should be in the mounted /hostvarrun directory.")
)

// Factory is the interface to get container and image runtime service
type Factory interface {
GetImageService() runtimeimage.ImageService
Expand Down Expand Up @@ -73,8 +66,8 @@
runtimeService criapi.RuntimeService
}

func NewFactory(varRunPath string, accountManager daemonutil.ImagePullAccountManager) (Factory, error) {
cfgs := detectRuntime(varRunPath)
func NewFactory(accountManager daemonutil.ImagePullAccountManager) (Factory, error) {
cfgs := detectRuntime()

Check warning on line 70 in pkg/daemon/criruntime/factory.go

View check run for this annotation

Codecov / codecov/patch

pkg/daemon/criruntime/factory.go#L69-L70

Added lines #L69 - L70 were not covered by tests
if len(cfgs) == 0 {
return nil, fmt.Errorf("not found container runtime sock")
}
Expand All @@ -89,12 +82,7 @@
var runtimeService criapi.RuntimeService
var typedVersion *runtimeapi.VersionResponse

addr, _, err := kubeletutil.GetAddressAndDialer(cfg.runtimeRemoteURI)
if err != nil {
klog.ErrorS(err, "Failed to get address", "runtimeType", cfg.runtimeType, "runtimeURI", cfg.runtimeURI, "runtimeRemoteURI", cfg.runtimeRemoteURI)
continue
}
imageService, err = runtimeimage.NewCRIImageService(addr, accountManager)
imageService, err = newImageService(cfg, accountManager)

Check warning on line 85 in pkg/daemon/criruntime/factory.go

View check run for this annotation

Codecov / codecov/patch

pkg/daemon/criruntime/factory.go#L85

Added line #L85 was not covered by tests
if err != nil {
klog.ErrorS(err, "Failed to new image service", "runtimeType", cfg.runtimeType, "runtimeURI", cfg.runtimeURI, "runtimeRemoteURI", cfg.runtimeRemoteURI)
continue
Expand Down Expand Up @@ -147,75 +135,3 @@
}
return nil
}

func detectRuntime(varRunPath string) (cfgs []runtimeConfig) {
var err error

// firstly check if it is configured from flag
if CRISocketFileName != nil && len(*CRISocketFileName) > 0 {
filePath := fmt.Sprintf("%s/%s", varRunPath, *CRISocketFileName)
if _, err = os.Stat(filePath); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/%s", varRunPath, *CRISocketFileName),
})
klog.InfoS("Find configured CRI socket with given flag", "filePath", filePath)
} else {
klog.ErrorS(err, "Failed to stat the CRI socket with given flag", "filePath", filePath)
}
return
}

// if the flag is not set, then try to find runtime in the recognized types and paths.

// containerd, with the same behavior of pullImage as commonCRI
{
if _, err = os.Stat(fmt.Sprintf("%s/containerd.sock", varRunPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeContainerd,
runtimeRemoteURI: fmt.Sprintf("unix://%s/containerd.sock", varRunPath),
})
}
if _, err = os.Stat(fmt.Sprintf("%s/containerd/containerd.sock", varRunPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeContainerd,
runtimeRemoteURI: fmt.Sprintf("unix://%s/containerd/containerd.sock", varRunPath),
})
}
}

// cri-o
{
if _, err = os.Stat(fmt.Sprintf("%s/crio.sock", varRunPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/crio.sock", varRunPath),
})
}
if _, err = os.Stat(fmt.Sprintf("%s/crio/crio.sock", varRunPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/crio/crio.sock", varRunPath),
})
}
}

// cri-docker dockerd as a compliant Container Runtime Interface, detail see https://github.com/Mirantis/cri-dockerd
{
if _, err = os.Stat(fmt.Sprintf("%s/cri-dockerd.sock", varRunPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/cri-dockerd.sock", varRunPath),
})
}
// Check if the cri-dockerd runtime socket exists in the expected k3s runtime directory.
// If found, append it to the runtime configuration list to ensure k3s can use cri-dockerd.
if _, err = os.Stat(fmt.Sprintf("%s/cri-dockerd/cri-dockerd.sock", varRunPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/cri-dockerd/cri-dockerd.sock", varRunPath),
})
}
}
return cfgs
}
121 changes: 121 additions & 0 deletions pkg/daemon/criruntime/factory_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//go:build !windows
// +build !windows

/*
Copyright 2021 The Kruise Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package criruntime

import (
"flag"
"fmt"
"os"

runtimeimage "github.com/openkruise/kruise/pkg/daemon/criruntime/imageruntime"
daemonutil "github.com/openkruise/kruise/pkg/daemon/util"
"k8s.io/klog/v2"
kubeletutil "k8s.io/kubernetes/pkg/kubelet/util"
)

const (
varRunMountPath = "/hostvarrun"
)

var (
statFunc = os.Stat
criSocketFileName = flag.String("socket-file", "", "The name of CRI socket file, and it should be in the mounted /hostvarrun directory.")
)

func detectRuntime() (cfgs []runtimeConfig) {
var err error

// firstly check if it is configured from flag
if criSocketFileName != nil && len(*criSocketFileName) > 0 {
filePath := fmt.Sprintf("%s/%s", varRunMountPath, *criSocketFileName)
if _, err = statFunc(filePath); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/%s", varRunMountPath, *criSocketFileName),
})
klog.InfoS("Find configured CRI socket with given flag", "filePath", filePath)
} else {
klog.ErrorS(err, "Failed to stat the CRI socket with given flag", "filePath", filePath)
}
return
}

// if the flag is not set, then try to find runtime in the recognized types and paths.

// containerd, with the same behavior of pullImage as commonCRI
{
if _, err = statFunc(fmt.Sprintf("%s/containerd.sock", varRunMountPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeContainerd,
runtimeRemoteURI: fmt.Sprintf("unix://%s/containerd.sock", varRunMountPath),
})
}
if _, err = statFunc(fmt.Sprintf("%s/containerd/containerd.sock", varRunMountPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeContainerd,
runtimeRemoteURI: fmt.Sprintf("unix://%s/containerd/containerd.sock", varRunMountPath),
})
}
}

// cri-o
{
if _, err = statFunc(fmt.Sprintf("%s/crio.sock", varRunMountPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/crio.sock", varRunMountPath),
})
}
if _, err = statFunc(fmt.Sprintf("%s/crio/crio.sock", varRunMountPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/crio/crio.sock", varRunMountPath),
})
}
}

// cri-docker dockerd as a compliant Container Runtime Interface, detail see https://github.com/Mirantis/cri-dockerd
{
if _, err = statFunc(fmt.Sprintf("%s/cri-dockerd.sock", varRunMountPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/cri-dockerd.sock", varRunMountPath),
})
}
// Check if the cri-dockerd runtime socket exists in the expected k3s runtime directory.
// If found, append it to the runtime configuration list to ensure k3s can use cri-dockerd.
if _, err = statFunc(fmt.Sprintf("%s/cri-dockerd/cri-dockerd.sock", varRunMountPath)); err == nil {
cfgs = append(cfgs, runtimeConfig{
runtimeType: ContainerRuntimeCommonCRI,
runtimeRemoteURI: fmt.Sprintf("unix://%s/cri-dockerd/cri-dockerd.sock", varRunMountPath),
})
}
}
return cfgs
}

func newImageService(cfg runtimeConfig, accountManager daemonutil.ImagePullAccountManager) (runtimeimage.ImageService, error) {
addr, _, err := kubeletutil.GetAddressAndDialer(cfg.runtimeRemoteURI)
if err != nil {
klog.ErrorS(err, "Failed to get address", "runtimeType", cfg.runtimeType, "runtimeURI", cfg.runtimeURI, "runtimeRemoteURI", cfg.runtimeRemoteURI)
return nil, err
}
return runtimeimage.NewCRIImageService(addr, accountManager)

Check warning on line 120 in pkg/daemon/criruntime/factory_unix.go

View check run for this annotation

Codecov / codecov/patch

pkg/daemon/criruntime/factory_unix.go#L114-L120

Added lines #L114 - L120 were not covered by tests
}
Loading
Loading