Skip to content

Commit

Permalink
feat(crd): add memcached port support (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhra303 authored Apr 3, 2024
1 parent 1227300 commit 7a563e6
Show file tree
Hide file tree
Showing 5 changed files with 432 additions and 183 deletions.
5 changes: 5 additions & 0 deletions api/v1alpha1/dragonfly_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ type DragonflySpec struct {
// +kubebuilder:validation:Optional
NodeSelector map[string]string `json:"nodeSelector,omitempty"`

// (Optional) Dragonfly memcached port
// +optional
// +kubebuilder:validation:Optional
MemcachedPort int32 `json:"memcachedPort,omitempty"`

// (Optional) Dragonfly pod tolerations
// +optional
// +kubebuilder:validation:Optional
Expand Down
197 changes: 136 additions & 61 deletions config/crd/bases/dragonflydb.io_dragonflies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,10 @@ spec:
type: string
description: (Optional) Labels to add to the Dragonfly pods.
type: object
memcachedPort:
description: (Optional) Dragonfly memcached port
format: int32
type: integer
nodeSelector:
additionalProperties:
type: string
Expand Down Expand Up @@ -1413,98 +1417,169 @@ spec:
topologySpreadConstraints:
description: (Optional) Dragonfly pod topologySpreadConstraints
items:
description: The pod this TopologySpreadConstraints is attached
description: TopologySpreadConstraint specifies how to spread matching
pods among the given topology.
properties:
maxSkew:
description: the degree to which Pods may be unevenly distributed.
You must specify this field and the number must be greater than zero.
Its semantics differ according to the value of whenUnsatisfiable
format: int32
type: integer
minDomains:
description: (Optional) indicates a minimum number of eligible domains.
This field is optional. A domain is a particular instance of a topology.
An eligible domain is a domain whose nodes match the node selector
format: int32
type: integer
topologyKey:
description: the key of node labels. Nodes that have a label with this key and
identical values are considered to be in the same topology. We call each
instance of a topology (in other words, a <key, value> pair) a domain.
The scheduler will try to put a balanced number of pods into each domain.
Also, we define an eligible domain as a domain whose nodes meet the
requirements of nodeAffinityPolicy and nodeTaintsPolicy.
type: string
whenUnsatisfiable:
description: DoNotSchedule (default) tells the scheduler not to schedule it.
ScheduleAnyway tells the scheduler to still schedule it while prioritizing
nodes that minimize the skew.
type: string
labelSelector:
description: A label query over a set of resources,
in this case pods.
description: LabelSelector is used to find matching pods. Pods
that match this label selector are counted to determine the
number of pods in their corresponding topology domain.
properties:
matchExpressions:
description: matchExpressions is a list of label
selector requirements. The requirements are
ANDed.
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: A label selector requirement
is a selector that contains values, a key,
and an operator that relates the key and
values.
description: A label selector requirement is a selector
that contains values, a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key that
the selector applies to.
description: key is the label key that the selector
applies to.
type: string
operator:
description: operator represents a key's
relationship to a set of values. Valid
operators are In, NotIn, Exists and
DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn,
Exists and DoesNotExist.
type: string
values:
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty.
If the operator is Exists or DoesNotExist,
the values array must be empty. This
array is replaced during a strategic
merge patch.
description: values is an array of string values.
If the operator is In or NotIn, the values array
must be non-empty. If the operator is Exists or
DoesNotExist, the values array must be empty. This
array is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is
"In", and the values array contains only "value".
The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs.
A single {key,value} in the matchLabels map is equivalent
to an element of matchExpressions, whose key field is
"key", the operator is "In", and the values array contains
only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
description: field is a beta-level field and enabled by default in 1.27.
You can disable it by disabling the MatchLabelKeysInPodTopologySpread
description: MatchLabelKeys is a set of pod label keys to select
the pods over which spreading will be calculated. The keys
are used to lookup values from the incoming pod labels, those
key-value labels are ANDed with labelSelector to select the
group of existing pods over which spreading will be calculated
for the incoming pod. Keys that don't exist in the incoming
pod labels will be ignored. A null or empty list means only
match against labelSelector.
items:
type: string
type: array
x-kubernetes-list-type: atomic
maxSkew:
description: 'MaxSkew describes the degree to which pods may
be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`,
it is the maximum permitted difference between the number
of matching pods in the target topology and the global minimum.
The global minimum is the minimum number of matching pods
in an eligible domain or zero if the number of eligible domains
is less than MinDomains. For example, in a 3-zone cluster,
MaxSkew is set to 1, and pods with the same labelSelector
spread as 2/2/1: In this case, the global minimum is 1. |
zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew
is 1, incoming pod can only be scheduled to zone3 to become
2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1)
on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming
pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`,
it is used to give higher precedence to topologies that satisfy
it. It''s a required field. Default value is 1 and 0 is not
allowed.'
format: int32
type: integer
minDomains:
description: "MinDomains indicates a minimum number of eligible
domains. When the number of eligible domains with matching
topology keys is less than minDomains, Pod Topology Spread
treats \"global minimum\" as 0, and then the calculation of
Skew is performed. And when the number of eligible domains
with matching topology keys equals or greater than minDomains,
this value has no effect on scheduling. As a result, when
the number of eligible domains is less than minDomains, scheduler
won't schedule more than maxSkew Pods to those domains. If
value is nil, the constraint behaves as if MinDomains is equal
to 1. Valid values are integers greater than 0. When value
is not nil, WhenUnsatisfiable must be DoNotSchedule. \n For
example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains
is set to 5 and pods with the same labelSelector spread as
2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P |
The number of domains is less than 5(MinDomains), so \"global
minimum\" is treated as 0. In this situation, new pod with
the same labelSelector cannot be scheduled, because computed
skew will be 3(3 - 0) if new Pod is scheduled to any of the
three zones, it will violate MaxSkew. \n This is a beta field
and requires the MinDomainsInPodTopologySpread feature gate
to be enabled (enabled by default)."
format: int32
type: integer
nodeAffinityPolicy:
description: indicates how we will treat Pod's nodeAffinity/nodeSelector
when calculating pod topology spread skew. Options are Honor or Ignore
description: "NodeAffinityPolicy indicates how we will treat
Pod's nodeAffinity/nodeSelector when calculating pod topology
spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector
are included in the calculations. - Ignore: nodeAffinity/nodeSelector
are ignored. All nodes are included in the calculations. \n
If this value is nil, the behavior is equivalent to the Honor
policy. This is a beta-level feature default enabled by the
NodeInclusionPolicyInPodTopologySpread feature flag."
type: string
nodeTaintsPolicy:
description: indicates how we will treat node taints when calculating pod topology spread skew. Honor or Ignore
description: "NodeTaintsPolicy indicates how we will treat node
taints when calculating pod topology spread skew. Options
are: - Honor: nodes without taints, along with tainted nodes
for which the incoming pod has a toleration, are included.
- Ignore: node taints are ignored. All nodes are included.
\n If this value is nil, the behavior is equivalent to the
Ignore policy. This is a beta-level feature default enabled
by the NodeInclusionPolicyInPodTopologySpread feature flag."
type: string
topologyKey:
description: TopologyKey is the key of node labels. Nodes that
have a label with this key and identical values are considered
to be in the same topology. We consider each <key, value>
as a "bucket", and try to put balanced number of pods into
each bucket. We define a domain as a particular instance of
a topology. Also, we define an eligible domain as a domain
whose nodes meet the requirements of nodeAffinityPolicy and
nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname",
each Node is a domain of that topology. And, if TopologyKey
is "topology.kubernetes.io/zone", each zone is a domain of
that topology. It's a required field.
type: string
whenUnsatisfiable:
description: 'WhenUnsatisfiable indicates how to deal with a
pod if it doesn''t satisfy the spread constraint. - DoNotSchedule
(default) tells the scheduler not to schedule it. - ScheduleAnyway
tells the scheduler to schedule the pod in any location, but
giving higher precedence to topologies that would help reduce
the skew. A constraint is considered "Unsatisfiable" for an
incoming pod if and only if every possible node assignment
for that pod would violate "MaxSkew" on some topology. For
example, in a 3-zone cluster, MaxSkew is set to 1, and pods
with the same labelSelector spread as 3/1/1: | zone1 | zone2
| zone3 | | P P P | P | P | If WhenUnsatisfiable is
set to DoNotSchedule, incoming pod can only be scheduled to
zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on
zone2(zone3) satisfies MaxSkew(1). In other words, the cluster
can still be imbalanced, but scheduler won''t make it *more*
imbalanced. It''s a required field.'
type: string
required:
- maxSkew
- topologyKey
- whenUnsatisfiable
type: object
type: array
type: object
Expand Down
9 changes: 9 additions & 0 deletions internal/resources/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ func GetDragonflyResources(ctx context.Context, df *resourcesv1.Dragonfly) ([]cl
if df.Spec.Args != nil {
statefulset.Spec.Template.Spec.Containers[0].Args = append(statefulset.Spec.Template.Spec.Containers[0].Args, df.Spec.Args...)
}
if df.Spec.MemcachedPort != 0 {
statefulset.Spec.Template.Spec.Containers[0].Args = append(statefulset.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--memcached_port=%d", df.Spec.MemcachedPort))
}

if df.Spec.AclFromSecret != nil {
statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, corev1.Volume{
Expand Down Expand Up @@ -374,6 +377,12 @@ func GetDragonflyResources(ctx context.Context, df *resourcesv1.Dragonfly) ([]cl
service.Spec.Type = df.Spec.ServiceSpec.Type
service.Annotations = df.Spec.ServiceSpec.Annotations
}
if df.Spec.MemcachedPort != 0 {
service.Spec.Ports = append(service.Spec.Ports, corev1.ServicePort{
Name: "memcached",
Port: df.Spec.MemcachedPort,
})
}

resources = append(resources, &service)

Expand Down
Loading

0 comments on commit 7a563e6

Please sign in to comment.