Skip to content

Commit c59afde

Browse files
authored
Added scheduler framework and basic functionality(#108)
Signed-off-by: xuzhonghu <[email protected]>
1 parent 0cfdbcd commit c59afde

File tree

21 files changed

+1036
-38
lines changed

21 files changed

+1036
-38
lines changed

Makefile

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,34 +27,45 @@ ifeq ($(VERSION), "")
2727
endif
2828
endif
2929

30-
all: karmada-controller-manager karmadactl
30+
all: karmada-controller-manager karmada-scheduler karmadactl
3131

3232
karmada-controller-manager: $(SOURCES)
3333
CGO_ENABLED=0 GOOS=$(GOOS) go build \
3434
-ldflags $(LDFLAGS) \
3535
-o karmada-controller-manager \
3636
cmd/controller-manager/controller-manager.go
3737

38+
karmada-scheduler: $(SOURCES)
39+
CGO_ENABLED=0 GOOS=$(GOOS) go build \
40+
-ldflags $(LDFLAGS) \
41+
-o karmada-scheduler \
42+
cmd/scheduler/main.go
43+
3844
karmadactl: $(SOURCES)
3945
CGO_ENABLED=0 GOOS=$(GOOS) go build \
4046
-ldflags $(LDFLAGS) \
4147
-o karmadactl \
4248
cmd/karmadactl/karmadactl.go
4349

4450
clean:
45-
rm -rf karmada-controller-manager
51+
rm -rf karmada-controller-manager karmada-scheduler karmadactl
4652

4753
.PHONY: test
4854
test:
4955
go test --race --v ./pkg/...
5056

51-
images: image-karmada-controller-manager
57+
images: image-karmada-controller-manager image-karmada-scheduler
5258

5359
image-karmada-controller-manager: karmada-controller-manager
5460
cp karmada-controller-manager cluster/images/karmada-controller-manager && \
5561
docker build -t $(REGISTRY)/karmada-controller-manager:$(VERSION) cluster/images/karmada-controller-manager && \
5662
rm cluster/images/karmada-controller-manager/karmada-controller-manager
5763

64+
image-karmada-scheduler: karmada-scheduler
65+
cp karmada-scheduler cluster/images/karmada-scheduler && \
66+
docker build -t $(REGISTRY)/karmada-scheduler:$(VERSION) cluster/images/karmada-scheduler && \
67+
rm cluster/images/karmada-scheduler/karmada-scheduler
68+
5869
upload-images: images
5970
@echo "push images to $(REGISTRY)"
6071
ifneq ($(REGISTRY_USER_NAME), "")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: karmada-scheduler
5+
namespace: karmada-system
6+
labels:
7+
app: karmada-scheduler
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
app: karmada-scheduler
13+
template:
14+
metadata:
15+
labels:
16+
app: karmada-scheduler
17+
spec:
18+
serviceAccountName: karmada-scheduler
19+
tolerations:
20+
- key: node-role.kubernetes.io/master
21+
operator: Exists
22+
containers:
23+
- name: karmada-scheduler
24+
image: swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-scheduler:latest
25+
imagePullPolicy: IfNotPresent
26+
command:
27+
- /bin/karmada-scheduler
28+
- --kubeconfig=/etc/kubeconfig
29+
volumeMounts:
30+
- name: kubeconfig
31+
subPath: kubeconfig
32+
mountPath: /etc/kubeconfig
33+
volumes:
34+
- name: kubeconfig
35+
secret:
36+
secretName: kubeconfig

artifacts/deploy/serviceaccount.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,9 @@ kind: ServiceAccount
33
metadata:
44
name: karmada-controller-manager
55
namespace: karmada-system
6+
---
7+
apiVersion: v1
8+
kind: ServiceAccount
9+
metadata:
10+
name: karmada-scheduler
11+
namespace: karmada-system
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM alpine:3.7
2+
3+
RUN apk add --no-cache ca-certificates
4+
5+
ADD karmada-scheduler /bin/
6+
7+
CMD ["/bin/karmada-scheduler"]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package options
2+
3+
import (
4+
"time"
5+
6+
"github.com/spf13/pflag"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/client-go/tools/leaderelection/resourcelock"
9+
componentbaseconfig "k8s.io/component-base/config"
10+
)
11+
12+
var (
13+
defaultElectionLeaseDuration = metav1.Duration{Duration: 15 * time.Second}
14+
defaultElectionRenewDeadline = metav1.Duration{Duration: 10 * time.Second}
15+
defaultElectionRetryPeriod = metav1.Duration{Duration: 2 * time.Second}
16+
)
17+
18+
// Options contains everything necessary to create and run controller-manager.
19+
type Options struct {
20+
LeaderElection componentbaseconfig.LeaderElectionConfiguration
21+
KubeConfig string
22+
Master string
23+
}
24+
25+
// NewOptions builds an default scheduler options.
26+
func NewOptions() *Options {
27+
return &Options{
28+
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
29+
LeaderElect: false,
30+
ResourceLock: resourcelock.LeasesResourceLock,
31+
LeaseDuration: defaultElectionLeaseDuration,
32+
RenewDeadline: defaultElectionRenewDeadline,
33+
RetryPeriod: defaultElectionRetryPeriod,
34+
},
35+
}
36+
}
37+
38+
// AddFlags adds flags of scheduler to the specified FlagSet
39+
func (o *Options) AddFlags(fs *pflag.FlagSet) {
40+
if o == nil {
41+
return
42+
}
43+
44+
fs.BoolVar(&o.LeaderElection.LeaderElect, "leader-elect", false, "Enable leader election, which must be true when running multi instances.")
45+
fs.StringVar(&o.LeaderElection.ResourceNamespace, "lock-namespace", "", "Define the namespace of the lock object.")
46+
fs.StringVar(&o.KubeConfig, "kubeconfig", o.KubeConfig, "Path to a KubeConfig. Only required if out-of-cluster.")
47+
fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server. Overrides any value in KubeConfig. Only required if out-of-cluster.")
48+
}

cmd/scheduler/app/scheduler.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package app
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"os"
8+
9+
"github.com/google/uuid"
10+
"github.com/spf13/cobra"
11+
"k8s.io/client-go/dynamic"
12+
"k8s.io/client-go/kubernetes"
13+
"k8s.io/client-go/rest"
14+
"k8s.io/client-go/tools/clientcmd"
15+
"k8s.io/client-go/tools/leaderelection"
16+
"k8s.io/client-go/tools/leaderelection/resourcelock"
17+
"k8s.io/klog/v2"
18+
19+
"github.com/karmada-io/karmada/cmd/scheduler/app/options"
20+
karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
21+
"github.com/karmada-io/karmada/pkg/scheduler"
22+
)
23+
24+
// NewSchedulerCommand creates a *cobra.Command object with default parameters
25+
func NewSchedulerCommand(stopChan <-chan struct{}) *cobra.Command {
26+
opts := options.NewOptions()
27+
28+
cmd := &cobra.Command{
29+
Use: "scheduler",
30+
Long: `The karmada scheduler binds resources to the clusters it manages.`,
31+
Run: func(cmd *cobra.Command, args []string) {
32+
if err := run(opts, stopChan); err != nil {
33+
fmt.Fprintf(os.Stderr, "%v\n", err)
34+
os.Exit(1)
35+
}
36+
},
37+
}
38+
39+
opts.AddFlags(cmd.Flags())
40+
cmd.Flags().AddGoFlagSet(flag.CommandLine)
41+
return cmd
42+
}
43+
44+
func run(opts *options.Options, stopChan <-chan struct{}) error {
45+
resetConfig, err := clientcmd.BuildConfigFromFlags(opts.Master, opts.KubeConfig)
46+
if err != nil {
47+
return fmt.Errorf("error building kubeconfig: %s", err.Error())
48+
}
49+
50+
dynamicClientSet := dynamic.NewForConfigOrDie(resetConfig)
51+
karmadaClient := karmadaclientset.NewForConfigOrDie(resetConfig)
52+
kubeClientSet := kubernetes.NewForConfigOrDie(resetConfig)
53+
54+
ctx, cancel := context.WithCancel(context.Background())
55+
go func() {
56+
<-stopChan
57+
cancel()
58+
}()
59+
60+
sched := scheduler.NewScheduler(dynamicClientSet, karmadaClient, kubeClientSet)
61+
if !opts.LeaderElection.LeaderElect {
62+
sched.Run(ctx)
63+
return fmt.Errorf("scheduler exited")
64+
}
65+
66+
leaderElectionClient, err := kubernetes.NewForConfig(rest.AddUserAgent(resetConfig, "leader-election"))
67+
if err != nil {
68+
return err
69+
}
70+
hostname, err := os.Hostname()
71+
if err != nil {
72+
return fmt.Errorf("unable to get hostname: %v", err)
73+
}
74+
// add a uniquifier so that two processes on the same host don't accidentally both become active
75+
id := hostname + "_" + uuid.New().String()
76+
77+
rl, err := resourcelock.New(opts.LeaderElection.ResourceLock,
78+
opts.LeaderElection.ResourceNamespace,
79+
"karmada-scheduler",
80+
leaderElectionClient.CoreV1(),
81+
leaderElectionClient.CoordinationV1(),
82+
resourcelock.ResourceLockConfig{
83+
Identity: id,
84+
})
85+
if err != nil {
86+
return fmt.Errorf("couldn't create resource lock: %v", err)
87+
}
88+
89+
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
90+
Lock: rl,
91+
LeaseDuration: opts.LeaderElection.LeaseDuration.Duration,
92+
RenewDeadline: opts.LeaderElection.RenewDeadline.Duration,
93+
RetryPeriod: opts.LeaderElection.RetryPeriod.Duration,
94+
Callbacks: leaderelection.LeaderCallbacks{
95+
OnStartedLeading: sched.Run,
96+
OnStoppedLeading: func() {
97+
klog.Fatalf("leaderelection lost")
98+
},
99+
},
100+
})
101+
102+
return nil
103+
}

cmd/scheduler/main.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import (
4+
apiserver "k8s.io/apiserver/pkg/server"
5+
"k8s.io/component-base/logs"
6+
"k8s.io/klog/v2"
7+
8+
"github.com/karmada-io/karmada/cmd/scheduler/app"
9+
)
10+
11+
func main() {
12+
logs.InitLogs()
13+
defer logs.FlushLogs()
14+
15+
// TODO: remove dependency on apiserver
16+
stopChan := apiserver.SetupSignalHandler()
17+
18+
if err := app.NewSchedulerCommand(stopChan).Execute(); err != nil {
19+
klog.Fatal(err.Error())
20+
}
21+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.14
44

55
require (
66
github.com/go-logr/logr v0.3.0 // indirect
7+
github.com/google/uuid v1.1.1
78
github.com/onsi/ginkgo v1.12.1
89
github.com/onsi/gomega v1.10.1
910
github.com/spf13/cobra v1.1.1

hack/deploy-karmada.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ waitPodReady $controller_pod_label "karmada-system"
8282
export KUBECONFIG=${KARMADA_APISERVER_CONFIG}
8383
installCRDs
8484

85-
# deploy controller-manager on host cluster
8685
export KUBECONFIG=${HOST_CLUSTER_KUBECONFIG}
86+
# deploy controller-manager on host cluster
8787
kubectl apply -f "${SCRIPT_ROOT}/artifacts/deploy/controller-manager.yaml"
88+
# deploy scheduler on host cluster
89+
kubectl apply -f "${SCRIPT_ROOT}/artifacts/deploy/karmada-scheduler.yaml"

hack/local-up-karmada.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ make images
3333
# load controller-manager image
3434
kind load docker-image "${REGISTRY}/karmada-controller-manager:${VERSION}" --name="${HOST_CLUSTER_NAME}"
3535

36+
# load scheduler image
37+
kind load docker-image "${REGISTRY}/karmada-scheduler:${VERSION}" --name="${HOST_CLUSTER_NAME}"
38+
3639
# deploy karmada control plane
3740
"${SCRIPT_ROOT}"/hack/deploy-karmada.sh
3841

0 commit comments

Comments
 (0)