You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by su...@apache.org on 2022/12/16 08:07:48 UTC

[shardingsphere-on-cloud] branch main updated: refactor: refactor reconcile and resources (#148)

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 0b0d762  refactor: refactor reconcile and resources  (#148)
0b0d762 is described below

commit 0b0d762c0c49c90911aaafc90727132aa4a6c881
Author: liyao <ma...@126.com>
AuthorDate: Fri Dec 16 16:07:44 2022 +0800

    refactor: refactor reconcile and resources  (#148)
    
    * refactor: refactor workloads
    
    Signed-off-by: mlycore <ma...@126.com>
    
    * chore: go fmt
    
    Signed-off-by: mlycore <ma...@126.com>
    
    * fix: IsNotFound should be checked while error is not nil
    
    Signed-off-by: mlycore <ma...@126.com>
    
    * chore: update UpdateDeployment
    
    Signed-off-by: mlycore <ma...@126.com>
    
    Signed-off-by: mlycore <ma...@126.com>
---
 .../api/v1alpha1/groupversion_info.go              |   4 +-
 .../api/v1alpha1/proxy_status.go                   |  16 +-
 .../pkg/controllers/proxy_controller.go            | 196 ++++++++------
 shardingsphere-operator/pkg/reconcile/coverage.txt |  54 ++++
 .../pkg/reconcile/deployment.go                    | 194 ++++++++++++++
 shardingsphere-operator/pkg/reconcile/hpa.go       | 104 ++++++++
 .../pkg/reconcile/reconcile_test.go                | 116 ++++-----
 shardingsphere-operator/pkg/reconcile/resource.go  | 281 +--------------------
 shardingsphere-operator/pkg/reconcile/service.go   |  72 ++++++
 9 files changed, 610 insertions(+), 427 deletions(-)

diff --git a/shardingsphere-operator/api/v1alpha1/groupversion_info.go b/shardingsphere-operator/api/v1alpha1/groupversion_info.go
index 7af5844..3e1541c 100644
--- a/shardingsphere-operator/api/v1alpha1/groupversion_info.go
+++ b/shardingsphere-operator/api/v1alpha1/groupversion_info.go
@@ -16,8 +16,8 @@
  */
 
 // Package v1alpha1 contains API Schema definitions for the shardingsphere v1alpha1 API group
-//+kubebuilder:object:generate=true
-//+groupName=shardingsphere.apache.org
+// +kubebuilder:object:generate=true
+// +groupName=shardingsphere.apache.org
 package v1alpha1
 
 import (
diff --git a/shardingsphere-operator/api/v1alpha1/proxy_status.go b/shardingsphere-operator/api/v1alpha1/proxy_status.go
index a769ff1..af6ffb7 100644
--- a/shardingsphere-operator/api/v1alpha1/proxy_status.go
+++ b/shardingsphere-operator/api/v1alpha1/proxy_status.go
@@ -56,14 +56,14 @@ type ProxyStatus struct {
 type Conditions []Condition
 
 // Condition
-//| **condition** | **status** | **directions**|
-//| ------------- | ---------- | ---------------------------------------------------- |
-//| Initialized   | true       | Initialization successful|
-//| Initialized   | false      | initialization failed|
-//| Started       | true       | pod started successfully but not ready|
-//| Started       | false      | pod started failed|
-//| Ready         | true       | The pod is ready and can provide external services|
-//| Unknown       | true       | ShardingSphere-Proxy failed to start correctly due to some problems |
+// | **condition** | **status** | **directions**|
+// | ------------- | ---------- | ---------------------------------------------------- |
+// | Initialized   | true       | Initialization successful|
+// | Initialized   | false      | initialization failed|
+// | Started       | true       | pod started successfully but not ready|
+// | Started       | false      | pod started failed|
+// | Ready         | true       | The pod is ready and can provide external services|
+// | Unknown       | true       | ShardingSphere-Proxy failed to start correctly due to some problems |
 type Condition struct {
 	Type           ConditionType      `json:"type"`
 	Status         v1.ConditionStatus `json:"status"`
diff --git a/shardingsphere-operator/pkg/controllers/proxy_controller.go b/shardingsphere-operator/pkg/controllers/proxy_controller.go
index 93ae6dd..85bf3c8 100644
--- a/shardingsphere-operator/pkg/controllers/proxy_controller.go
+++ b/shardingsphere-operator/pkg/controllers/proxy_controller.go
@@ -23,13 +23,16 @@ import (
 
 	"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1"
 	"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile"
+
 	appsv1 "k8s.io/api/apps/v1"
 	autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
 	v1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+
 	logger "sigs.k8s.io/controller-runtime/pkg/log"
 )
 
@@ -61,106 +64,144 @@ type ProxyReconciler struct {
 func (r *ProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := logger.FromContext(ctx)
 
-	run := &v1alpha1.ShardingSphereProxy{}
-	err := r.Get(ctx, req.NamespacedName, run)
+	rt, err := r.getRuntimeShardingSphereProxy(ctx, req.NamespacedName)
 	if apierrors.IsNotFound(err) {
 		log.Info("Resource in work queue no longer exists!")
 		return ctrl.Result{}, nil
 	} else if err != nil {
-		log.Error(err, "Error getting  CRD resource")
+		log.Error(err, "Error getting CRD resource")
 		return ctrl.Result{}, err
 	}
 
-	runtimeDeployment := &appsv1.Deployment{}
-	err = r.Get(ctx, req.NamespacedName, runtimeDeployment)
-	if err != nil && !apierrors.IsNotFound(err) {
-		log.Error(err, "Error getting cascaded HPA")
-		return ctrl.Result{}, err
+	return r.reconcile(ctx, req, rt)
+}
+
+func (r *ProxyReconciler) getRuntimeShardingSphereProxy(ctx context.Context, namespacedName types.NamespacedName) (*v1alpha1.ShardingSphereProxy, error) {
+	rt := &v1alpha1.ShardingSphereProxy{}
+	err := r.Get(ctx, namespacedName, rt)
+	return rt, err
+}
+
+func (r *ProxyReconciler) reconcile(ctx context.Context, req ctrl.Request, rt *v1alpha1.ShardingSphereProxy) (ctrl.Result, error) {
+	log := logger.FromContext(ctx)
+	if res, err := r.reconcileDeployment(ctx, req.NamespacedName, rt); err != nil {
+		log.Error(err, "Error reconcile Deployment")
+		return res, err
 	}
-	if apierrors.IsNotFound(err) {
-		cascadingDeployment := reconcile.ConstructCascadingDeployment(run)
-		err = r.Create(ctx, cascadingDeployment)
-		if err != nil {
-			run.SetInitializationFailed()
-			_ = r.Status().Update(ctx, run)
-			log.Error(err, "Error creating cascaded deployment")
+
+	if res, err := r.reconcileService(ctx, req.NamespacedName, rt); err != nil {
+		log.Error(err, "Error reconcile Service")
+		return res, err
+	}
+	if res, err := r.reconcilePodList(ctx, req.Namespace, req.Name, rt); err != nil {
+		log.Error(err, "Error reconcile Pod list")
+		return res, err
+	}
+
+	if res, err := r.reconcileHPA(ctx, req.NamespacedName, rt); err != nil {
+		log.Error(err, "Error reconcile HPA")
+		return res, err
+	}
+
+	return ctrl.Result{}, nil
+}
+
+func (r *ProxyReconciler) reconcileDeployment(ctx context.Context, namespacedName types.NamespacedName, ssproxy *v1alpha1.ShardingSphereProxy) (ctrl.Result, error) {
+	deploy := &appsv1.Deployment{}
+
+	var err error
+	if err = r.Get(ctx, namespacedName, deploy); err != nil {
+		if !apierrors.IsNotFound(err) {
 			return ctrl.Result{}, err
+		} else {
+			exp := reconcile.NewDeployment(ssproxy)
+			if err := r.Create(ctx, exp); err != nil {
+				ssproxy.SetInitializationFailed()
+				_ = r.Status().Update(ctx, ssproxy)
+				return ctrl.Result{}, err
+			}
 		}
 	} else {
-		originDeployment := runtimeDeployment.DeepCopy()
-		reconcile.UpdateDeployment(run, originDeployment)
-		err = r.Update(ctx, originDeployment)
-		if err != nil {
-			log.Error(err, "Error updating cascaded deployment")
+		act := deploy.DeepCopy()
+		exp := reconcile.UpdateDeployment(ssproxy, act)
+
+		//FIXME: using diff to trigger update
+		// if reflect.DeepEqual(act.Spec.Template, exp.Spec.Template) {
+		// 	return ctrl.Result{}, nil
+		// }
+
+		if err := r.Update(ctx, exp); err != nil {
 			return ctrl.Result{Requeue: true}, err
 		}
 	}
-	runtimeHPA := &autoscalingv2beta2.HorizontalPodAutoscaler{}
-	err = r.Get(ctx, req.NamespacedName, runtimeHPA)
-	if err != nil && !apierrors.IsNotFound(err) {
-		log.Error(err, "Error getting cascaded HPA")
-		return ctrl.Result{}, err
-	}
-	if apierrors.IsNotFound(err) {
-		if run.Spec.AutomaticScaling != nil {
-			cascadingHPA := reconcile.ConstructHPA(run)
-			err = r.Create(ctx, cascadingHPA)
-			if err != nil {
-				run.SetInitializationFailed()
-				_ = r.Status().Update(ctx, run)
-				log.Error(err, "Error creating cascaded HPA")
-				return ctrl.Result{}, err
+	return ctrl.Result{}, nil
+}
+
+func (r *ProxyReconciler) reconcileHPA(ctx context.Context, namespacedName types.NamespacedName, ssproxy *v1alpha1.ShardingSphereProxy) (ctrl.Result, error) {
+	hpa := &autoscalingv2beta2.HorizontalPodAutoscaler{}
+
+	var err error
+	if err = r.Get(ctx, namespacedName, hpa); err != nil {
+		if !apierrors.IsNotFound(err) {
+			return ctrl.Result{}, err
+		} else {
+			if ssproxy.Spec.AutomaticScaling != nil && ssproxy.Spec.AutomaticScaling.Enable {
+				exp := reconcile.NewHPA(ssproxy)
+				if err := r.Create(ctx, exp); err != nil {
+					ssproxy.SetInitializationFailed()
+					_ = r.Status().Update(ctx, ssproxy)
+					return ctrl.Result{}, err
+				}
 			}
 		}
 	} else {
-		if run.Spec.AutomaticScaling == nil {
-			err = r.Delete(ctx, runtimeHPA)
-			if err != nil {
-				log.Error(err, "Error delete cascaded HPA")
+		if ssproxy.Spec.AutomaticScaling == nil || !ssproxy.Spec.AutomaticScaling.Enable {
+			if err := r.Delete(ctx, hpa); err != nil {
 				return ctrl.Result{}, err
 			}
 		} else {
-			originHPA := runtimeHPA.DeepCopy()
-			reconcile.UpdateHPA(run, originHPA)
-			err = r.Update(ctx, originHPA)
-			if err != nil {
-				log.Error(err, "Error updating cascaded HPA")
+			act := hpa.DeepCopy()
+			exp := reconcile.UpdateHPA(ssproxy, act)
+			if err := r.Update(ctx, exp); err != nil {
 				return ctrl.Result{}, err
 			}
 		}
 	}
 
-	runtimeService := &v1.Service{}
-	err = r.Get(ctx, req.NamespacedName, runtimeService)
-	if err != nil && !apierrors.IsNotFound(err) {
-		log.Error(err, "Error getting cascaded Service")
-		return ctrl.Result{}, err
-	}
-	if apierrors.IsNotFound(err) {
-		cascadingService := reconcile.ConstructCascadingService(run)
-		err = r.Create(ctx, cascadingService)
-		if err != nil {
-			run.SetInitializationFailed()
-			_ = r.Status().Update(ctx, run)
-			log.Error(err, "Error creating cascaded service")
+	return ctrl.Result{}, nil
+}
+
+func (r *ProxyReconciler) reconcileService(ctx context.Context, namespacedName types.NamespacedName, ssproxy *v1alpha1.ShardingSphereProxy) (ctrl.Result, error) {
+	service := &v1.Service{}
+
+	var err error
+	if err = r.Get(ctx, namespacedName, service); err != nil {
+		if !apierrors.IsNotFound(err) {
 			return ctrl.Result{}, err
+		} else {
+			exp := reconcile.NewService(ssproxy)
+			if err := r.Create(ctx, exp); err != nil {
+				ssproxy.SetInitializationFailed()
+				_ = r.Status().Update(ctx, ssproxy)
+				return ctrl.Result{}, err
+			}
+			ssproxy.SetInitialized()
+			return ctrl.Result{RequeueAfter: WaitingForReady}, nil
 		}
-		run.SetInitialized()
-		return ctrl.Result{RequeueAfter: WaitingForReady}, nil
 	} else {
-		originService := runtimeService.DeepCopy()
-		reconcile.UpdateService(run, originService)
-		err = r.Update(ctx, originService)
-		if err != nil {
-			log.Error(err, "Error updating cascaded service")
+		act := service.DeepCopy()
+		reconcile.UpdateService(ssproxy, act)
+		if err := r.Update(ctx, act); err != nil {
 			return ctrl.Result{}, err
 		}
 	}
 
+	return ctrl.Result{}, nil
+}
+
+func (r *ProxyReconciler) reconcilePodList(ctx context.Context, namespace, name string, ssproxy *v1alpha1.ShardingSphereProxy) (ctrl.Result, error) {
 	podList := &v1.PodList{}
-	err = r.List(ctx, podList, client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{"apps": req.Name}))
-	if err != nil {
-		log.Error(err, "Error listing cascaded pod")
+	if err := r.List(ctx, podList, client.InNamespace(namespace), client.MatchingLabels(map[string]string{"apps": name})); err != nil {
 		return ctrl.Result{}, err
 	}
 
@@ -169,30 +210,27 @@ func (r *ProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
 	if reconcile.IsRunning(podList) {
 		if readyNodes < miniReadyCount {
 			result.RequeueAfter = WaitingForReady
-			if readyNodes != run.Status.ReadyNodes {
-				run.SetPodStarted(readyNodes)
+			if readyNodes != ssproxy.Status.ReadyNodes {
+				ssproxy.SetPodStarted(readyNodes)
 			}
 		} else {
-			if run.Status.Phase != v1alpha1.StatusReady {
-				log.Info("Status is now ready!")
-				run.SetReady(readyNodes)
-			} else if readyNodes != *runtimeDeployment.Spec.Replicas {
-				run.UpdateReadyNodes(readyNodes)
+			if ssproxy.Status.Phase != v1alpha1.StatusReady {
+				ssproxy.SetReady(readyNodes)
+			} else if readyNodes != ssproxy.Spec.Replicas {
+				ssproxy.UpdateReadyNodes(readyNodes)
 			}
 		}
 	} else {
 		// TODO: Waiting for pods to start exceeds the maximum number of retries
-		run.SetPodNotStarted(readyNodes)
+		ssproxy.SetPodNotStarted(readyNodes)
 		result.RequeueAfter = WaitingForReady
 	}
 
 	// TODO: Compare Status with or without modification
-	err = r.Status().Update(ctx, run)
-	if err != nil {
-		log.Error(err, "Error updating status")
+	if err := r.Status().Update(ctx, ssproxy); err != nil {
 		return result, err
 	}
-	log.Info("RuntimeCRD status ", "status", run.Status)
+
 	return result, nil
 }
 
diff --git a/shardingsphere-operator/pkg/reconcile/coverage.txt b/shardingsphere-operator/pkg/reconcile/coverage.txt
new file mode 100644
index 0000000..6a9fca8
--- /dev/null
+++ b/shardingsphere-operator/pkg/reconcile/coverage.txt
@@ -0,0 +1,54 @@
+mode: atomic
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:71.91,72.79 1 3
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:76.2,140.40 2 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:143.2,143.33 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:146.2,146.37 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:149.2,149.38 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:152.2,152.36 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:155.2,155.42 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:158.2,158.44 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:72.79,74.3 1 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:140.40,142.3 1 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:143.33,145.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:146.37,148.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:149.38,151.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:152.36,154.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:155.42,157.3 1 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:161.81,162.79 1 3
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:166.2,188.59 2 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:191.2,191.13 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:162.79,164.3 1 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:188.59,190.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:194.75,196.52 1 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:210.2,229.3 4 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:196.52,208.3 2 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:233.110,234.35 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:237.2,237.11 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:234.35,236.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:241.103,257.2 2 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:260.100,263.56 2 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:267.2,300.3 1 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:263.56,265.3 1 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:304.79,317.2 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:320.75,323.2 2 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:326.98,328.40 2 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:331.2,334.42 4 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:337.2,340.91 4 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:328.40,330.3 1 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:334.42,336.3 1 0
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:344.85,348.42 4 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:348.42,350.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:353.109,358.56 5 2
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:358.56,360.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:360.8,363.3 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/resource.go:366.46,368.2 1 4
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:24.42,26.36 2 6
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:32.2,32.15 1 6
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:26.36,27.83 1 9
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:27.83,29.4 1 4
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:35.51,37.36 2 6
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:45.2,45.18 1 6
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:37.36,38.45 1 7
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:41.3,41.87 1 6
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:38.45,39.12 1 1
+github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/reconcile/status.go:41.87,43.4 1 3
diff --git a/shardingsphere-operator/pkg/reconcile/deployment.go b/shardingsphere-operator/pkg/reconcile/deployment.go
new file mode 100644
index 0000000..d40c7a2
--- /dev/null
+++ b/shardingsphere-operator/pkg/reconcile/deployment.go
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package reconcile
+
+import (
+	"fmt"
+	"html/template"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1"
+	v1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func NewDeployment(ssproxy *v1alpha1.ShardingSphereProxy) *v1.Deployment {
+	return ConstructCascadingDeployment(ssproxy)
+}
+func ConstructCascadingDeployment(proxy *v1alpha1.ShardingSphereProxy) *v1.Deployment {
+	if proxy == nil || reflect.DeepEqual(proxy, &v1alpha1.ShardingSphereProxy{}) {
+		return &v1.Deployment{}
+	}
+
+	dp := &v1.Deployment{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      proxy.Name,
+			Namespace: proxy.Namespace,
+			OwnerReferences: []metav1.OwnerReference{
+				*metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()),
+			},
+		},
+		Spec: v1.DeploymentSpec{
+			Strategy: v1.DeploymentStrategy{
+				Type: v1.RecreateDeploymentStrategyType,
+			},
+			Selector: &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"apps": proxy.Name,
+				},
+			},
+			Template: corev1.PodTemplateSpec{
+				ObjectMeta: metav1.ObjectMeta{
+					Labels: map[string]string{
+						"apps": proxy.Name,
+					},
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:            "proxy",
+							Image:           fmt.Sprintf("%s:%s", imageName, proxy.Spec.Version),
+							ImagePullPolicy: corev1.PullIfNotPresent,
+							Ports: []corev1.ContainerPort{
+								{
+									ContainerPort: proxy.Spec.Port,
+								},
+							},
+							Env: []corev1.EnvVar{
+								{
+									Name:  "PORT",
+									Value: strconv.FormatInt(int64(proxy.Spec.Port), 10),
+								},
+							},
+							VolumeMounts: []corev1.VolumeMount{
+								{
+									Name:      "config",
+									MountPath: "/opt/shardingsphere-proxy/conf",
+								},
+							},
+						},
+					},
+					Volumes: []corev1.Volume{
+						{
+							Name: "config",
+							VolumeSource: corev1.VolumeSource{
+								ConfigMap: &corev1.ConfigMapVolumeSource{
+									LocalObjectReference: corev1.LocalObjectReference{
+										Name: proxy.Spec.ProxyConfigName,
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	if proxy.Spec.AutomaticScaling == nil {
+		dp.Spec.Replicas = &proxy.Spec.Replicas
+	}
+	if proxy.Spec.Resources != nil {
+		dp.Spec.Template.Spec.Containers[0].Resources = *proxy.Spec.Resources
+	}
+	if proxy.Spec.LivenessProbe != nil {
+		dp.Spec.Template.Spec.Containers[0].LivenessProbe = proxy.Spec.LivenessProbe
+	}
+	if proxy.Spec.ReadinessProbe != nil {
+		dp.Spec.Template.Spec.Containers[0].ReadinessProbe = proxy.Spec.ReadinessProbe
+	}
+	if proxy.Spec.StartupProbe != nil {
+		dp.Spec.Template.Spec.Containers[0].StartupProbe = proxy.Spec.StartupProbe
+	}
+	if len(proxy.Spec.ImagePullSecrets) > 0 {
+		dp.Spec.Template.Spec.ImagePullSecrets = proxy.Spec.ImagePullSecrets
+	}
+	return processOptionalParameter(proxy, dp)
+}
+
+func processOptionalParameter(proxy *v1alpha1.ShardingSphereProxy, dp *v1.Deployment) *v1.Deployment {
+	if proxy.Spec.MySQLDriver != nil {
+		addInitContainer(dp, proxy.Spec.MySQLDriver)
+	}
+	return dp
+}
+
+func addInitContainer(dp *v1.Deployment, mysql *v1alpha1.MySQLDriver) {
+
+	if len(dp.Spec.Template.Spec.InitContainers) == 0 {
+		dp.Spec.Template.Spec.Containers[0].VolumeMounts = append(dp.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
+			Name:      "mysql-connect-jar",
+			MountPath: "/opt/shardingsphere-proxy/ext-lib",
+		})
+
+		dp.Spec.Template.Spec.Volumes = append(dp.Spec.Template.Spec.Volumes, corev1.Volume{
+			Name: "mysql-connect-jar",
+			VolumeSource: corev1.VolumeSource{
+				EmptyDir: &corev1.EmptyDirVolumeSource{},
+			},
+		})
+	}
+
+	scriptStr := strings.Builder{}
+	t1, _ := template.New("shell").Parse(`wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/{{ .Version }}/mysql-connector-java-{{ .Version }}.jar;
+wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/{{ .Version }}/mysql-connector-java-{{ .Version }}.jar.md5;
+if [ $(md5sum /mysql-connector-java-{{ .Version }}.jar | cut -d ' ' -f1) = $(cat /mysql-connector-java-{{ .Version }}.jar.md5) ];
+then echo success;
+else echo failed;exit 1;fi;mv /mysql-connector-java-{{ .Version }}.jar /opt/shardingsphere-proxy/ext-lib`)
+	_ = t1.Execute(&scriptStr, mysql)
+	dp.Spec.Template.Spec.InitContainers = []corev1.Container{
+		{
+			Name:    "download-mysql-connect",
+			Image:   "busybox:1.35.0",
+			Command: []string{"/bin/sh", "-c", scriptStr.String()},
+			VolumeMounts: []corev1.VolumeMount{
+				{
+					Name:      "mysql-connect-jar",
+					MountPath: "/opt/shardingsphere-proxy/ext-lib",
+				},
+			},
+		},
+	}
+
+}
+
+// UpdateDeployment FIXME:merge UpdateDeployment and ConstructCascadingDeployment
+func UpdateDeployment(proxy *v1alpha1.ShardingSphereProxy, act *v1.Deployment) *v1.Deployment {
+	if proxy.Spec.AutomaticScaling == nil || !proxy.Spec.AutomaticScaling.Enable {
+		act.Spec.Replicas = &proxy.Spec.Replicas
+	}
+
+	act.Spec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s:%s", imageName, proxy.Spec.Version)
+	act.Spec.Template.Spec.Containers[0].Env[0].Value = strconv.FormatInt(int64(proxy.Spec.Port), 10)
+	act.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort = proxy.Spec.Port
+	act.Spec.Template.Spec.Containers[0].Resources = *proxy.Spec.Resources
+	act.Spec.Template.Spec.Containers[0].LivenessProbe = proxy.Spec.LivenessProbe
+	act.Spec.Template.Spec.Containers[0].ReadinessProbe = proxy.Spec.ReadinessProbe
+	act.Spec.Template.Spec.Containers[0].StartupProbe = proxy.Spec.StartupProbe
+
+	act.Spec.Template.Spec.Volumes[0].ConfigMap.Name = proxy.Spec.ProxyConfigName
+
+	if proxy.Spec.MySQLDriver.Version != "" {
+		addInitContainer(act, proxy.Spec.MySQLDriver)
+	}
+
+	exp := act.DeepCopy()
+	return exp
+}
diff --git a/shardingsphere-operator/pkg/reconcile/hpa.go b/shardingsphere-operator/pkg/reconcile/hpa.go
new file mode 100644
index 0000000..8428f7a
--- /dev/null
+++ b/shardingsphere-operator/pkg/reconcile/hpa.go
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package reconcile
+
+import (
+	"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1"
+	appsv1 "k8s.io/api/apps/v1"
+	autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func NewHPA(ssproxy *v1alpha1.ShardingSphereProxy) *autoscalingv2beta2.HorizontalPodAutoscaler {
+	return ConstructHPA(ssproxy)
+}
+
+// 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,
+			Namespace: proxy.Namespace,
+			OwnerReferences: []metav1.OwnerReference{
+				*metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()),
+			},
+		},
+		Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
+			ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
+				Kind:       "Deployment",
+				Name:       proxy.Name,
+				APIVersion: appsv1.SchemeGroupVersion.String(),
+			},
+			MinReplicas: &proxy.Spec.AutomaticScaling.MinInstance,
+			MaxReplicas: proxy.Spec.AutomaticScaling.MaxInstance,
+			Metrics:     metrics,
+			Behavior: &autoscalingv2beta2.HorizontalPodAutoscalerBehavior{
+				ScaleUp: &autoscalingv2beta2.HPAScalingRules{
+					StabilizationWindowSeconds: &proxy.Spec.AutomaticScaling.ScaleUpWindows,
+				},
+				ScaleDown: &autoscalingv2beta2.HPAScalingRules{
+					StabilizationWindowSeconds: &proxy.Spec.AutomaticScaling.ScaleDownWindows,
+					Policies: []autoscalingv2beta2.HPAScalingPolicy{
+						{
+							Type:          autoscalingv2beta2.PodsScalingPolicy,
+							Value:         1,
+							PeriodSeconds: 30,
+						},
+					},
+				},
+			},
+		},
+	}
+
+}
+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,
+				},
+			},
+		},
+	}
+}
+
+func UpdateHPA(proxy *v1alpha1.ShardingSphereProxy, act *autoscalingv2beta2.HorizontalPodAutoscaler) *autoscalingv2beta2.HorizontalPodAutoscaler {
+	act.Spec.Behavior.ScaleDown.StabilizationWindowSeconds = &proxy.Spec.AutomaticScaling.ScaleDownWindows
+	act.Spec.Behavior.ScaleUp.StabilizationWindowSeconds = &proxy.Spec.AutomaticScaling.ScaleUpWindows
+	act.Spec.MaxReplicas = proxy.Spec.AutomaticScaling.MaxInstance
+	act.Spec.MinReplicas = &proxy.Spec.AutomaticScaling.MinInstance
+	if len(proxy.Spec.AutomaticScaling.CustomMetrics) > 0 {
+		act.Spec.Metrics = proxy.Spec.AutomaticScaling.CustomMetrics
+	} else {
+		// We need to reconstruct the default hpa metric when the user deletes the custom metric.
+		act.Spec.Metrics = ConstructDefaultHPAMetric(&proxy.Spec.AutomaticScaling.Target)
+	}
+
+	exp := act.DeepCopy()
+	return exp
+}
diff --git a/shardingsphere-operator/pkg/reconcile/reconcile_test.go b/shardingsphere-operator/pkg/reconcile/reconcile_test.go
index b415292..aed6768 100644
--- a/shardingsphere-operator/pkg/reconcile/reconcile_test.go
+++ b/shardingsphere-operator/pkg/reconcile/reconcile_test.go
@@ -528,86 +528,86 @@ func Test_ConstructCascadingService(t *testing.T) {
 }
 
 func Test_addInitContaienr(t *testing.T) {
-    cases := []struct{
-        deploy *appsv1.Deployment
-        mysql *v1alpha1.MySQLDriver
-        message string
-    }{
-        {
-            deploy: &appsv1.Deployment{
-                Spec: appsv1.DeploymentSpec{
-                    Template: v1.PodTemplateSpec{
-                        Spec: v1.PodSpec{
-                            InitContainers: []v1.Container{},
-                            Containers: []v1.Container{
-                                {
-                                    VolumeMounts: []v1.VolumeMount{},
-                                },
-                            },
-                            Volumes: []v1.Volume{},
-                        },
-                    },
-                },
-            },
-            mysql: &v1alpha1.MySQLDriver{
-                Version: "5.1.47",
-            },
-            message: "Add InitContainer for MySQL Driver",
-        },
-    }
+	cases := []struct {
+		deploy  *appsv1.Deployment
+		mysql   *v1alpha1.MySQLDriver
+		message string
+	}{
+		{
+			deploy: &appsv1.Deployment{
+				Spec: appsv1.DeploymentSpec{
+					Template: v1.PodTemplateSpec{
+						Spec: v1.PodSpec{
+							InitContainers: []v1.Container{},
+							Containers: []v1.Container{
+								{
+									VolumeMounts: []v1.VolumeMount{},
+								},
+							},
+							Volumes: []v1.Volume{},
+						},
+					},
+				},
+			},
+			mysql: &v1alpha1.MySQLDriver{
+				Version: "5.1.47",
+			},
+			message: "Add InitContainer for MySQL Driver",
+		},
+	}
 
-    for _, c := range cases {
-        addInitContainer(c.deploy, c.mysql)
-        assert.Equal(t, c.deploy.Spec.Template.Spec.InitContainers[0].Name, "download-mysql-connect", c.message)
-    }
+	for _, c := range cases {
+		addInitContainer(c.deploy, c.mysql)
+		assert.Equal(t, c.deploy.Spec.Template.Spec.InitContainers[0].Name, "download-mysql-connect", c.message)
+	}
 }
 
 func Test_processOptionalParameter(t *testing.T) {
-    /*
-    cases := []struct{
+	/*
+	   cases := []struct{
 
-    }{
-        {
+	   }{
+	       {
 
-        },
-    }
+	       },
+	   }
 
-    for _, c := range cases {
+	   for _, c := range cases {
 
-    }
-    */
+	   }
+	*/
 }
 
 func Test_ConstructCascadingConfigmap(t *testing.T) {
-    /*
-    cases := []struct{
+	/*
+	   cases := []struct{
 
-    }{
-        {
+	   }{
+	       {
 
-        },
-    }
+	       },
+	   }
 
-    for _, c := range cases {
+	   for _, c := range cases {
 
-    }
-    */
+	   }
+	*/
 }
 
 func Test_ConstructHPA(t *testing.T) {
-    /*
-    cases := []struct{
+	/*
+	   cases := []struct{
 
-    }{
-        {
+	   }{
+	       {
 
-        },
-    }
+	       },
+	   }
 
-    for _, c := range cases {
+	   for _, c := range cases {
 
-    }
-    */
+	   }
+	*/
 }
 
 func Test_ToYAML(t *testing.T) {
diff --git a/shardingsphere-operator/pkg/reconcile/resource.go b/shardingsphere-operator/pkg/reconcile/resource.go
index a1e8e49..e90f0d8 100644
--- a/shardingsphere-operator/pkg/reconcile/resource.go
+++ b/shardingsphere-operator/pkg/reconcile/resource.go
@@ -18,16 +18,8 @@
 package reconcile
 
 import (
-	"fmt"
-	"html/template"
-	"reflect"
-	"strconv"
-	"strings"
-
 	"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1"
 	"gopkg.in/yaml.v2"
-	appsv1 "k8s.io/api/apps/v1"
-	autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -35,7 +27,7 @@ import (
 
 const imageName = "apache/shardingsphere-proxy"
 
-var logback = `<?xml version="1.0"?>
+const logback = `<?xml version="1.0"?>
 <configuration>
     <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
@@ -68,175 +60,6 @@ var logback = `<?xml version="1.0"?>
 </configuration> 
 `
 
-func ConstructCascadingDeployment(proxy *v1alpha1.ShardingSphereProxy) *appsv1.Deployment {
-	if proxy == nil || reflect.DeepEqual(proxy, &v1alpha1.ShardingSphereProxy{}) {
-		return &appsv1.Deployment{}
-	}
-
-	dp := &appsv1.Deployment{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      proxy.Name,
-			Namespace: proxy.Namespace,
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()),
-			},
-		},
-		Spec: appsv1.DeploymentSpec{
-			Strategy: appsv1.DeploymentStrategy{
-				Type: appsv1.RecreateDeploymentStrategyType,
-			},
-			Selector: &metav1.LabelSelector{
-				MatchLabels: map[string]string{
-					"apps": proxy.Name,
-				},
-			},
-			Template: v1.PodTemplateSpec{
-				ObjectMeta: metav1.ObjectMeta{
-					Labels: map[string]string{
-						"apps": proxy.Name,
-					},
-				},
-				Spec: v1.PodSpec{
-					Containers: []v1.Container{
-						{
-							Name:            "proxy",
-							Image:           fmt.Sprintf("%s:%s", imageName, proxy.Spec.Version),
-							ImagePullPolicy: v1.PullIfNotPresent,
-							Ports: []v1.ContainerPort{
-								{
-									ContainerPort: proxy.Spec.Port,
-								},
-							},
-							Env: []v1.EnvVar{
-								{
-									Name:  "PORT",
-									Value: strconv.FormatInt(int64(proxy.Spec.Port), 10),
-								},
-							},
-							VolumeMounts: []v1.VolumeMount{
-								{
-									Name:      "config",
-									MountPath: "/opt/shardingsphere-proxy/conf",
-								},
-							},
-						},
-					},
-					Volumes: []v1.Volume{
-						{
-							Name: "config",
-							VolumeSource: v1.VolumeSource{
-								ConfigMap: &v1.ConfigMapVolumeSource{
-									LocalObjectReference: v1.LocalObjectReference{
-										Name: proxy.Spec.ProxyConfigName,
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-	}
-	if proxy.Spec.AutomaticScaling == nil {
-		dp.Spec.Replicas = &proxy.Spec.Replicas
-	}
-	if proxy.Spec.Resources != nil {
-		dp.Spec.Template.Spec.Containers[0].Resources = *proxy.Spec.Resources
-	}
-	if proxy.Spec.LivenessProbe != nil {
-		dp.Spec.Template.Spec.Containers[0].LivenessProbe = proxy.Spec.LivenessProbe
-	}
-	if proxy.Spec.ReadinessProbe != nil {
-		dp.Spec.Template.Spec.Containers[0].ReadinessProbe = proxy.Spec.ReadinessProbe
-	}
-	if proxy.Spec.StartupProbe != nil {
-		dp.Spec.Template.Spec.Containers[0].StartupProbe = proxy.Spec.StartupProbe
-	}
-	if len(proxy.Spec.ImagePullSecrets) > 0 {
-		dp.Spec.Template.Spec.ImagePullSecrets = proxy.Spec.ImagePullSecrets
-	}
-	return processOptionalParameter(proxy, dp)
-}
-
-func ConstructCascadingService(proxy *v1alpha1.ShardingSphereProxy) *v1.Service {
-	if proxy == nil || reflect.DeepEqual(proxy, &v1alpha1.ShardingSphereProxy{}) {
-		return &v1.Service{}
-	}
-
-	svc := v1.Service{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      proxy.Name,
-			Namespace: proxy.Namespace,
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()),
-			},
-		},
-		Spec: v1.ServiceSpec{
-			Selector: map[string]string{
-				"apps": proxy.Name,
-			},
-			Type: proxy.Spec.ServiceType.Type,
-			Ports: []v1.ServicePort{
-				{
-					Name:       "proxy-port",
-					TargetPort: fromInt32(proxy.Spec.Port),
-					Port:       proxy.Spec.Port,
-				},
-			},
-		},
-	}
-	if proxy.Spec.ServiceType.Type == v1.ServiceTypeNodePort {
-		svc.Spec.Ports[0].NodePort = proxy.Spec.ServiceType.NodePort
-	}
-	return &svc
-}
-
-func addInitContainer(dp *appsv1.Deployment, mysql *v1alpha1.MySQLDriver) {
-
-	if len(dp.Spec.Template.Spec.InitContainers) == 0 {
-		dp.Spec.Template.Spec.Containers[0].VolumeMounts = append(dp.Spec.Template.Spec.Containers[0].VolumeMounts, v1.VolumeMount{
-			Name:      "mysql-connect-jar",
-			MountPath: "/opt/shardingsphere-proxy/ext-lib",
-		})
-
-		dp.Spec.Template.Spec.Volumes = append(dp.Spec.Template.Spec.Volumes, v1.Volume{
-			Name: "mysql-connect-jar",
-			VolumeSource: v1.VolumeSource{
-				EmptyDir: &v1.EmptyDirVolumeSource{},
-			},
-		})
-	}
-
-	scriptStr := strings.Builder{}
-	t1, _ := template.New("shell").Parse(`wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/{{ .Version }}/mysql-connector-java-{{ .Version }}.jar;
-wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/{{ .Version }}/mysql-connector-java-{{ .Version }}.jar.md5;
-if [ $(md5sum /mysql-connector-java-{{ .Version }}.jar | cut -d ' ' -f1) = $(cat /mysql-connector-java-{{ .Version }}.jar.md5) ];
-then echo success;
-else echo failed;exit 1;fi;mv /mysql-connector-java-{{ .Version }}.jar /opt/shardingsphere-proxy/ext-lib`)
-	_ = t1.Execute(&scriptStr, mysql)
-	dp.Spec.Template.Spec.InitContainers = []v1.Container{
-		{
-			Name:    "download-mysql-connect",
-			Image:   "busybox:1.35.0",
-			Command: []string{"/bin/sh", "-c", scriptStr.String()},
-			VolumeMounts: []v1.VolumeMount{
-				{
-					Name:      "mysql-connect-jar",
-					MountPath: "/opt/shardingsphere-proxy/ext-lib",
-				},
-			},
-		},
-	}
-
-}
-
-func processOptionalParameter(proxy *v1alpha1.ShardingSphereProxy, dp *appsv1.Deployment) *appsv1.Deployment {
-	if proxy.Spec.MySQLDriver != nil {
-		addInitContainer(dp, proxy.Spec.MySQLDriver)
-	}
-	return dp
-}
-
 // ConstructCascadingConfigmap Construct spec resources to Configmap
 func ConstructCascadingConfigmap(proxyConfig *v1alpha1.ShardingSphereProxyServerConfig) *v1.ConfigMap {
 	y := toYaml(proxyConfig)
@@ -253,67 +76,6 @@ func ConstructCascadingConfigmap(proxyConfig *v1alpha1.ShardingSphereProxyServer
 			"logback.xml": logback,
 		},
 	}
-
-}
-
-// 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,
-			Namespace: proxy.Namespace,
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()),
-			},
-		},
-		Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
-			ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
-				Kind:       "Deployment",
-				Name:       proxy.Name,
-				APIVersion: appsv1.SchemeGroupVersion.String(),
-			},
-			MinReplicas: &proxy.Spec.AutomaticScaling.MinInstance,
-			MaxReplicas: proxy.Spec.AutomaticScaling.MaxInstance,
-			Metrics:     metrics,
-			Behavior: &autoscalingv2beta2.HorizontalPodAutoscalerBehavior{
-				ScaleUp: &autoscalingv2beta2.HPAScalingRules{
-					StabilizationWindowSeconds: &proxy.Spec.AutomaticScaling.ScaleUpWindows,
-				},
-				ScaleDown: &autoscalingv2beta2.HPAScalingRules{
-					StabilizationWindowSeconds: &proxy.Spec.AutomaticScaling.ScaleDownWindows,
-					Policies: []autoscalingv2beta2.HPAScalingPolicy{
-						{
-							Type:          autoscalingv2beta2.PodsScalingPolicy,
-							Value:         1,
-							PeriodSeconds: 30,
-						},
-					},
-				},
-			},
-		},
-	}
-
-}
-
-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
@@ -322,47 +84,6 @@ func toYaml(proxyConfig *v1alpha1.ShardingSphereProxyServerConfig) string {
 	return string(y)
 }
 
-// UpdateDeployment FIXME:merge UpdateDeployment and ConstructCascadingDeployment
-func UpdateDeployment(proxy *v1alpha1.ShardingSphereProxy, runtimeDeployment *appsv1.Deployment) {
-	runtimeDeployment.Spec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s:%s", imageName, proxy.Spec.Version)
-	if proxy.Spec.AutomaticScaling == nil {
-		runtimeDeployment.Spec.Replicas = &proxy.Spec.Replicas
-	}
-	runtimeDeployment.Spec.Template.Spec.Volumes[0].ConfigMap.Name = proxy.Spec.ProxyConfigName
-	runtimeDeployment.Spec.Template.Spec.Containers[0].Env[0].Value = strconv.FormatInt(int64(proxy.Spec.Port), 10)
-	runtimeDeployment.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort = proxy.Spec.Port
-	if proxy.Spec.MySQLDriver.Version != "" {
-		addInitContainer(runtimeDeployment, proxy.Spec.MySQLDriver)
-	}
-	runtimeDeployment.Spec.Template.Spec.Containers[0].Resources = *proxy.Spec.Resources
-	runtimeDeployment.Spec.Template.Spec.Containers[0].LivenessProbe = proxy.Spec.LivenessProbe
-	runtimeDeployment.Spec.Template.Spec.Containers[0].ReadinessProbe = proxy.Spec.ReadinessProbe
-	runtimeDeployment.Spec.Template.Spec.Containers[0].StartupProbe = proxy.Spec.StartupProbe
-
-}
-
-func UpdateService(proxy *v1alpha1.ShardingSphereProxy, runtimeService *v1.Service) {
-	runtimeService.Spec.Type = proxy.Spec.ServiceType.Type
-	runtimeService.Spec.Ports[0].Port = proxy.Spec.Port
-	runtimeService.Spec.Ports[0].TargetPort = fromInt32(proxy.Spec.Port)
-	if proxy.Spec.ServiceType.NodePort != 0 {
-		runtimeService.Spec.Ports[0].NodePort = proxy.Spec.ServiceType.NodePort
-	}
-}
-
-func UpdateHPA(proxy *v1alpha1.ShardingSphereProxy, runtimeHPA *autoscalingv2beta2.HorizontalPodAutoscaler) {
-	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 {
 	return intstr.IntOrString{Type: intstr.Int, IntVal: val}
 }
diff --git a/shardingsphere-operator/pkg/reconcile/service.go b/shardingsphere-operator/pkg/reconcile/service.go
new file mode 100644
index 0000000..3fdf693
--- /dev/null
+++ b/shardingsphere-operator/pkg/reconcile/service.go
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package reconcile
+
+import (
+	"reflect"
+
+	"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func NewService(ssproxy *v1alpha1.ShardingSphereProxy) *v1.Service {
+	return ConstructCascadingService(ssproxy)
+}
+
+func ConstructCascadingService(proxy *v1alpha1.ShardingSphereProxy) *v1.Service {
+	if proxy == nil || reflect.DeepEqual(proxy, &v1alpha1.ShardingSphereProxy{}) {
+		return &v1.Service{}
+	}
+
+	svc := v1.Service{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      proxy.Name,
+			Namespace: proxy.Namespace,
+			OwnerReferences: []metav1.OwnerReference{
+				*metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()),
+			},
+		},
+		Spec: v1.ServiceSpec{
+			Selector: map[string]string{
+				"apps": proxy.Name,
+			},
+			Type: proxy.Spec.ServiceType.Type,
+			Ports: []v1.ServicePort{
+				{
+					Name:       "proxy-port",
+					TargetPort: fromInt32(proxy.Spec.Port),
+					Port:       proxy.Spec.Port,
+				},
+			},
+		},
+	}
+	if proxy.Spec.ServiceType.Type == v1.ServiceTypeNodePort {
+		svc.Spec.Ports[0].NodePort = proxy.Spec.ServiceType.NodePort
+	}
+	return &svc
+}
+
+func UpdateService(proxy *v1alpha1.ShardingSphereProxy, runtimeService *v1.Service) {
+	runtimeService.Spec.Type = proxy.Spec.ServiceType.Type
+	runtimeService.Spec.Ports[0].Port = proxy.Spec.Port
+	runtimeService.Spec.Ports[0].TargetPort = fromInt32(proxy.Spec.Port)
+	if proxy.Spec.ServiceType.NodePort != 0 {
+		runtimeService.Spec.Ports[0].NodePort = proxy.Spec.ServiceType.NodePort
+	}
+}