forked from kosmos-io/kosmos
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a webhook to prevent eviction of pods on kosmos NotReady nodes
Signed-off-by: wangyizhi1 <[email protected]>
- Loading branch information
1 parent
76c7ecb
commit edb2381
Showing
14 changed files
with
436 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package options | ||
|
||
import ( | ||
"github.com/spf13/pflag" | ||
"k8s.io/client-go/tools/leaderelection/resourcelock" | ||
componentbaseconfig "k8s.io/component-base/config" | ||
|
||
"github.com/kosmos.io/kosmos/pkg/utils" | ||
"github.com/kosmos.io/kosmos/pkg/webhook" | ||
) | ||
|
||
type Options struct { | ||
LeaderElection componentbaseconfig.LeaderElectionConfiguration | ||
KubernetesOptions KubernetesOptions | ||
WebhookServerOptions WebhookServerOptions | ||
PodValidatorOptions webhook.PodValidatorOptions | ||
} | ||
|
||
type KubernetesOptions struct { | ||
KubeConfig string `json:"kubeconfig" yaml:"kubeconfig"` | ||
Master string `json:"master,omitempty" yaml:"master,omitempty"` | ||
QPS float32 `json:"qps,omitempty" yaml:"qps,omitempty"` | ||
Burst int `json:"burst,omitempty" yaml:"burst,omitempty"` | ||
} | ||
|
||
type WebhookServerOptions struct { | ||
Host string | ||
Port int | ||
CertDir string | ||
CertName string | ||
KeyName string | ||
} | ||
|
||
func NewOptions() *Options { | ||
return &Options{ | ||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{ | ||
LeaderElect: true, | ||
ResourceLock: resourcelock.LeasesResourceLock, | ||
ResourceNamespace: utils.DefaultNamespace, | ||
ResourceName: "network-manager", | ||
}, | ||
} | ||
} | ||
|
||
func (o *Options) AddFlags(flags *pflag.FlagSet) { | ||
if o == nil { | ||
return | ||
} | ||
|
||
flags.BoolVar(&o.LeaderElection.LeaderElect, "leader-elect", true, "Start a leader election client and gain leadership before executing the main loop. Enable this when running replicated components for high availability.") | ||
flags.StringVar(&o.LeaderElection.ResourceName, "leader-elect-resource-name", "kosmos-webhook", "The name of resource object that is used for locking during leader election.") | ||
flags.StringVar(&o.LeaderElection.ResourceNamespace, "leader-elect-resource-namespace", utils.DefaultNamespace, "The namespace of resource object that is used for locking during leader election.") | ||
flags.Float32Var(&o.KubernetesOptions.QPS, "kube-qps", 40.0, "QPS to use while talking with kube-apiserver.") | ||
flags.IntVar(&o.KubernetesOptions.Burst, "kube-burst", 60, "Burst to use while talking with kube-apiserver.") | ||
flags.StringVar(&o.KubernetesOptions.KubeConfig, "kubeconfig", "", "Path for kubernetes kubeconfig file, if left blank, will use in cluster way.") | ||
flags.StringVar(&o.KubernetesOptions.Master, "master", "", "Used to generate kubeconfig for downloading, if not specified, will use host in kubeconfig.") | ||
flags.StringVar(&o.WebhookServerOptions.Host, "bind-address", "0.0.0.0", "The IP address on which to listen for the --secure-port port.") | ||
flags.IntVar(&o.WebhookServerOptions.Port, "secure-port", 9443, "The secure port on which to serve HTTPS.") | ||
flags.StringVar(&o.WebhookServerOptions.CertDir, "cert-dir", "/etc/certs", "The directory that contains the server key and certificate.") | ||
flags.StringVar(&o.WebhookServerOptions.CertName, "tls-cert-file-name", "tls.crt", "The name of server certificate.") | ||
flags.StringVar(&o.WebhookServerOptions.KeyName, "tls-private-key-file-name", "tls.key", "The name of server key.") | ||
flags.StringArrayVar(&o.PodValidatorOptions.UsernamesNeedToPrevent, "usernames-need-to-prevent", []string{"system:serviceaccount:kube-system:node-controller"}, "Usernames that need to prevent deleting pods on NotReady kosmos nodes.") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package options | ||
|
||
import "k8s.io/apimachinery/pkg/util/validation/field" | ||
|
||
// Validate checks Options and return a slice of found errs. | ||
func (o *Options) Validate() field.ErrorList { | ||
errs := field.ErrorList{} | ||
|
||
return errs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package app | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/spf13/cobra" | ||
"k8s.io/client-go/tools/clientcmd" | ||
cliflag "k8s.io/component-base/cli/flag" | ||
"k8s.io/klog/v2" | ||
controllerruntime "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/healthz" | ||
"sigs.k8s.io/controller-runtime/pkg/webhook" | ||
|
||
"github.com/kosmos.io/kosmos/cmd/webhook/app/options" | ||
"github.com/kosmos.io/kosmos/pkg/scheme" | ||
"github.com/kosmos.io/kosmos/pkg/sharedcli/klogflag" | ||
kosmoswebhook "github.com/kosmos.io/kosmos/pkg/webhook" | ||
) | ||
|
||
func NewWebhookCommand(ctx context.Context) *cobra.Command { | ||
opts := options.NewOptions() | ||
|
||
cmd := &cobra.Command{ | ||
Use: "kosmos-webhook", | ||
Long: `TODO`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if errs := opts.Validate(); len(errs) != 0 { | ||
return errs.ToAggregate() | ||
} | ||
if err := Run(ctx, opts); err != nil { | ||
return err | ||
} | ||
return nil | ||
}, | ||
Args: func(cmd *cobra.Command, args []string) error { | ||
for _, arg := range args { | ||
if len(arg) > 0 { | ||
return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args) | ||
} | ||
} | ||
return nil | ||
}, | ||
} | ||
|
||
fss := cliflag.NamedFlagSets{} | ||
|
||
genericFlagSet := fss.FlagSet("generic") | ||
opts.AddFlags(genericFlagSet) | ||
|
||
logsFlagSet := fss.FlagSet("logs") | ||
klogflag.Add(logsFlagSet) | ||
|
||
cmd.Flags().AddFlagSet(genericFlagSet) | ||
cmd.Flags().AddFlagSet(logsFlagSet) | ||
|
||
return cmd | ||
} | ||
|
||
func Run(ctx context.Context, opts *options.Options) error { | ||
config, err := clientcmd.BuildConfigFromFlags(opts.KubernetesOptions.Master, opts.KubernetesOptions.KubeConfig) | ||
if err != nil { | ||
panic(err) | ||
} | ||
config.QPS, config.Burst = opts.KubernetesOptions.QPS, opts.KubernetesOptions.Burst | ||
|
||
mgr, err := controllerruntime.NewManager(config, controllerruntime.Options{ | ||
Logger: klog.Background(), | ||
Scheme: scheme.NewSchema(), | ||
WebhookServer: &webhook.Server{ | ||
Host: opts.WebhookServerOptions.Host, | ||
Port: opts.WebhookServerOptions.Port, | ||
CertDir: opts.WebhookServerOptions.CertDir, | ||
CertName: opts.WebhookServerOptions.CertName, | ||
KeyName: opts.WebhookServerOptions.KeyName, | ||
}, | ||
MetricsBindAddress: "0", | ||
HealthProbeBindAddress: "0", | ||
LeaderElection: opts.LeaderElection.LeaderElect, | ||
LeaderElectionID: opts.LeaderElection.ResourceName, | ||
LeaderElectionNamespace: opts.LeaderElection.ResourceNamespace, | ||
}) | ||
if err != nil { | ||
klog.Errorf("failed to build webhook server: %v", err) | ||
return err | ||
} | ||
|
||
hookServer := mgr.GetWebhookServer() | ||
hookServer.Register("/validate-delete-pod", &webhook.Admission{Handler: &kosmoswebhook.PodValidator{ | ||
Client: mgr.GetClient(), | ||
Options: opts.PodValidatorOptions, | ||
}}) | ||
hookServer.WebhookMux.Handle("/health", http.StripPrefix("/health", &healthz.Handler{})) | ||
|
||
if err := mgr.Start(ctx); err != nil { | ||
klog.Errorf("failed to start webhook manager: %v", err) | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
apiserver "k8s.io/apiserver/pkg/server" | ||
"k8s.io/component-base/cli" | ||
|
||
"github.com/kosmos.io/kosmos/cmd/webhook/app" | ||
) | ||
|
||
func main() { | ||
ctx := apiserver.SetupSignalContext() | ||
cmd := app.NewWebhookCommand(ctx) | ||
code := cli.Run(cmd) | ||
os.Exit(code) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: kosmos-webhook | ||
namespace: kosmos-system | ||
spec: | ||
selector: | ||
matchLabels: | ||
app: kosmos-webhook | ||
template: | ||
metadata: | ||
labels: | ||
app: kosmos-webhook | ||
spec: | ||
serviceAccountName: kosmos-webhook | ||
affinity: | ||
nodeAffinity: | ||
requiredDuringSchedulingIgnoredDuringExecution: | ||
nodeSelectorTerms: | ||
- matchExpressions: | ||
- key: kosmos.io/node | ||
operator: DoesNotExist | ||
podAntiAffinity: | ||
requiredDuringSchedulingIgnoredDuringExecution: | ||
- labelSelector: | ||
matchExpressions: | ||
- key: app | ||
operator: In | ||
values: | ||
- kosmos-webhook | ||
namespaces: | ||
- kosmos-system | ||
topologyKey: kubernetes.io/hostname | ||
containers: | ||
- image: ghcr.io/kosmos-io/webhook:__VERSION__ | ||
name: kosmos-webhook | ||
volumeMounts: | ||
- name: tls | ||
mountPath: "/etc/certs" | ||
command: | ||
- webhook | ||
- --v=4 | ||
resources: | ||
limits: | ||
memory: 500Mi | ||
cpu: 500m | ||
requests: | ||
cpu: 500m | ||
memory: 500Mi | ||
volumes: | ||
- name: tls | ||
secret: | ||
secretName: kosmos-webhook-tls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
apiVersion: v1 | ||
kind: ServiceAccount | ||
metadata: | ||
name: kosmos-webhook | ||
namespace: kosmos-system | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: ClusterRole | ||
metadata: | ||
name: kosmos-webhook | ||
rules: | ||
- apiGroups: ['*'] | ||
resources: ["nodes", "pods"] | ||
verbs: ["*"] | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: ClusterRoleBinding | ||
metadata: | ||
name: kosmos-webhook | ||
roleRef: | ||
apiGroup: rbac.authorization.k8s.io | ||
kind: ClusterRole | ||
name: kosmos-webhook | ||
subjects: | ||
- kind: ServiceAccount | ||
name: kosmos-webhook | ||
namespace: kosmos-system |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: kosmos-webhook | ||
namespace: kosmos-system | ||
spec: | ||
ports: | ||
- port: 9443 | ||
protocol: TCP | ||
targetPort: 9443 | ||
selector: | ||
app: kosmos-webhook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
apiVersion: v1 | ||
data: | ||
tls.crt: __BASE64_SERVER_CRT__ | ||
tls.key: __BASE64_SERVER_KEY__ | ||
kind: Secret | ||
metadata: | ||
name: kosmos-webhook-tls | ||
namespace: kosmos-system | ||
type: kubernetes.io/tls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
apiVersion: admissionregistration.k8s.io/v1 | ||
kind: ValidatingWebhookConfiguration | ||
metadata: | ||
name: "validate-delete-pod.kosmos.io" | ||
webhooks: | ||
- name: "validate-delete-pod.kosmos.io" | ||
rules: | ||
- apiGroups: [""] | ||
apiVersions: ["v1"] | ||
operations: ["DELETE"] | ||
resources: ["pods"] | ||
scope: "*" | ||
admissionReviewVersions: ["v1"] | ||
# FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are | ||
# Ignore or Fail. Defaults to Fail. | ||
failurePolicy: Ignore | ||
sideEffects: None | ||
timeoutSeconds: 3 | ||
clientConfig: | ||
service: | ||
namespace: kosmos-system | ||
name: kosmos-webhook | ||
path: /validate-delete-pod | ||
port: 9443 | ||
caBundle: | | ||
__BASE64_CA_CRT__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/bin/bash | ||
|
||
WEBHOOK_NAME="kosmos-webhook" | ||
NAMESPACE="kosmos-system" | ||
DAYS="36500" | ||
|
||
openssl genrsa -out ca.key 2048 | ||
|
||
openssl req -new -x509 -days ${DAYS} -key ca.key \ | ||
-subj "/C=CN/CN=${WEBHOOK_NAME}"\ | ||
-out ca.crt | ||
|
||
openssl req -newkey rsa:2048 -nodes -keyout server.key \ | ||
-subj "/C=CN/CN=${WEBHOOK_NAME}" \ | ||
-out server.csr | ||
|
||
openssl x509 -req \ | ||
-extfile <(printf "subjectAltName=DNS:${WEBHOOK_NAME}.${NAMESPACE}.svc") \ | ||
-days ${DAYS} \ | ||
-in server.csr \ | ||
-CA ca.crt -CAkey ca.key -CAcreateserial \ | ||
-out server.crt | ||
|
||
echo | ||
echo ">> Generating kube secrets..." | ||
kubectl create secret tls ${WEBHOOK_NAME}-tls \ | ||
--cert=server.crt \ | ||
--key=server.key \ | ||
--dry-run=client -o yaml \ | ||
> tls-secret.yaml | ||
|
||
echo | ||
echo ">> MutatingWebhookConfiguration caBundle:" | ||
cat ca.crt | base64 | fold | ||
|
||
rm ca.crt ca.key ca.srl server.crt server.csr server.key |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.