Skip to content

Commit 56f9316

Browse files
authored
Merge pull request #3 from KusionStack/master-read
chore: e2e & bug fix & update readme
2 parents 899e833 + dfe80dd commit 56f9316

30 files changed

+832
-37
lines changed

README.md

+20-21
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The design architecture of this project is based on [openkruise/controllermesh](
1616
3. **Circuit breaker and rate limiter**: Not only Kubernetes operation requests, but also other external operation requests.
1717
4. **Multicluster routing and sharding**: This feature is supported by [kusionstack/kaera(karbour)]()
1818

19-
<p align="center"><img width="800" src="./docs/img/img2.png"/></p>
19+
<p align="center"><img width="800" src="./docs/img/img4.png"/></p>
2020

2121
## Quick Start
2222
Visit [Quick Start]().
@@ -71,28 +71,27 @@ spec:
7171
certDir: /tmp/webhook-certs
7272
port: 9443
7373
limits:
74-
- objectSelector:
75-
relateResources:
76-
- apiGroups:
77-
- '*'
78-
resources:
79-
- pods
80-
- services
81-
selector:
82-
matchExpressions:
83-
- key: kridge.kusionstack.io/namespace
84-
operator: In
85-
values:
86-
- ns-a
87-
- ns-b
88-
matchLabels:
89-
# ...
90-
selector:
91-
matchExpressions:
92-
- key: statefulset.kubernetes.io/pod-name
74+
- relateResources:
75+
- apiGroups:
76+
- '*'
77+
resources:
78+
- pods
79+
- services
80+
selector:
81+
matchExpressions:
82+
- key: kridge.kusionstack.io/namespace
9383
operator: In
9484
values:
95-
- operator-demo-0
85+
- ns-a
86+
- ns-b
87+
matchLabels:
88+
# ...
89+
selector:
90+
matchExpressions:
91+
- key: statefulset.kubernetes.io/pod-name
92+
operator: In
93+
values:
94+
- operator-demo-0
9695
```
9796
9897
- selector: for all pods under a shard. It can be a subset of pods under a StatefulSet.

artifacts/images/custom.Dockerfile

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Build the manager binary
2+
FROM golang:1.19 as builder
3+
4+
WORKDIR /workspace
5+
6+
COPY go.mod go.mod
7+
COPY go.sum go.sum
8+
COPY e2e/ e2e/
9+
COPY vendor/ vendor/
10+
11+
RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64 go build -mod=vendor -a -o testapp ./e2e/customoperator/app/main.go
12+
13+
14+
FROM ubuntu:focal
15+
16+
17+
RUN apt-get update && \
18+
apt-get install --no-install-recommends -y \
19+
ca-certificates \
20+
curl \
21+
iputils-ping \
22+
tcpdump \
23+
iproute2 \
24+
iptables \
25+
net-tools \
26+
telnet \
27+
lsof \
28+
linux-tools-generic \
29+
sudo && \
30+
apt-get clean && \
31+
rm -rf /var/log/*log /var/lib/apt/lists/* /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old
32+
33+
WORKDIR /
34+
COPY --from=builder /workspace/testapp .
35+
ENTRYPOINT ["/testapp"]

artifacts/images/manager.Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build the manager binary
2-
FROM golang:1.19 as builder
2+
FROM golang:1.20 as builder
33

44
WORKDIR /workspace
55

artifacts/images/proxy.Dockerfile

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.19 as builder
1+
FROM golang:1.20 as builder
22

33
WORKDIR /workspace
44

@@ -8,7 +8,7 @@ COPY artifacts/ artifacts/
88
COPY pkg/ pkg/
99
COPY vendor/ vendor/
1010

11-
RUN CGO_ENABLED=0 GO111MODULE=on go build -mod=vendor -a -o kridge-proxy ./pkg/cmd/proxy/main.go
11+
RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64 go build -mod=vendor -a -o kridge-proxy ./pkg/cmd/proxy/main.go
1212

1313
FROM ubuntu:focal
1414

@@ -33,6 +33,6 @@ RUN useradd -m --uid 1359 kridge-proxy && \
3333
echo "kridge-proxy ALL=NOPASSWD: ALL" >> /etc/sudoers
3434
WORKDIR /
3535
COPY artifacts/scripts/proxy-poststart.sh /poststart.sh
36-
36+
RUN mkdir /kridge && chmod 777 /kridge
3737
COPY --from=builder /workspace/kridge-proxy .
3838
ENTRYPOINT ["/kridge-proxy"]

docs/img/img4.png

289 KB
Loading

docs/installation.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
## Installation
3+
4+
**Install by helm**
5+
```shell
6+
# Firstly add charts repository if you haven't do this.
7+
$ helm repo add kusionstack https://kusionstack.github.io/charts/
8+
9+
# [Optional]
10+
$ helm repo update
11+
12+
# Install the latest version.
13+
$ helm install kridge kusionstack/kridge --version 0.0.x
14+
15+
# Uninstall
16+
$ helm uninstall kridge
17+
```
18+

docs/intro.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
# Kridge
4+
5+
Kridge is a solution that helps developers manage their controllers/operators better.
6+
7+
The design architecture of this project is based on [openkruise/controllermesh](https://github.com/openkruise/controllermesh).
8+
9+
## Key Features
10+
11+
1. **Sharding**: Through relevant configurations, Kubernetes single-point deployed operator applications can be flexibly shard deployed.
12+
2. **Canary upgrade**: Depends on sharding, the controllers can be updated in canary progress instead of one time replace.
13+
3. **Circuit breaker and rate limiter**: Not only Kubernetes operation requests, but also other external operation requests.
14+
4. **Multicluster routing and sharding**: This feature is supported by [kusionstack/kaera(karbour)]()
15+
16+
<p align="center"><img width="800" src="../docs/img/img4.png"/></p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Copyright 2023 The KusionStack Authors.
3+
Modified from Kruise code, Copyright 2021 The Kruise Authors.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package controller
19+
20+
import (
21+
"context"
22+
"os"
23+
24+
v1 "k8s.io/api/core/v1"
25+
"k8s.io/client-go/util/workqueue"
26+
"k8s.io/klog/v2"
27+
ctrl "sigs.k8s.io/controller-runtime"
28+
"sigs.k8s.io/controller-runtime/pkg/client"
29+
"sigs.k8s.io/controller-runtime/pkg/event"
30+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
31+
"sigs.k8s.io/controller-runtime/pkg/source"
32+
)
33+
34+
var (
35+
podName, podNamespace string
36+
)
37+
38+
// ManagerStateReconciler reconciles a ManagerState object
39+
type PodReconciler struct {
40+
client.Client
41+
DirectorClient client.Client
42+
}
43+
44+
func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, err error) {
45+
return reconcile.Result{}, nil
46+
}
47+
48+
// SetupWithManager sets up the controller with the Manager.
49+
func (r *PodReconciler) SetupWithManager(mgr ctrl.Manager) error {
50+
podNamespace = os.Getenv("POD_NAMESPACE")
51+
podName = os.Getenv("POD_NAME")
52+
// default handler.EnqueueRequestForObject
53+
return ctrl.NewControllerManagedBy(mgr).
54+
For(&v1.Pod{}).
55+
Watches(&source.Kind{Type: &v1.Pod{}}, &enqueueHandler{Client: r.DirectorClient, kind: "Pod"}).
56+
Watches(&source.Kind{Type: &v1.ConfigMap{}}, &enqueueHandler{Client: r.DirectorClient, kind: "ConfigMap"}).
57+
Complete(r)
58+
}
59+
60+
type enqueueHandler struct {
61+
client.Client
62+
kind string
63+
}
64+
65+
func (e *enqueueHandler) Create(event event.CreateEvent, q workqueue.RateLimitingInterface) {
66+
Add(e.Client, event.Object.GetNamespace(), event.Object.GetName(), e.kind)
67+
}
68+
69+
func (e *enqueueHandler) Update(event event.UpdateEvent, q workqueue.RateLimitingInterface) {
70+
Add(e.Client, event.ObjectNew.GetNamespace(), event.ObjectNew.GetName(), e.kind)
71+
}
72+
73+
func (e *enqueueHandler) Delete(event event.DeleteEvent, q workqueue.RateLimitingInterface) {
74+
Add(e.Client, event.Object.GetNamespace(), event.Object.GetName(), e.kind)
75+
}
76+
77+
func (e *enqueueHandler) Generic(event event.GenericEvent, q workqueue.RateLimitingInterface) {
78+
Add(e.Client, event.Object.GetNamespace(), event.Object.GetName(), e.kind)
79+
}
80+
81+
func Add(c client.Client, namespace, name, kind string) {
82+
klog.Infof("handle event %s %s/%s", kind, namespace, name)
83+
if err := add(c, namespace, kind); err != nil {
84+
klog.Errorf("fail to record event %s %s/%s, %v", kind, namespace, name, err)
85+
}
86+
}
+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package controller
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"strings"
8+
"time"
9+
10+
v1 "k8s.io/api/core/v1"
11+
"k8s.io/apimachinery/pkg/types"
12+
"k8s.io/apimachinery/pkg/util/sets"
13+
"k8s.io/apimachinery/pkg/util/wait"
14+
"k8s.io/client-go/util/retry"
15+
"k8s.io/klog/v2"
16+
"sigs.k8s.io/controller-runtime/pkg/client"
17+
)
18+
19+
var (
20+
cmName = "test-resource-recorder"
21+
)
22+
23+
func initConfigMap(c client.Client) *v1.ConfigMap {
24+
//podName := os.Getenv("POD_NAME")
25+
cm := &v1.ConfigMap{}
26+
cm.Name = cmName
27+
cm.Namespace = podNamespace
28+
cm.Data = map[string]string{}
29+
if err := c.Create(context.TODO(), cm); err != nil {
30+
klog.Errorf("Failed to create cm %v", err)
31+
}
32+
return cm
33+
}
34+
35+
var Retry = wait.Backoff{
36+
Steps: 50,
37+
Duration: 10 * time.Millisecond,
38+
Factor: 1.0,
39+
Jitter: 0.1,
40+
}
41+
42+
func add(c client.Client, namespace, kind string) error {
43+
if namespace == "" || kind == "" {
44+
return nil
45+
}
46+
key := podName
47+
return retry.RetryOnConflict(Retry, func() error {
48+
cm := &v1.ConfigMap{}
49+
if err := c.Get(context.TODO(), types.NamespacedName{Name: cmName, Namespace: podNamespace}, cm); err != nil {
50+
klog.Errorf("Failed to get cm %v, try init", err)
51+
cm = initConfigMap(c)
52+
}
53+
if cm.Data == nil {
54+
cm.Data = map[string]string{}
55+
}
56+
val, _ := cm.Data[key]
57+
sto := &store{}
58+
if val == "" {
59+
sto.Kinds = map[string]string{}
60+
} else {
61+
json.Unmarshal([]byte(val), sto)
62+
}
63+
names, _ := sto.Kinds[kind]
64+
nameSet := list(names)
65+
if nameSet.Has(namespace) {
66+
return nil
67+
}
68+
nameSet.Insert(namespace)
69+
sto.Kinds[kind] = toString(nameSet)
70+
bt, _ := json.Marshal(sto)
71+
cm.Data[key] = string(bt)
72+
return c.Update(context.TODO(), cm)
73+
})
74+
}
75+
76+
func Checker(ctx context.Context, c client.Client) {
77+
cm := &v1.ConfigMap{}
78+
for {
79+
resources := map[string]sets.Set[string]{}
80+
<-time.After(20 * time.Second)
81+
82+
select {
83+
case <-ctx.Done():
84+
return
85+
default:
86+
}
87+
88+
if err := c.Get(context.TODO(), types.NamespacedName{Name: cmName, Namespace: podNamespace}, cm); err != nil {
89+
klog.Errorf("fail to get configMap %s, %v", cmName, err)
90+
continue
91+
}
92+
if cm.Data == nil {
93+
klog.Infof("nil configmap data")
94+
continue
95+
}
96+
for pod, val := range cm.Data {
97+
sto := &store{}
98+
if err := json.Unmarshal([]byte(val), sto); err != nil {
99+
klog.Errorf("fail to unmarshal store, %v", err)
100+
}
101+
if sto.Kinds == nil {
102+
continue
103+
}
104+
for kind, names := range sto.Kinds {
105+
set, ok := resources[kind]
106+
if !ok {
107+
set = list(names)
108+
resources[kind] = set
109+
continue
110+
}
111+
nameList := list(names).UnsortedList()
112+
for _, name := range nameList {
113+
if set.Has(name) {
114+
msg := fmt.Sprintf("conflict namespace %s in store, pod: %s", name, pod)
115+
klog.Errorf(msg)
116+
<-time.After(20 * time.Second)
117+
panic(msg)
118+
}
119+
set.Insert(name)
120+
}
121+
resources[kind] = set
122+
}
123+
}
124+
}
125+
}
126+
127+
func list(val string) sets.Set[string] {
128+
res := sets.New[string]()
129+
if val == "" {
130+
return res
131+
}
132+
133+
res.Insert(strings.Split(val, ",")...)
134+
return res
135+
}
136+
137+
func toString(names sets.Set[string]) string {
138+
return strings.Join(sets.List(names), ",")
139+
}
140+
141+
type store struct {
142+
Kinds map[string]string
143+
}

0 commit comments

Comments
 (0)