This is an automated email from the ASF dual-hosted git repository.
sunnianjun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/shardingsphere-on-cloud.git
The following commit(s) were added to refs/heads/main by this push:
new fdb8283 feta(operator,hpa): add support for Custom Metric for HPA.
(#112)
fdb8283 is described below
commit fdb8283a7a1df37600724f39f03faeadd414b604
Author: pierce <[email protected]>
AuthorDate: Thu Nov 24 17:54:00 2022 +0800
feta(operator,hpa): add support for Custom Metric for HPA. (#112)
* feta(operator,hpa): add support for Custom Metric for HPA.
Signed-off-by: xuanyuan300 <[email protected]>
* chore(license): add license to crd yaml
Signed-off-by: xuanyuan300 <[email protected]>
Signed-off-by: xuanyuan300 <[email protected]>
---
...ingsphere.apache.org_shardingsphereproxies.yaml | 490 ++++++++++++++++++++-
...pache.org_shardingsphereproxyserverconfigs.yaml | 8 +-
.../api/v1alpha1/proxy_types.go | 7 +-
.../api/v1alpha1/zz_generated.deepcopy.go | 10 +-
.../pkg/reconcile/reconcile_test.go | 148 +++++++
shardingsphere-operator/pkg/reconcile/resource.go | 41 +-
6 files changed, 674 insertions(+), 30 deletions(-)
diff --git
a/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxies.yaml
b/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxies.yaml
index 0592270..01a235e 100644
---
a/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxies.yaml
+++
b/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxies.yaml
@@ -20,7 +20,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.8.0
+ controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: shardingsphereproxies.shardingsphere.apache.org
spec:
@@ -62,6 +62,488 @@ spec:
automaticScaling:
description: AutomaticScaling HPA configuration
properties:
+ customMetrics:
+ items:
+ description: MetricSpec specifies how to scale based on
a single
+ metric (only `type` and one other matching field
should be
+ set at once).
+ properties:
+ containerResource:
+ description: container resource refers to a resource
metric
+ (such as those specified in requests and limits)
known
+ to Kubernetes describing a single container in
each pod
+ of the current scale target (e.g. CPU or memory).
Such
+ metrics are built in to Kubernetes, and have
special scaling
+ options on top of those available to normal
per-pod metrics
+ using the "pods" source. This is an alpha feature
and
+ can be enabled by the HPAContainerMetrics feature
flag.
+ properties:
+ container:
+ description: container is the name of the
container
+ in the pods of the scaling target
+ type: string
+ name:
+ description: name is the name of the resource in
question.
+ type: string
+ target:
+ description: target specifies the target value
for the
+ given metric
+ properties:
+ averageUtilization:
+ description: averageUtilization is the
target value
+ of the average of the resource metric
across all
+ relevant pods, represented as a percentage
of
+ the requested value of the resource for
the pods.
+ Currently only valid for Resource metric
source
+ type
+ format: int32
+ type: integer
+ averageValue:
+ anyOf:
+ - type: integer
+ - type: string
+ description: averageValue is the target
value of
+ the average of the metric across all
relevant
+ pods (as a quantity)
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type:
+ description: type represents whether the
metric
+ type is Utilization, Value, or AverageValue
+ type: string
+ value:
+ anyOf:
+ - type: integer
+ - type: string
+ description: value is the target value of
the metric
+ (as a quantity).
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - type
+ type: object
+ required:
+ - container
+ - name
+ - target
+ type: object
+ external:
+ description: external refers to a global metric that
is
+ not associated with any Kubernetes object. It
allows autoscaling
+ based on information coming from components
running outside
+ of cluster (for example length of queue in cloud
messaging
+ service, or QPS from loadbalancer running outside
of cluster).
+ properties:
+ metric:
+ description: metric identifies the target metric
by
+ name and selector
+ properties:
+ name:
+ description: name is the name of the given
metric
+ type: string
+ selector:
+ description: selector is the string-encoded
form
+ of a standard kubernetes label selector
for the
+ given metric When set, it is passed as an
additional
+ parameter to the metrics server for more
specific
+ metrics scoping. When unset, just the
metricName
+ will be used to gather metrics.
+ properties:
+ matchExpressions:
+ 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.
+ properties:
+ key:
+ 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.
+ 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.
+ items:
+ type: string
+ type: array
+ required:
+ - 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.
+ type: object
+ type: object
+ required:
+ - name
+ type: object
+ target:
+ description: target specifies the target value
for the
+ given metric
+ properties:
+ averageUtilization:
+ description: averageUtilization is the
target value
+ of the average of the resource metric
across all
+ relevant pods, represented as a percentage
of
+ the requested value of the resource for
the pods.
+ Currently only valid for Resource metric
source
+ type
+ format: int32
+ type: integer
+ averageValue:
+ anyOf:
+ - type: integer
+ - type: string
+ description: averageValue is the target
value of
+ the average of the metric across all
relevant
+ pods (as a quantity)
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type:
+ description: type represents whether the
metric
+ type is Utilization, Value, or AverageValue
+ type: string
+ value:
+ anyOf:
+ - type: integer
+ - type: string
+ description: value is the target value of
the metric
+ (as a quantity).
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - type
+ type: object
+ required:
+ - metric
+ - target
+ type: object
+ object:
+ description: object refers to a metric describing a
single
+ kubernetes object (for example, hits-per-second on
an
+ Ingress object).
+ properties:
+ describedObject:
+ description: CrossVersionObjectReference
contains enough
+ information to let you identify the referred
resource.
+ properties:
+ apiVersion:
+ description: API version of the referent
+ type: string
+ kind:
+ description: 'Kind of the referent; More
info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"'
+ type: string
+ name:
+ description: 'Name of the referent; More
info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ metric:
+ description: metric identifies the target metric
by
+ name and selector
+ properties:
+ name:
+ description: name is the name of the given
metric
+ type: string
+ selector:
+ description: selector is the string-encoded
form
+ of a standard kubernetes label selector
for the
+ given metric When set, it is passed as an
additional
+ parameter to the metrics server for more
specific
+ metrics scoping. When unset, just the
metricName
+ will be used to gather metrics.
+ properties:
+ matchExpressions:
+ 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.
+ properties:
+ key:
+ 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.
+ 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.
+ items:
+ type: string
+ type: array
+ required:
+ - 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.
+ type: object
+ type: object
+ required:
+ - name
+ type: object
+ target:
+ description: target specifies the target value
for the
+ given metric
+ properties:
+ averageUtilization:
+ description: averageUtilization is the
target value
+ of the average of the resource metric
across all
+ relevant pods, represented as a percentage
of
+ the requested value of the resource for
the pods.
+ Currently only valid for Resource metric
source
+ type
+ format: int32
+ type: integer
+ averageValue:
+ anyOf:
+ - type: integer
+ - type: string
+ description: averageValue is the target
value of
+ the average of the metric across all
relevant
+ pods (as a quantity)
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type:
+ description: type represents whether the
metric
+ type is Utilization, Value, or AverageValue
+ type: string
+ value:
+ anyOf:
+ - type: integer
+ - type: string
+ description: value is the target value of
the metric
+ (as a quantity).
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - type
+ type: object
+ required:
+ - describedObject
+ - metric
+ - target
+ type: object
+ pods:
+ description: pods refers to a metric describing each
pod
+ in the current scale target (for example,
transactions-processed-per-second). The
+ values will be averaged together before being
compared
+ to the target value.
+ properties:
+ metric:
+ description: metric identifies the target metric
by
+ name and selector
+ properties:
+ name:
+ description: name is the name of the given
metric
+ type: string
+ selector:
+ description: selector is the string-encoded
form
+ of a standard kubernetes label selector
for the
+ given metric When set, it is passed as an
additional
+ parameter to the metrics server for more
specific
+ metrics scoping. When unset, just the
metricName
+ will be used to gather metrics.
+ properties:
+ matchExpressions:
+ 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.
+ properties:
+ key:
+ 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.
+ 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.
+ items:
+ type: string
+ type: array
+ required:
+ - 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.
+ type: object
+ type: object
+ required:
+ - name
+ type: object
+ target:
+ description: target specifies the target value
for the
+ given metric
+ properties:
+ averageUtilization:
+ description: averageUtilization is the
target value
+ of the average of the resource metric
across all
+ relevant pods, represented as a percentage
of
+ the requested value of the resource for
the pods.
+ Currently only valid for Resource metric
source
+ type
+ format: int32
+ type: integer
+ averageValue:
+ anyOf:
+ - type: integer
+ - type: string
+ description: averageValue is the target
value of
+ the average of the metric across all
relevant
+ pods (as a quantity)
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type:
+ description: type represents whether the
metric
+ type is Utilization, Value, or AverageValue
+ type: string
+ value:
+ anyOf:
+ - type: integer
+ - type: string
+ description: value is the target value of
the metric
+ (as a quantity).
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - type
+ type: object
+ required:
+ - metric
+ - target
+ type: object
+ resource:
+ description: resource refers to a resource metric
(such
+ as those specified in requests and limits) known
to Kubernetes
+ describing each pod in the current scale target
(e.g.
+ CPU or memory). Such metrics are built in to
Kubernetes,
+ and have special scaling options on top of those
available
+ to normal per-pod metrics using the "pods" source.
+ properties:
+ name:
+ description: name is the name of the resource in
question.
+ type: string
+ target:
+ description: target specifies the target value
for the
+ given metric
+ properties:
+ averageUtilization:
+ description: averageUtilization is the
target value
+ of the average of the resource metric
across all
+ relevant pods, represented as a percentage
of
+ the requested value of the resource for
the pods.
+ Currently only valid for Resource metric
source
+ type
+ format: int32
+ type: integer
+ averageValue:
+ anyOf:
+ - type: integer
+ - type: string
+ description: averageValue is the target
value of
+ the average of the metric across all
relevant
+ pods (as a quantity)
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type:
+ description: type represents whether the
metric
+ type is Utilization, Value, or AverageValue
+ type: string
+ value:
+ anyOf:
+ - type: integer
+ - type: string
+ description: value is the target value of
the metric
+ (as a quantity).
+ pattern:
^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - type
+ type: object
+ required:
+ - name
+ - target
+ type: object
+ type:
+ description: 'type is the type of metric source. It
should
+ be one of "ContainerResource", "External",
"Object", "Pods"
+ or "Resource", each mapping to a matching field in
the
+ object. Note: "ContainerResource" type is
available on
+ when the feature-gate HPAContainerMetrics is
enabled'
+ type: string
+ required:
+ - type
+ type: object
+ type: array
enable:
type: boolean
maxInstance:
@@ -656,9 +1138,3 @@ spec:
storage: true
subresources:
status: {}
-status:
- acceptedNames:
- kind: ""
- plural: ""
- conditions: []
- storedVersions: []
diff --git
a/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxyserverconfigs.yaml
b/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxyserverconfigs.yaml
index 1b18874..bebd4b6 100644
---
a/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxyserverconfigs.yaml
+++
b/charts/apache-shardingsphere-operator-charts/crds/shardingsphere.apache.org_shardingsphereproxyserverconfigs.yaml
@@ -20,7 +20,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.8.0
+ controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: shardingsphereproxyserverconfigs.shardingsphere.apache.org
spec:
@@ -205,9 +205,3 @@ spec:
storage: true
subresources:
status: {}
-status:
- acceptedNames:
- kind: ""
- plural: ""
- conditions: []
- storedVersions: []
diff --git a/shardingsphere-operator/api/v1alpha1/proxy_types.go
b/shardingsphere-operator/api/v1alpha1/proxy_types.go
index 7404370..920e308 100644
--- a/shardingsphere-operator/api/v1alpha1/proxy_types.go
+++ b/shardingsphere-operator/api/v1alpha1/proxy_types.go
@@ -18,6 +18,7 @@
package v1alpha1
import (
+ autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -25,7 +26,7 @@ import (
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags
for the fields to be serialized.
-//ServiceType defines the Service in Kubernetes of ShardingSphere-Proxy
+// ServiceType defines the Service in Kubernetes of ShardingSphere-Proxy
type ServiceType struct {
//
+kubebuilder:validation:Enum=ClusterIP;NodePort;LoadBalancer;ExternalName
@@ -45,7 +46,7 @@ type ServiceType struct {
NodePort int32 `json:"nodePort"`
}
-//MySQLDriver Defines the mysql-driven version in ShardingSphere-proxy
+// MySQLDriver Defines the mysql-driven version in ShardingSphere-proxy
type MySQLDriver struct {
//
+kubebuilder:validation:Pattern=`^([1-9]\d|[1-9])(\.([1-9]\d|\d)){2}$`
// mysql-driven version,must be x.y.z
@@ -66,6 +67,8 @@ type AutomaticScaling struct {
MaxInstance int32 `json:"maxInstance,omitempty"`
// +optional
MinInstance int32 `json:"minInstance,omitempty"`
+ // +optional
+ CustomMetrics []autoscalingv2beta2.MetricSpec
`json:"customMetrics,omitempty"`
}
// ProxySpec defines the desired state of ShardingSphereProxy
diff --git a/shardingsphere-operator/api/v1alpha1/zz_generated.deepcopy.go
b/shardingsphere-operator/api/v1alpha1/zz_generated.deepcopy.go
index e50a798..06c0e31 100644
--- a/shardingsphere-operator/api/v1alpha1/zz_generated.deepcopy.go
+++ b/shardingsphere-operator/api/v1alpha1/zz_generated.deepcopy.go
@@ -22,6 +22,7 @@ limitations under the License.
package v1alpha1
import (
+ "k8s.io/api/autoscaling/v2beta2"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -54,6 +55,13 @@ func (in *Auth) DeepCopy() *Auth {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
func (in *AutomaticScaling) DeepCopyInto(out *AutomaticScaling) {
*out = *in
+ if in.CustomMetrics != nil {
+ in, out := &in.CustomMetrics, &out.CustomMetrics
+ *out = make([]v2beta2.MetricSpec, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new AutomaticScaling.
@@ -223,7 +231,7 @@ func (in *ProxySpec) DeepCopyInto(out *ProxySpec) {
if in.AutomaticScaling != nil {
in, out := &in.AutomaticScaling, &out.AutomaticScaling
*out = new(AutomaticScaling)
- **out = **in
+ (*in).DeepCopyInto(*out)
}
if in.ImagePullSecrets != nil {
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
diff --git a/shardingsphere-operator/pkg/reconcile/reconcile_test.go
b/shardingsphere-operator/pkg/reconcile/reconcile_test.go
index d4f35ac..ab6dd55 100644
--- a/shardingsphere-operator/pkg/reconcile/reconcile_test.go
+++ b/shardingsphere-operator/pkg/reconcile/reconcile_test.go
@@ -19,6 +19,9 @@ package reconcile
import (
"fmt"
+ autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
+ "k8s.io/apimachinery/pkg/api/resource"
+ "k8s.io/utils/pointer"
"strconv"
"testing"
@@ -637,7 +640,152 @@ func Test_UpdateService(t *testing.T) {
}
func Test_UpdateHPA(t *testing.T) {
+ cases := []struct {
+ proxy *v1alpha1.ShardingSphereProxy
+ hpa *autoscalingv2beta2.HorizontalPodAutoscaler
+ message string
+ }{
+ {
+ proxy: &v1alpha1.ShardingSphereProxy{
+ Spec: v1alpha1.ProxySpec{
+ AutomaticScaling:
&v1alpha1.AutomaticScaling{
+ Enable: true,
+ ScaleUpWindows: 15,
+ ScaleDownWindows: 30,
+ MaxInstance: 5,
+ MinInstance: 3,
+ Target: 70,
+ },
+ },
+ },
+ hpa: &autoscalingv2beta2.HorizontalPodAutoscaler{
+ Spec:
autoscalingv2beta2.HorizontalPodAutoscalerSpec{
+ ScaleTargetRef:
autoscalingv2beta2.CrossVersionObjectReference{
+ Kind: "Deployment",
+ Name: "test",
+ APIVersion:
appsv1.SchemeGroupVersion.String(),
+ },
+ MinReplicas: pointer.Int32(3),
+ MaxReplicas: 10,
+ Metrics:
[]autoscalingv2beta2.MetricSpec{
+ {
+ Type:
autoscalingv2beta2.ResourceMetricSourceType,
+ Resource:
&autoscalingv2beta2.ResourceMetricSource{
+ Name: "cpu",
+ Target:
autoscalingv2beta2.MetricTarget{
+ Type:
autoscalingv2beta2.UtilizationMetricType,
+
AverageUtilization: pointer.Int32(60),
+ },
+ },
+ },
+ },
+ Behavior:
&autoscalingv2beta2.HorizontalPodAutoscalerBehavior{
+ ScaleUp:
&autoscalingv2beta2.HPAScalingRules{
+
StabilizationWindowSeconds: pointer.Int32(15),
+ },
+ ScaleDown:
&autoscalingv2beta2.HPAScalingRules{
+
StabilizationWindowSeconds: pointer.Int32(60),
+ Policies:
[]autoscalingv2beta2.HPAScalingPolicy{
+ {
+ Type:
autoscalingv2beta2.PodsScalingPolicy,
+ Value:
1,
+
PeriodSeconds: 30,
+ },
+ },
+ },
+ },
+ },
+ },
+ message: "hpa should be updated",
+ },
+ }
+
+ for _, c := range cases {
+ UpdateHPA(c.proxy, c.hpa)
+ assert.Equal(t, c.proxy.Spec.AutomaticScaling.Target,
*c.hpa.Spec.Metrics[0].Resource.Target.AverageUtilization)
+ assert.Equal(t, c.proxy.Spec.AutomaticScaling.ScaleDownWindows,
*c.hpa.Spec.Behavior.ScaleDown.StabilizationWindowSeconds)
+ }
+}
+func Test_UpdateHPAMetric(t *testing.T) {
+ cases := []struct {
+ proxy *v1alpha1.ShardingSphereProxy
+ hpa *autoscalingv2beta2.HorizontalPodAutoscaler
+ message string
+ }{
+ {
+ proxy: &v1alpha1.ShardingSphereProxy{
+ Spec: v1alpha1.ProxySpec{
+ AutomaticScaling:
&v1alpha1.AutomaticScaling{
+ Enable: true,
+ ScaleUpWindows: 15,
+ ScaleDownWindows: 30,
+ MaxInstance: 5,
+ MinInstance: 3,
+ Target: 70,
+ CustomMetrics:
[]autoscalingv2beta2.MetricSpec{
+ {
+ Type: "pods",
+ Pods:
&autoscalingv2beta2.PodsMetricSource{
+ Metric:
autoscalingv2beta2.MetricIdentifier{
+
Name: "latency_seconds_test_avg",
+ },
+ Target:
autoscalingv2beta2.MetricTarget{
+
Type: autoscalingv2beta2.AverageValueMetricType,
+
AverageValue: resource.NewQuantity(12, resource.DecimalSI),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ hpa: &autoscalingv2beta2.HorizontalPodAutoscaler{
+ Spec:
autoscalingv2beta2.HorizontalPodAutoscalerSpec{
+ ScaleTargetRef:
autoscalingv2beta2.CrossVersionObjectReference{
+ Kind: "Deployment",
+ Name: "test",
+ APIVersion:
appsv1.SchemeGroupVersion.String(),
+ },
+ MinReplicas: pointer.Int32(3),
+ MaxReplicas: 10,
+ Metrics:
[]autoscalingv2beta2.MetricSpec{
+ {
+ Type:
autoscalingv2beta2.ResourceMetricSourceType,
+ Resource:
&autoscalingv2beta2.ResourceMetricSource{
+ Name: "cpu",
+ Target:
autoscalingv2beta2.MetricTarget{
+ Type:
autoscalingv2beta2.UtilizationMetricType,
+
AverageUtilization: pointer.Int32(60),
+ },
+ },
+ },
+ },
+ Behavior:
&autoscalingv2beta2.HorizontalPodAutoscalerBehavior{
+ ScaleUp:
&autoscalingv2beta2.HPAScalingRules{
+
StabilizationWindowSeconds: pointer.Int32(15),
+ },
+ ScaleDown:
&autoscalingv2beta2.HPAScalingRules{
+
StabilizationWindowSeconds: pointer.Int32(60),
+ Policies:
[]autoscalingv2beta2.HPAScalingPolicy{
+ {
+ Type:
autoscalingv2beta2.PodsScalingPolicy,
+ Value:
1,
+
PeriodSeconds: 30,
+ },
+ },
+ },
+ },
+ },
+ },
+ message: "hpa should be updated",
+ },
+ }
+
+ for _, c := range cases {
+ UpdateHPA(c.proxy, c.hpa)
+ assert.Equal(t, c.proxy.Spec.AutomaticScaling.CustomMetrics,
c.hpa.Spec.Metrics)
+ }
}
func Test_fromInt32(t *testing.T) {
diff --git a/shardingsphere-operator/pkg/reconcile/resource.go
b/shardingsphere-operator/pkg/reconcile/resource.go
index c7d8dd1..66f0be0 100644
--- a/shardingsphere-operator/pkg/reconcile/resource.go
+++ b/shardingsphere-operator/pkg/reconcile/resource.go
@@ -256,6 +256,12 @@ func ConstructCascadingConfigmap(proxyConfig
*v1alpha1.ShardingSphereProxyServer
// ConstructHPA Create HPA if you need
func ConstructHPA(proxy *v1alpha1.ShardingSphereProxy)
*autoscalingv2beta2.HorizontalPodAutoscaler {
+ var metrics =
ConstructDefaultHPAMetric(&proxy.Spec.AutomaticScaling.Target)
+
+ if len(proxy.Spec.AutomaticScaling.CustomMetrics) > 0 {
+ metrics = proxy.Spec.AutomaticScaling.CustomMetrics
+ }
+
return &autoscalingv2beta2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: proxy.Name,
@@ -272,18 +278,7 @@ func ConstructHPA(proxy *v1alpha1.ShardingSphereProxy)
*autoscalingv2beta2.Horiz
},
MinReplicas: &proxy.Spec.AutomaticScaling.MinInstance,
MaxReplicas: proxy.Spec.AutomaticScaling.MaxInstance,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type:
autoscalingv2beta2.ResourceMetricSourceType,
- Resource:
&autoscalingv2beta2.ResourceMetricSource{
- Name: "cpu",
- Target:
autoscalingv2beta2.MetricTarget{
- Type:
autoscalingv2beta2.UtilizationMetricType,
- AverageUtilization:
&proxy.Spec.AutomaticScaling.Target,
- },
- },
- },
- },
+ Metrics: metrics,
Behavior:
&autoscalingv2beta2.HorizontalPodAutoscalerBehavior{
ScaleUp: &autoscalingv2beta2.HPAScalingRules{
StabilizationWindowSeconds:
&proxy.Spec.AutomaticScaling.ScaleUpWindows,
@@ -304,6 +299,21 @@ func ConstructHPA(proxy *v1alpha1.ShardingSphereProxy)
*autoscalingv2beta2.Horiz
}
+func ConstructDefaultHPAMetric(target *int32) []autoscalingv2beta2.MetricSpec {
+ return []autoscalingv2beta2.MetricSpec{
+ {
+ Type: autoscalingv2beta2.ResourceMetricSourceType,
+ Resource: &autoscalingv2beta2.ResourceMetricSource{
+ Name: "cpu",
+ Target: autoscalingv2beta2.MetricTarget{
+ Type:
autoscalingv2beta2.UtilizationMetricType,
+ AverageUtilization: target,
+ },
+ },
+ },
+ }
+}
+
// ToYaml Convert ShardingSphereProxyServerConfig spec content to yaml format
func toYaml(proxyConfig *v1alpha1.ShardingSphereProxyServerConfig) string {
y, _ := yaml.Marshal(proxyConfig.Spec)
@@ -339,11 +349,16 @@ func UpdateService(proxy *v1alpha1.ShardingSphereProxy,
runtimeService *v1.Servi
}
func UpdateHPA(proxy *v1alpha1.ShardingSphereProxy, runtimeHPA
*autoscalingv2beta2.HorizontalPodAutoscaler) {
- runtimeHPA.Spec.Metrics[0].Resource.Target.AverageUtilization =
&proxy.Spec.AutomaticScaling.Target
runtimeHPA.Spec.Behavior.ScaleDown.StabilizationWindowSeconds =
&proxy.Spec.AutomaticScaling.ScaleDownWindows
runtimeHPA.Spec.Behavior.ScaleUp.StabilizationWindowSeconds =
&proxy.Spec.AutomaticScaling.ScaleUpWindows
runtimeHPA.Spec.MaxReplicas = proxy.Spec.AutomaticScaling.MaxInstance
runtimeHPA.Spec.MinReplicas = &proxy.Spec.AutomaticScaling.MinInstance
+ if len(proxy.Spec.AutomaticScaling.CustomMetrics) > 0 {
+ runtimeHPA.Spec.Metrics =
proxy.Spec.AutomaticScaling.CustomMetrics
+ } else {
+ // We need to reconstruct the default hpa metric when the user
deletes the custom metric.
+ runtimeHPA.Spec.Metrics =
ConstructDefaultHPAMetric(&proxy.Spec.AutomaticScaling.Target)
+ }
}
func fromInt32(val int32) intstr.IntOrString {