Skip to content

Commit d7695c5

Browse files
authored
Merge pull request #42 from BetaCat0/feat-kubelet-proxy
feat: kubelet proxy
2 parents b761e47 + 405833a commit d7695c5

File tree

11 files changed

+585
-55
lines changed

11 files changed

+585
-55
lines changed

.golangci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ formatters:
1717
enable:
1818
- gofumpt
1919
- goimports
20+
21+
22+
run:
23+
tests: false

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build the manager binary
2-
FROM golang:1.22 as builder
2+
FROM golang:1.24 as builder
33
ARG TARGETOS
44
ARG TARGETARCH
55

@@ -36,4 +36,4 @@ EXPOSE 9090
3636
EXPOSE 8080
3737
EXPOSE 7777
3838

39-
ENTRYPOINT ["./module_controller"]
39+
ENTRYPOINT ["./module_controller"]

cmd/module-controller/main.go

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,46 @@ import (
1818
"context"
1919
"errors"
2020
"fmt"
21-
"github.com/koupleless/module_controller/common/zaplogger"
22-
"github.com/koupleless/module_controller/report_server"
23-
"github.com/koupleless/virtual-kubelet/vnode_controller"
2421
"os"
2522
"os/signal"
26-
ctrl "sigs.k8s.io/controller-runtime"
27-
"sigs.k8s.io/controller-runtime/pkg/healthz"
2823
"strconv"
2924
"syscall"
3025

3126
"github.com/google/uuid"
3227
"github.com/koupleless/module_controller/common/model"
28+
"github.com/koupleless/module_controller/common/zaplogger"
3329
"github.com/koupleless/module_controller/controller/module_deployment_controller"
3430
"github.com/koupleless/module_controller/module_tunnels/koupleless_http_tunnel"
3531
"github.com/koupleless/module_controller/module_tunnels/koupleless_mqtt_tunnel"
32+
"github.com/koupleless/module_controller/report_server"
33+
"github.com/koupleless/module_controller/staging/kubelet_proxy"
3634
"github.com/koupleless/virtual-kubelet/common/tracker"
3735
"github.com/koupleless/virtual-kubelet/common/utils"
3836
vkModel "github.com/koupleless/virtual-kubelet/model"
3937
"github.com/koupleless/virtual-kubelet/tunnel"
38+
"github.com/koupleless/virtual-kubelet/vnode_controller"
4039
"github.com/sirupsen/logrus"
4140
"github.com/virtual-kubelet/virtual-kubelet/log"
4241
logruslogger "github.com/virtual-kubelet/virtual-kubelet/log/logrus"
4342
"github.com/virtual-kubelet/virtual-kubelet/trace"
4443
"github.com/virtual-kubelet/virtual-kubelet/trace/opencensus"
44+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
45+
"k8s.io/client-go/kubernetes"
46+
ctrl "sigs.k8s.io/controller-runtime"
4547
"sigs.k8s.io/controller-runtime/pkg/cache"
4648
"sigs.k8s.io/controller-runtime/pkg/client/config"
49+
"sigs.k8s.io/controller-runtime/pkg/healthz"
4750
"sigs.k8s.io/controller-runtime/pkg/manager"
4851
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
4952
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
5053
)
5154

55+
const (
56+
certFilePath = "/etc/virtual-kubelet/tls/tls.crt"
57+
keyFilePath = "/etc/virtual-kubelet/tls/tls.key"
58+
DefaultKubeletHttpListenAddr = "10250" // Default listen address for the HTTP server
59+
)
60+
5261
// Main function for the module controller
5362
// Responsibilities:
5463
// 1. Sets up signal handling for graceful shutdown
@@ -59,6 +68,7 @@ import (
5968
// 6. Creates and configures the VNode controller
6069
// 7. Optionally creates module deployment controller
6170
// 8. Starts all tunnels and the manager
71+
// 9. Starts the kubelet proxy server(if enabled)
6272

6373
func main() {
6474
ctx, cancel := context.WithCancel(context.Background())
@@ -75,27 +85,29 @@ func main() {
7585
trace.T = opencensus.Adapter{}
7686

7787
// Get configuration from environment variables
78-
clientID := utils.GetEnv("CLIENT_ID", uuid.New().String())
88+
clientID := utils.GetEnv(model.EnvKeyOfClientID, uuid.New().String())
7989
env := utils.GetEnv("ENV", "dev")
8090

8191
zlogger := zaplogger.GetLogger()
8292
ctx = zaplogger.WithLogger(ctx, zlogger)
8393

8494
// Parse configuration with defaults
85-
isCluster := utils.GetEnv("IS_CLUSTER", "") == "true"
86-
workloadMaxLevel, err := strconv.Atoi(utils.GetEnv("WORKLOAD_MAX_LEVEL", "3"))
95+
isCluster := utils.GetEnv(model.EnvKeyOfClusterModeEnabled, "") == "true"
96+
workloadMaxLevel, err := strconv.Atoi(utils.GetEnv(model.EnvKeyOfWorkloadMaxLevel, "3"))
8797

8898
if err != nil {
8999
zlogger.Error(err, "failed to parse WORKLOAD_MAX_LEVEL, will be set to 3 default")
90100
workloadMaxLevel = 3
91101
}
92102

93-
vnodeWorkerNum, err := strconv.Atoi(utils.GetEnv("VNODE_WORKER_NUM", "8"))
103+
vnodeWorkerNum, err := strconv.Atoi(utils.GetEnv(model.EnvKeyOfVNodeWorkerNum, "8"))
94104
if err != nil {
95105
zlogger.Error(err, "failed to parse VNODE_WORKER_NUM, will be set to 8 default")
96106
vnodeWorkerNum = 8
97107
}
98108

109+
deployNamespace := utils.GetEnv(model.EnvKeyOfNamespace, "default")
110+
99111
// Initialize controller manager
100112
kubeConfig := config.GetConfigOrDie()
101113
// TODO: should support to set from parameter
@@ -111,14 +123,25 @@ func main() {
111123
BindAddress: ":9090",
112124
},
113125
})
114-
115126
if err != nil {
116127
zlogger.Error(err, "unable to set up overall controller manager")
117128
os.Exit(1)
118129
}
119130

120131
tracker.SetTracker(&tracker.DefaultTracker{})
121132

133+
k8sClientSet := kubernetes.NewForConfigOrDie(kubeConfig)
134+
135+
var moduleControllerServiceIP string
136+
var kubeletProxyEnabled bool
137+
if os.Getenv(model.EnvKeyOfKubeletProxyEnabled) == "true" {
138+
moduleControllerServiceIP, err = lookupProxyServiceIP(ctx, deployNamespace, k8sClientSet)
139+
if err != nil {
140+
log.G(ctx).Fatalf("Failed to lookup kubelet proxy service IP: %v", err)
141+
}
142+
kubeletProxyEnabled = true
143+
}
144+
122145
// Configure and create VNode controller
123146
vNodeControllerConfig := vkModel.BuildVNodeControllerConfig{
124147
ClientID: clientID,
@@ -127,6 +150,8 @@ func main() {
127150
IsCluster: isCluster,
128151
WorkloadMaxLevel: workloadMaxLevel,
129152
VNodeWorkerNum: vnodeWorkerNum,
153+
// vnode ip will fall back to the ip of the base pod if not set
154+
PseudoNodeIP: moduleControllerServiceIP,
130155
}
131156

132157
moduleDeploymentController, err := module_deployment_controller.NewModuleDeploymentController(env)
@@ -164,6 +189,21 @@ func main() {
164189
os.Exit(1)
165190
}
166191

192+
if kubeletProxyEnabled {
193+
zlogger.Info("starting kubelet proxy server")
194+
err := kubelet_proxy.StartKubeletProxy(
195+
ctx,
196+
certFilePath,
197+
keyFilePath,
198+
":"+utils.GetEnv(model.EnvKeyOfKubeletProxyPort, DefaultKubeletHttpListenAddr),
199+
k8sClientSet,
200+
)
201+
if err != nil {
202+
zlogger.Error(err, "failed to start kubelet proxy server")
203+
os.Exit(1)
204+
}
205+
}
206+
167207
zlogger.Info("Module controller running")
168208
err = k8sControllerManager.Start(signals.SetupSignalHandler())
169209
if err != nil {
@@ -218,3 +258,25 @@ func startTunnels(ctx context.Context, clientId string, env string, mgr manager.
218258
// we only using one tunnel for now
219259
return tunnels[0]
220260
}
261+
262+
// lookupProxyServiceIP retrieves the ClusterIP of the kubelet proxy service in the specified namespace.
263+
func lookupProxyServiceIP(ctx context.Context, namespace string, clientSet kubernetes.Interface) (string, error) {
264+
svcList, err := clientSet.CoreV1().Services(namespace).List(ctx, metav1.ListOptions{
265+
LabelSelector: fmt.Sprintf("%s=%s", model.LabelKeyOfKubeletProxyService, "true"),
266+
})
267+
if err != nil {
268+
return "", fmt.Errorf("failed to list services in namespace %s: %w", namespace, err)
269+
}
270+
if len(svcList.Items) == 0 {
271+
return "", fmt.Errorf("no kubelet proxy service found in namespace %s", namespace)
272+
}
273+
if len(svcList.Items) > 1 {
274+
return "", fmt.Errorf("multiple kubelet proxy services deteched in namespace %s, expected only one", namespace)
275+
}
276+
277+
firstSvc := svcList.Items[0]
278+
if firstSvc.Spec.ClusterIP == "" || firstSvc.Spec.ClusterIP == "None" {
279+
return "", fmt.Errorf("kubelet proxy service %s in namespace %s has no valid ClusterIP", firstSvc.Name, namespace)
280+
}
281+
return firstSvc.Spec.ClusterIP, nil
282+
}

common/model/consts.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ const (
1414
LabelKeyOfSkipReplicasControl = "virtual-kubelet.koupleless.io/replicas-control"
1515
// LabelKeyOfVPodDeploymentStrategy specifies the deployment strategy
1616
LabelKeyOfVPodDeploymentStrategy = "virtual-kubelet.koupleless.io/strategy"
17+
// LabelKeyOfKubeletProxyService indicates the kubelet proxy service
18+
LabelKeyOfKubeletProxyService = "virtual-kubelet.koupleless.io/kubelet-proxy-service"
19+
)
20+
21+
// Env keys for module controller
22+
const (
23+
// EnvKeyOfClientID is the environment variable key for the client ID
24+
EnvKeyOfClientID = "CLIENT_ID"
25+
// EnvKeyOfNamespace is the environment variable key for the deployment namespace, default to "default"
26+
EnvKeyOfNamespace = "NAMESPACE"
27+
// EnvKeyOfENV is the environment variable key for the environment label
28+
EnvKeyOfENV = "ENV"
29+
// EnvKeyOfClusterModeEnabled is the environment variable key for the cluster flag, use "true" or "false"
30+
EnvKeyOfClusterModeEnabled = "IS_CLUSTER"
31+
// EnvKeyOfWorkloadMaxLevel is the environment variable key for the maximum workload level
32+
EnvKeyOfWorkloadMaxLevel = "WORKLOAD_MAX_LEVEL"
33+
// EnvKeyOfVNodeWorkerNum is the environment variable key for the number of vnode worker threads
34+
EnvKeyOfVNodeWorkerNum = "VNODE_WORKER_NUM"
35+
// EnvKeyOfKubeletProxyEnabled is the environment variable key for enabling kubelet proxy
36+
EnvKeyOfKubeletProxyEnabled = "KUBELET_PROXY_ENABLED"
37+
// EnvKeyOfKubeletProxyPort is the environment variable key for the kubelet proxy port
38+
EnvKeyOfKubeletProxyPort = "KUBELET_PROXY_PORT"
1739
)
1840

1941
// Component types

debug.Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build the manager binary
2-
FROM golang:1.22 as builder
2+
FROM golang:1.24 as builder
33
ARG TARGETOS
44
ARG TARGETARCH
55

@@ -43,4 +43,4 @@ EXPOSE 7777
4343
EXPOSE 2345
4444

4545
#ENTRYPOINT ["dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./module_controller"]
46-
CMD ["/bin/sh", "-c", "tail -f /dev/null"]
46+
CMD ["/bin/sh", "-c", "tail -f /dev/null"]

go.mod

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
module github.com/koupleless/module_controller
22

3-
go 1.22.0
3+
go 1.23.0
44

5-
toolchain go1.22.4
5+
toolchain go1.24.5
66

77
require (
88
github.com/eclipse/paho.mqtt.golang v1.5.0
99
github.com/go-logr/logr v1.4.2
1010
github.com/go-resty/resty/v2 v2.11.0
1111
github.com/google/uuid v1.6.0
1212
github.com/koupleless/arkctl v0.2.4-0.20250106035535-5ed5cb871995
13-
github.com/koupleless/virtual-kubelet v0.3.8
13+
github.com/koupleless/virtual-kubelet v0.3.9
1414
github.com/onsi/ginkgo/v2 v2.19.0
1515
github.com/onsi/gomega v1.33.1
1616
github.com/sirupsen/logrus v1.9.3
17-
github.com/stretchr/testify v1.9.0
17+
github.com/stretchr/testify v1.10.0
1818
github.com/virtual-kubelet/virtual-kubelet v1.11.0
1919
github.com/wind-c/comqtt/v2 v2.6.0
2020
k8s.io/api v0.31.0
@@ -27,6 +27,7 @@ require (
2727

2828
require (
2929
github.com/beorn7/perks v1.0.1 // indirect
30+
github.com/blang/semver/v4 v4.0.0 // indirect
3031
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3132
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3233
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
@@ -42,22 +43,26 @@ require (
4243
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
4344
github.com/golang/protobuf v1.5.4 // indirect
4445
github.com/google/gnostic-models v0.6.8 // indirect
45-
github.com/google/go-cmp v0.6.0 // indirect
46+
github.com/google/go-cmp v0.7.0 // indirect
4647
github.com/google/gofuzz v1.2.0 // indirect
4748
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
49+
github.com/gorilla/mux v1.8.0 // indirect
4850
github.com/gorilla/websocket v1.5.3 // indirect
4951
github.com/imdario/mergo v0.3.12 // indirect
5052
github.com/josharian/intern v1.0.0 // indirect
5153
github.com/json-iterator/go v1.1.12 // indirect
54+
github.com/klauspost/compress v1.17.9 // indirect
5255
github.com/mailru/easyjson v0.7.7 // indirect
56+
github.com/moby/spdystream v0.4.0 // indirect
5357
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
5458
github.com/modern-go/reflect2 v1.0.2 // indirect
5559
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
60+
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
5661
github.com/pkg/errors v0.9.1 // indirect
5762
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
58-
github.com/prometheus/client_golang v1.19.1 // indirect
59-
github.com/prometheus/client_model v0.6.1 // indirect
60-
github.com/prometheus/common v0.55.0 // indirect
63+
github.com/prometheus/client_golang v1.20.4 // indirect
64+
github.com/prometheus/client_model v0.6.2 // indirect
65+
github.com/prometheus/common v0.64.0 // indirect
6166
github.com/prometheus/procfs v0.15.1 // indirect
6267
github.com/rs/xid v1.5.0 // indirect
6368
github.com/spf13/pflag v1.0.5 // indirect
@@ -66,21 +71,23 @@ require (
6671
go.uber.org/multierr v1.11.0 // indirect
6772
go.uber.org/zap v1.27.0 // indirect
6873
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
69-
golang.org/x/net v0.27.0 // indirect
70-
golang.org/x/oauth2 v0.21.0 // indirect
71-
golang.org/x/sync v0.7.0 // indirect
72-
golang.org/x/sys v0.22.0 // indirect
73-
golang.org/x/term v0.22.0 // indirect
74-
golang.org/x/text v0.16.0 // indirect
74+
golang.org/x/net v0.40.0 // indirect
75+
golang.org/x/oauth2 v0.30.0 // indirect
76+
golang.org/x/sync v0.14.0 // indirect
77+
golang.org/x/sys v0.33.0 // indirect
78+
golang.org/x/term v0.32.0 // indirect
79+
golang.org/x/text v0.25.0 // indirect
7580
golang.org/x/time v0.5.0 // indirect
7681
golang.org/x/tools v0.23.0 // indirect
7782
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
78-
google.golang.org/protobuf v1.34.2 // indirect
83+
google.golang.org/protobuf v1.36.6 // indirect
7984
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
8085
gopkg.in/inf.v0 v0.9.1 // indirect
8186
gopkg.in/yaml.v2 v2.4.0 // indirect
8287
gopkg.in/yaml.v3 v3.0.1 // indirect
8388
k8s.io/apiextensions-apiserver v0.31.0 // indirect
89+
k8s.io/apiserver v0.31.0 // indirect
90+
k8s.io/component-base v0.31.0 // indirect
8491
k8s.io/klog/v2 v2.130.1 // indirect
8592
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
8693
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect

0 commit comments

Comments
 (0)