Skip to content

Commit

Permalink
Support manage single node
Browse files Browse the repository at this point in the history
  • Loading branch information
wzshiming committed Aug 15, 2023
1 parent 8ab0b37 commit ae2bedb
Show file tree
Hide file tree
Showing 15 changed files with 407 additions and 54 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ jobs:
case:
- kwok
- kwok-with-cni
- kwok-single-node
continue-on-error: false
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions kustomize/kwok/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ spec:
- --manage-all-nodes=false
- --manage-nodes-with-annotation-selector=kwok.x-k8s.io/node=fake
- --manage-nodes-with-label-selector=
- --manage-single-node=
- --disregard-status-with-annotation-selector=kwok.x-k8s.io/status=custom
- --disregard-status-with-label-selector=
- --node-ip=$(POD_IP)
Expand Down
18 changes: 16 additions & 2 deletions pkg/apis/config/v1alpha1/kwok_configuration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,33 @@ type KwokConfigurationOptions struct {
// is the default value for flag --tls-private-key-file
TLSPrivateKeyFile string `json:"tlsPrivateKeyFile,omitempty"`

// ManageSingleNode is the option to manage a single node name.
// is the default value for flag --manage-single-node
// Note: when `manage-all-nodes` is specified as true or
// `manage-nodes-with-label-selector` or `manage-nodes-with-annotation-selector` is specified,
// this is a no-op.
ManageSingleNode string `json:"manageSingleNode,omitempty"`

// Default option to manage (i.e., maintain heartbeat/liveness of) all Nodes or not.
// is the default value for flag --manage-all-nodes
// Note: when `manage-single-node` is specified as true or
// `manage-nodes-with-label-selector` or `manage-nodes-with-annotation-selector` is specified,
// this is a no-op.
// +default=false
ManageAllNodes *bool `json:"manageAllNodes,omitempty"`

// Default annotations specified on Nodes to demand manage.
// Note: when `all-node-manage` is specified as true, this is a no-op.
// is the default value for flag --manage-nodes-with-annotation-selector
// Note: when `all-node-manage` is specified as true or
// `manage-single-node` is specified,
// this is a no-op.
ManageNodesWithAnnotationSelector string `json:"manageNodesWithAnnotationSelector,omitempty"`

// Default labels specified on Nodes to demand manage.
// Note: when `all-node-manage` is specified as true, this is a no-op.
// is the default value for flag --manage-nodes-with-label-selector
// Note: when `all-node-manage` is specified as true or
// `manage-single-node` is specified,
// this is a no-op.
ManageNodesWithLabelSelector string `json:"manageNodesWithLabelSelector,omitempty"`

// If a Node/Pod is on a managed Node and has this annotation status will not be modified
Expand Down
7 changes: 5 additions & 2 deletions pkg/apis/internalversion/kwok_configuration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ type KwokConfigurationOptions struct {
// TLSPrivateKeyFile is the ile containing x509 private key
TLSPrivateKeyFile string

// ManageSingleNode is the option to manage a single node name
ManageSingleNode string

// Default option to manage (i.e., maintain heartbeat/liveness of) all Nodes or not.
ManageAllNodes bool

Expand All @@ -74,11 +77,11 @@ type KwokConfigurationOptions struct {
// Experimental support for getting pod ip from CNI, for CNI-related components, Only works with Linux.
EnableCNI bool

// enableDebuggingHandlers enables server endpoints for log collection
// EnableDebuggingHandlers enables server endpoints for log collection
// and local running of containers and commands
EnableDebuggingHandlers bool

// enableContentionProfiling enables lock contention profiling, if enableDebuggingHandlers is true.
// EnableContentionProfiling enables lock contention profiling, if enableDebuggingHandlers is true.
EnableContentionProfiling bool

// EnableProfiling enables /debug/pprof handler.
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/internalversion/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 10 additions & 21 deletions pkg/kwok/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ func NewCommand(ctx context.Context) *cobra.Command {
cmd.Flags().IntVar(&flags.Options.NodePort, "node-port", flags.Options.NodePort, "Port of the node")
cmd.Flags().StringVar(&flags.Options.TLSCertFile, "tls-cert-file", flags.Options.TLSCertFile, "File containing the default x509 Certificate for HTTPS")
cmd.Flags().StringVar(&flags.Options.TLSPrivateKeyFile, "tls-private-key-file", flags.Options.TLSPrivateKeyFile, "File containing the default x509 private key matching --tls-cert-file")
cmd.Flags().BoolVar(&flags.Options.ManageAllNodes, "manage-all-nodes", flags.Options.ManageAllNodes, "All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector and manage-nodes-with-label-selector.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithAnnotationSelector, "manage-nodes-with-annotation-selector", flags.Options.ManageNodesWithAnnotationSelector, "Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithLabelSelector, "manage-nodes-with-label-selector", flags.Options.ManageNodesWithLabelSelector, "Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes.")
cmd.Flags().StringVar(&flags.Options.ManageSingleNode, "manage-single-node", flags.Options.ManageSingleNode, "Node that matches the name will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-all-nodes.")
cmd.Flags().BoolVar(&flags.Options.ManageAllNodes, "manage-all-nodes", flags.Options.ManageAllNodes, "All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-single-node.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithAnnotationSelector, "manage-nodes-with-annotation-selector", flags.Options.ManageNodesWithAnnotationSelector, "Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithLabelSelector, "manage-nodes-with-label-selector", flags.Options.ManageNodesWithLabelSelector, "Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.")
cmd.Flags().StringVar(&flags.Options.DisregardStatusWithAnnotationSelector, "disregard-status-with-annotation-selector", flags.Options.DisregardStatusWithAnnotationSelector, "All node/pod status excluding the ones that match the annotation selector will be watched and managed.")
cmd.Flags().StringVar(&flags.Options.DisregardStatusWithLabelSelector, "disregard-status-with-label-selector", flags.Options.DisregardStatusWithLabelSelector, "All node/pod status excluding the ones that match the label selector will be watched and managed.")
cmd.Flags().StringVar(&flags.Kubeconfig, "kubeconfig", flags.Kubeconfig, "Path to the kubeconfig file to use")
Expand Down Expand Up @@ -229,24 +230,6 @@ func runE(ctx context.Context, flags *flagpole) error {
return err
}

if flags.Options.ManageAllNodes {
if flags.Options.ManageNodesWithAnnotationSelector != "" || flags.Options.ManageNodesWithLabelSelector != "" {
logger.Error("manage-all-nodes is conflicted with manage-nodes-with-annotation-selector and manage-nodes-with-label-selector.", nil)
os.Exit(1)
}
logger.Info("Watch all nodes")
} else if flags.Options.ManageNodesWithAnnotationSelector != "" || flags.Options.ManageNodesWithLabelSelector != "" {
logger.Info("Watch nodes",
"annotation", flags.Options.ManageNodesWithAnnotationSelector,
"label", flags.Options.ManageNodesWithLabelSelector,
)
}

err = waitForReady(ctx, typedClient)
if err != nil {
return err
}

id, err := controllers.Identity()
if err != nil {
return err
Expand All @@ -261,6 +244,7 @@ func runE(ctx context.Context, flags *flagpole) error {
EnableCNI: flags.Options.EnableCNI,
EnableMetrics: enableMetrics,
EnablePodCache: enableMetrics,
ManageSingleNode: flags.Options.ManageSingleNode,
ManageAllNodes: flags.Options.ManageAllNodes,
ManageNodesWithAnnotationSelector: flags.Options.ManageNodesWithAnnotationSelector,
ManageNodesWithLabelSelector: flags.Options.ManageNodesWithLabelSelector,
Expand All @@ -282,6 +266,11 @@ func runE(ctx context.Context, flags *flagpole) error {
return err
}

err = waitForReady(ctx, typedClient)
if err != nil {
return err
}

serverAddress := flags.Options.ServerAddress
if serverAddress == "" && flags.Options.NodePort != 0 {
serverAddress = "0.0.0.0:" + format.String(flags.Options.NodePort)
Expand Down
62 changes: 50 additions & 12 deletions pkg/kwok/controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type Config struct {
EnableCNI bool
TypedClient kubernetes.Interface
TypedKwokClient versioned.Interface
ManageSingleNode string
ManageAllNodes bool
ManageNodesWithAnnotationSelector string
ManageNodesWithLabelSelector string
Expand All @@ -132,16 +133,31 @@ type Config struct {
EnablePodCache bool
}

// NewController creates a new fake kubelet controller
func NewController(conf Config) (*Controller, error) {
func (c Config) validate() error {
switch {
case conf.ManageAllNodes:
conf.ManageNodesWithAnnotationSelector = ""
conf.ManageNodesWithLabelSelector = ""
case conf.ManageNodesWithAnnotationSelector != "":
case conf.ManageNodesWithLabelSelector != "":
case c.ManageSingleNode != "":
if c.ManageAllNodes {
return fmt.Errorf("manage-single-node is conflicted with manage-all-nodes")
}
if c.ManageNodesWithAnnotationSelector != "" || c.ManageNodesWithLabelSelector != "" {
return fmt.Errorf("manage-single-node is conflicted with manage-nodes-with-annotation-selector or manage-nodes-with-label-selector")
}
case c.ManageAllNodes:
if c.ManageNodesWithAnnotationSelector != "" || c.ManageNodesWithLabelSelector != "" {
return fmt.Errorf("manage-all-nodes is conflicted with manage-nodes-with-annotation-selector or manage-nodes-with-label-selector")
}
case c.ManageNodesWithAnnotationSelector != "" || c.ManageNodesWithLabelSelector != "":
default:
return nil, fmt.Errorf("no nodes are managed")
return fmt.Errorf("no nodes are managed")
}
return nil
}

// NewController creates a new fake kubelet controller
func NewController(conf Config) (*Controller, error) {
err := conf.validate()
if err != nil {
return nil, err
}

n := &Controller{
Expand Down Expand Up @@ -170,14 +186,34 @@ func (c *Controller) Start(ctx context.Context) error {
onLeaseNodeManageFunc func(nodeName string)
onNodeManagedFunc func(nodeName string)
readOnlyFunc func(nodeName string) bool

manageNodesWithLabelSelector string
manageNodesWithAnnotationSelector string
manageNodesWithFieldSelector string
manageNodeLeasesWithFieldSelector string
managePodsWithFieldSelector string
)

switch {
case conf.ManageSingleNode != "":
managePodsWithFieldSelector = fields.OneTermEqualSelector("spec.nodeName", conf.ManageSingleNode).String()
manageNodesWithFieldSelector = fields.OneTermEqualSelector("metadata.name", conf.ManageSingleNode).String()
manageNodeLeasesWithFieldSelector = fields.OneTermEqualSelector("metadata.name", conf.ManageSingleNode).String()
case conf.ManageAllNodes:
managePodsWithFieldSelector = fields.OneTermNotEqualSelector("spec.nodeName", "").String()
case conf.ManageNodesWithLabelSelector != "" || conf.ManageNodesWithAnnotationSelector != "":
manageNodesWithLabelSelector = conf.ManageNodesWithLabelSelector
manageNodesWithAnnotationSelector = conf.ManageNodesWithAnnotationSelector
managePodsWithFieldSelector = fields.OneTermNotEqualSelector("spec.nodeName", "").String()
}

nodeChan := make(chan informer.Event[*corev1.Node], 1)
nodesCli := conf.TypedClient.CoreV1().Nodes()
nodesInformer := informer.NewInformer[*corev1.Node, *corev1.NodeList](nodesCli)
nodesCache, err := nodesInformer.WatchWithCache(ctx, informer.Option{
LabelSelector: conf.ManageNodesWithLabelSelector,
AnnotationSelector: conf.ManageNodesWithAnnotationSelector,
LabelSelector: manageNodesWithLabelSelector,
AnnotationSelector: manageNodesWithAnnotationSelector,
FieldSelector: manageNodesWithFieldSelector,
}, nodeChan)
if err != nil {
return fmt.Errorf("failed to watch nodes: %w", err)
Expand All @@ -188,7 +224,7 @@ func (c *Controller) Start(ctx context.Context) error {
podsInformer := informer.NewInformer[*corev1.Pod, *corev1.PodList](podsCli)

podWatchOption := informer.Option{
FieldSelector: fields.OneTermNotEqualSelector("spec.nodeName", "").String(),
FieldSelector: managePodsWithFieldSelector,
}

var podsCache informer.Getter[*corev1.Pod]
Expand All @@ -205,7 +241,9 @@ func (c *Controller) Start(ctx context.Context) error {
nodeLeasesChan = make(chan informer.Event[*coordinationv1.Lease], 1)
nodeLeasesCli := conf.TypedClient.CoordinationV1().Leases(corev1.NamespaceNodeLease)
nodeLeasesInformer := informer.NewInformer[*coordinationv1.Lease, *coordinationv1.LeaseList](nodeLeasesCli)
err = nodeLeasesInformer.Watch(ctx, informer.Option{}, nodeLeasesChan)
err = nodeLeasesInformer.Watch(ctx, informer.Option{
FieldSelector: manageNodeLeasesWithFieldSelector,
}, nodeLeasesChan)
if err != nil {
return fmt.Errorf("failed to watch nodes: %w", err)
}
Expand Down
32 changes: 27 additions & 5 deletions site/content/en/docs/generated/apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -1860,14 +1860,32 @@ is the default value for flag &ndash;tls-private-key-file</p>
</tr>
<tr>
<td>
<code>manageSingleNode</code>
<em>
string
</em>
</td>
<td>
<p>ManageSingleNode is the option to manage a single node name.
is the default value for flag &ndash;manage-single-node
Note: when <code>manage-all-nodes</code> is specified as true or
<code>manage-nodes-with-label-selector</code> or <code>manage-nodes-with-annotation-selector</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
<td>
<code>manageAllNodes</code>
<em>
bool
</em>
</td>
<td>
<p>Default option to manage (i.e., maintain heartbeat/liveness of) all Nodes or not.
is the default value for flag &ndash;manage-all-nodes</p>
is the default value for flag &ndash;manage-all-nodes
Note: when <code>manage-single-node</code> is specified as true or
<code>manage-nodes-with-label-selector</code> or <code>manage-nodes-with-annotation-selector</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
Expand All @@ -1879,8 +1897,10 @@ string
</td>
<td>
<p>Default annotations specified on Nodes to demand manage.
Note: when <code>all-node-manage</code> is specified as true, this is a no-op.
is the default value for flag &ndash;manage-nodes-with-annotation-selector</p>
is the default value for flag &ndash;manage-nodes-with-annotation-selector
Note: when <code>all-node-manage</code> is specified as true or
<code>manage-single-node</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
Expand All @@ -1892,8 +1912,10 @@ string
</td>
<td>
<p>Default labels specified on Nodes to demand manage.
Note: when <code>all-node-manage</code> is specified as true, this is a no-op.
is the default value for flag &ndash;manage-nodes-with-label-selector</p>
is the default value for flag &ndash;manage-nodes-with-label-selector
Note: when <code>all-node-manage</code> is specified as true or
<code>manage-single-node</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
Expand Down
7 changes: 4 additions & 3 deletions site/content/en/docs/generated/kwok.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ kwok [flags]
--experimental-enable-cni Experimental support for getting pod ip from CNI, for CNI-related components, Only works with Linux
-h, --help help for kwok
--kubeconfig string Path to the kubeconfig file to use (default "~/.kube/config")
--manage-all-nodes All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector and manage-nodes-with-label-selector.
--manage-nodes-with-annotation-selector string Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes.
--manage-nodes-with-label-selector string Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes.
--manage-all-nodes All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-single-node.
--manage-nodes-with-annotation-selector string Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.
--manage-nodes-with-label-selector string Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.
--manage-single-node string Node that matches the name will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-all-nodes.
--master string The address of the Kubernetes API server (overrides any value in kubeconfig).
--node-ip string IP of the node
--node-lease-duration-seconds uint Duration of node lease seconds
Expand Down
32 changes: 32 additions & 0 deletions test/kwok-single-node/fake-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: fake-pod
namespace: default
spec:
replicas: 5
selector:
matchLabels:
app: fake-pod
template:
metadata:
labels:
app: fake-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- kwok-controller
tolerations:
- key: "kwok-controller/provider"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: fake-container
image: fake
nodeName: fake-node
21 changes: 21 additions & 0 deletions test/kwok-single-node/fake-node.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: v1
kind: Node
metadata:
annotations:
kwok.x-k8s.io/node: fake
node.alpha.kubernetes.io/ttl: "0"
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
kubernetes.io/arch: amd64
kubernetes.io/hostname: fake-node
kubernetes.io/os: linux
kubernetes.io/role: agent
node-role.kubernetes.io/agent: ""
type: kwok-controller
name: fake-node
spec:
taints:
- effect: NoSchedule
key: kwok-controller/provider
value: fake
Loading

0 comments on commit ae2bedb

Please sign in to comment.