diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..0f04682
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
+# Ignore build and test binaries.
+bin/
+testbin/
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e917e5c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+bin
+testbin/*
+Dockerfile.cross
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Kubernetes Generated files - skip generated files, except for vendored files
+
+!vendor/**/zz_generated.*
+
+# editor and IDE paraphernalia
+.idea
+*.swp
+*.swo
+*~
diff --git a/api/v1alpha1/appservice_types.go b/api/v1alpha1/appservice_types.go
index 793c8d9..8d9ba40 100644
--- a/api/v1alpha1/appservice_types.go
+++ b/api/v1alpha1/appservice_types.go
@@ -31,11 +31,11 @@ type AppServiceSpec struct {
 	// Important: Run "make" to regenerate code after modifying this file
 
 	// Foo is an example field of AppService. Edit appservice_types.go to remove/update
-	Size     *int32               `json:"size"`
-	Image    string               `json:"image"`
-	Resource *Resources           `json:"resource,omitempty"`
-	Envs     []corev1.EnvVar      `json:"envs,omitempty"`
-	Ports    []corev1.ServicePort `json:"ports,omitempty"`
+	Size      *int32               `json:"size"`
+	Image     string               `json:"image"`
+	Resources *Resources           `json:"resource,omitempty"`
+	Envs      []corev1.EnvVar      `json:"envs,omitempty"`
+	Ports     []corev1.ServicePort `json:"ports,omitempty"`
 }
 
 type Resources struct {
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 891cb3b..440ec96 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -93,8 +93,8 @@ func (in *AppServiceSpec) DeepCopyInto(out *AppServiceSpec) {
 		*out = new(int32)
 		**out = **in
 	}
-	if in.Resource != nil {
-		in, out := &in.Resource, &out.Resource
+	if in.Resources != nil {
+		in, out := &in.Resources, &out.Resources
 		*out = new(Resources)
 		(*in).DeepCopyInto(*out)
 	}
diff --git a/config/crd/bases/app.treesir.pub.treesir.pub_appservices.yaml b/config/crd/bases/app.treesir.pub.treesir.pub_appservices.yaml
new file mode 100644
index 0000000..9f31590
--- /dev/null
+++ b/config/crd/bases/app.treesir.pub.treesir.pub_appservices.yaml
@@ -0,0 +1,316 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.11.1
+  creationTimestamp: null
+  name: appservices.app.treesir.pub.treesir.pub
+spec:
+  group: app.treesir.pub.treesir.pub
+  names:
+    kind: AppService
+    listKind: AppServiceList
+    plural: appservices
+    singular: appservice
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: AppService is the Schema for the appservices API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: AppServiceSpec defines the desired state of AppService
+            properties:
+              envs:
+                items:
+                  description: EnvVar represents an environment variable present in
+                    a Container.
+                  properties:
+                    name:
+                      description: Name of the environment variable. Must be a C_IDENTIFIER.
+                      type: string
+                    value:
+                      description: 'Variable references $(VAR_NAME) are expanded using
+                        the previously defined environment variables in the container
+                        and any service environment variables. If a variable cannot
+                        be resolved, the reference in the input string will be unchanged.
+                        Double $$ are reduced to a single $, which allows for escaping
+                        the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the
+                        string literal "$(VAR_NAME)". Escaped references will never
+                        be expanded, regardless of whether the variable exists or
+                        not. Defaults to "".'
+                      type: string
+                    valueFrom:
+                      description: Source for the environment variable's value. Cannot
+                        be used if value is not empty.
+                      properties:
+                        configMapKeyRef:
+                          description: Selects a key of a ConfigMap.
+                          properties:
+                            key:
+                              description: The key to select.
+                              type: string
+                            name:
+                              description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+                                TODO: Add other useful fields. apiVersion, kind, uid?'
+                              type: string
+                            optional:
+                              description: Specify whether the ConfigMap or its key
+                                must be defined
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                          x-kubernetes-map-type: atomic
+                        fieldRef:
+                          description: 'Selects a field of the pod: supports metadata.name,
+                            metadata.namespace, `metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`,
+                            spec.nodeName, spec.serviceAccountName, status.hostIP,
+                            status.podIP, status.podIPs.'
+                          properties:
+                            apiVersion:
+                              description: Version of the schema the FieldPath is
+                                written in terms of, defaults to "v1".
+                              type: string
+                            fieldPath:
+                              description: Path of the field to select in the specified
+                                API version.
+                              type: string
+                          required:
+                          - fieldPath
+                          type: object
+                          x-kubernetes-map-type: atomic
+                        resourceFieldRef:
+                          description: 'Selects a resource of the container: only
+                            resources limits and requests (limits.cpu, limits.memory,
+                            limits.ephemeral-storage, requests.cpu, requests.memory
+                            and requests.ephemeral-storage) are currently supported.'
+                          properties:
+                            containerName:
+                              description: 'Container name: required for volumes,
+                                optional for env vars'
+                              type: string
+                            divisor:
+                              anyOf:
+                              - type: integer
+                              - type: string
+                              description: Specifies the output format of the exposed
+                                resources, defaults to "1"
+                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                              x-kubernetes-int-or-string: true
+                            resource:
+                              description: 'Required: resource to select'
+                              type: string
+                          required:
+                          - resource
+                          type: object
+                          x-kubernetes-map-type: atomic
+                        secretKeyRef:
+                          description: Selects a key of a secret in the pod's namespace
+                          properties:
+                            key:
+                              description: The key of the secret to select from.  Must
+                                be a valid secret key.
+                              type: string
+                            name:
+                              description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+                                TODO: Add other useful fields. apiVersion, kind, uid?'
+                              type: string
+                            optional:
+                              description: Specify whether the Secret or its key must
+                                be defined
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                          x-kubernetes-map-type: atomic
+                      type: object
+                  required:
+                  - name
+                  type: object
+                type: array
+              image:
+                type: string
+              ports:
+                items:
+                  description: ServicePort contains information on service's port.
+                  properties:
+                    appProtocol:
+                      description: The application protocol for this port. This field
+                        follows standard Kubernetes label syntax. Un-prefixed names
+                        are reserved for IANA standard service names (as per RFC-6335
+                        and https://www.iana.org/assignments/service-names). Non-standard
+                        protocols should use prefixed names such as mycompany.com/my-custom-protocol.
+                      type: string
+                    name:
+                      description: The name of this port within the service. This
+                        must be a DNS_LABEL. All ports within a ServiceSpec must have
+                        unique names. When considering the endpoints for a Service,
+                        this must match the 'name' field in the EndpointPort. Optional
+                        if only one ServicePort is defined on this service.
+                      type: string
+                    nodePort:
+                      description: 'The port on each node on which this service is
+                        exposed when type is NodePort or LoadBalancer.  Usually assigned
+                        by the system. If a value is specified, in-range, and not
+                        in use it will be used, otherwise the operation will fail.  If
+                        not specified, a port will be allocated if this Service requires
+                        one.  If this field is specified when creating a Service which
+                        does not need it, creation will fail. This field will be wiped
+                        when updating a Service to no longer need it (e.g. changing
+                        type from NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport'
+                      format: int32
+                      type: integer
+                    port:
+                      description: The port that will be exposed by this service.
+                      format: int32
+                      type: integer
+                    protocol:
+                      default: TCP
+                      description: The IP protocol for this port. Supports "TCP",
+                        "UDP", and "SCTP". Default is TCP.
+                      type: string
+                    targetPort:
+                      anyOf:
+                      - type: integer
+                      - type: string
+                      description: 'Number or name of the port to access on the pods
+                        targeted by the service. Number must be in the range 1 to
+                        65535. Name must be an IANA_SVC_NAME. If this is a string,
+                        it will be looked up as a named port in the target Pod''s
+                        container ports. If this is not specified, the value of the
+                        ''port'' field is used (an identity map). This field is ignored
+                        for services with clusterIP=None, and should be omitted or
+                        set equal to the ''port'' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service'
+                      x-kubernetes-int-or-string: true
+                  required:
+                  - port
+                  type: object
+                type: array
+              resource:
+                properties:
+                  limits:
+                    additionalProperties:
+                      anyOf:
+                      - type: integer
+                      - type: string
+                      pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                      x-kubernetes-int-or-string: true
+                    description: ResourceList is a set of (resource name, quantity)
+                      pairs.
+                    type: object
+                  requests:
+                    additionalProperties:
+                      anyOf:
+                      - type: integer
+                      - type: string
+                      pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                      x-kubernetes-int-or-string: true
+                    description: ResourceList is a set of (resource name, quantity)
+                      pairs.
+                    type: object
+                type: object
+              size:
+                description: Foo is an example field of AppService. Edit appservice_types.go
+                  to remove/update
+                format: int32
+                type: integer
+            required:
+            - image
+            - size
+            type: object
+          status:
+            description: AppServiceStatus defines the observed state of AppService
+            properties:
+              availableReplicas:
+                description: Total number of available pods (ready for at least minReadySeconds)
+                  targeted by this deployment.
+                format: int32
+                type: integer
+              collisionCount:
+                description: Count of hash collisions for the Deployment. The Deployment
+                  controller uses this field as a collision avoidance mechanism when
+                  it needs to create the name for the newest ReplicaSet.
+                format: int32
+                type: integer
+              conditions:
+                description: Represents the latest available observations of a deployment's
+                  current state.
+                items:
+                  description: DeploymentCondition describes the state of a deployment
+                    at a certain point.
+                  properties:
+                    lastTransitionTime:
+                      description: Last time the condition transitioned from one status
+                        to another.
+                      format: date-time
+                      type: string
+                    lastUpdateTime:
+                      description: The last time this condition was updated.
+                      format: date-time
+                      type: string
+                    message:
+                      description: A human readable message indicating details about
+                        the transition.
+                      type: string
+                    reason:
+                      description: The reason for the condition's last transition.
+                      type: string
+                    status:
+                      description: Status of the condition, one of True, False, Unknown.
+                      type: string
+                    type:
+                      description: Type of deployment condition.
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+              observedGeneration:
+                description: The generation observed by the deployment controller.
+                format: int64
+                type: integer
+              readyReplicas:
+                description: readyReplicas is the number of pods targeted by this
+                  Deployment with a Ready Condition.
+                format: int32
+                type: integer
+              replicas:
+                description: Total number of non-terminated pods targeted by this
+                  deployment (their labels match the selector).
+                format: int32
+                type: integer
+              unavailableReplicas:
+                description: Total number of unavailable pods targeted by this deployment.
+                  This is the total number of pods that are still required for the
+                  deployment to have 100% available capacity. They may either be pods
+                  that are running but not yet available or pods that still have not
+                  been created.
+                format: int32
+                type: integer
+              updatedReplicas:
+                description: Total number of non-terminated pods targeted by this
+                  deployment that have the desired template spec.
+                format: int32
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
new file mode 100644
index 0000000..6954d02
--- /dev/null
+++ b/config/rbac/role.yaml
@@ -0,0 +1,33 @@
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: manager-role
+rules:
+- apiGroups:
+  - app.treesir.pub.treesir.pub
+  resources:
+  - appservices
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - app.treesir.pub.treesir.pub
+  resources:
+  - appservices/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - app.treesir.pub.treesir.pub
+  resources:
+  - appservices/status
+  verbs:
+  - get
+  - patch
+  - update
diff --git a/controllers/appservice_controller.go b/controllers/appservice_controller.go
index dfff4ee..77600d4 100644
--- a/controllers/appservice_controller.go
+++ b/controllers/appservice_controller.go
@@ -19,7 +19,7 @@ package controllers
 import (
 	"context"
 	"encoding/json"
-	appv1alpha1 "git.treesir.pub/cdryzun/operator-demo/api/v1alpha1"
+	"fmt"
 	"reflect"
 
 	appsv1 "k8s.io/api/apps/v1"
@@ -27,11 +27,12 @@ import (
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/runtime/schema"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+
+	apptreesirpubv1alpha1 "git.treesir.pub/cdryzun/operator-demo/api/v1alpha1"
 )
 
 // AppServiceReconciler reconciles a AppService object
@@ -58,7 +59,7 @@ func (r *AppServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	reqLogger.Info("Reconciling AppService")
 
 	// Fetch the AppService instance
-	instance := &appv1alpha1.AppService{}
+	instance := &apptreesirpubv1alpha1.AppService{}
 	err := r.Get(context.TODO(), req.NamespacedName, instance)
 	if err != nil {
 		if errors.IsNotFound(err) {
@@ -81,6 +82,7 @@ func (r *AppServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	// 如果不需要更新,则正常返回
 
 	deploy := &appsv1.Deployment{}
+	fmt.Println(deploy)
 	if err := r.Get(context.TODO(), req.NamespacedName, deploy); err != nil && errors.IsNotFound(err) {
 		// 创建关联资源
 		// 1. 创建 Deploy
@@ -107,7 +109,7 @@ func (r *AppServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 		return ctrl.Result{}, nil
 	}
 
-	oldspec := appv1alpha1.AppServiceSpec{}
+	oldspec := apptreesirpubv1alpha1.AppServiceSpec{}
 	if err := json.Unmarshal([]byte(instance.Annotations["spec"]), &oldspec); err != nil {
 		return ctrl.Result{}, err
 	}
@@ -147,86 +149,71 @@ func (r *AppServiceReconciler) SetupWithManager(mgr ctrl.Manager) error {
 		Complete(r)
 }
 
-func NewDeploy(app *appv1alpha1.AppService) *appsv1.Deployment {
-	labels := map[string]string{"app": app.Name}
-	selector := &metav1.LabelSelector{MatchLabels: labels}
+func NewDeploy(instance *apptreesirpubv1alpha1.AppService) *appsv1.Deployment {
+	labels := map[string]string{
+		"app": instance.Name,
+	}
 	return &appsv1.Deployment{
-		TypeMeta: metav1.TypeMeta{
-			APIVersion: "apps/v1",
-			Kind:       "Deployment",
-		},
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      app.Name,
-			Namespace: app.Namespace,
-
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(app, schema.GroupVersionKind{
-					Group:   appsv1.SchemeGroupVersion.Group,
-					Version: appsv1.SchemeGroupVersion.Version,
-					Kind:    "AppService",
-				}),
-			},
+		ObjectMeta: ctrl.ObjectMeta{
+			Name:      instance.Name,
+			Namespace: instance.Namespace,
+			Labels:    labels,
 		},
 		Spec: appsv1.DeploymentSpec{
-			Replicas: app.Spec.Size,
+			Replicas: instance.Spec.Size,
+			Selector: &metav1.LabelSelector{
+				MatchLabels: labels,
+			},
 			Template: corev1.PodTemplateSpec{
-				ObjectMeta: metav1.ObjectMeta{
+				ObjectMeta: ctrl.ObjectMeta{
 					Labels: labels,
 				},
 				Spec: corev1.PodSpec{
-					Containers: newContainers(app),
+					Containers: newContainers(instance),
 				},
 			},
-			Selector: selector,
 		},
 	}
 }
 
-func newContainers(app *appv1alpha1.AppService) []corev1.Container {
+func NewService(instance *apptreesirpubv1alpha1.AppService) *corev1.Service {
+	labels := map[string]string{
+		"app": instance.Name,
+	}
+	return &corev1.Service{
+		ObjectMeta: ctrl.ObjectMeta{
+			Name:      instance.Name,
+			Namespace: instance.Namespace,
+			Labels:    labels,
+		},
+		Spec: corev1.ServiceSpec{
+			Type:  corev1.ServiceTypeNodePort,
+			Ports: instance.Spec.Ports,
+			Selector: map[string]string{
+				"app": instance.Name,
+			},
+		},
+	}
+}
+
+func newContainers(instance *apptreesirpubv1alpha1.AppService) []corev1.Container {
 	var containerPorts []corev1.ContainerPort
-	for _, svcPort := range app.Spec.Ports {
+	for _, svcPort := range instance.Spec.Ports {
 		cport := corev1.ContainerPort{}
 		cport.ContainerPort = svcPort.TargetPort.IntVal
 		containerPorts = append(containerPorts, cport)
 	}
 	return []corev1.Container{
 		{
-			Name:  app.Name,
-			Image: app.Spec.Image,
+			Name:  instance.Name,
+			Image: instance.Spec.Image,
 			Resources: corev1.ResourceRequirements{
-				Requests: app.Spec.Resources.Requests,
-				Limits:   app.Spec.Resources.Limits,
+				Requests: instance.Spec.Resources.Requests,
+				Limits:   instance.Spec.Resources.Limits,
 			},
 			Ports:           containerPorts,
 			ImagePullPolicy: corev1.PullIfNotPresent,
-			Env:             app.Spec.Envs,
-		},
-	}
-}
-
-func NewService(app *appv1alpha1.AppService) *corev1.Service {
-	return &corev1.Service{
-		TypeMeta: metav1.TypeMeta{
-			Kind:       "Service",
-			APIVersion: "v1",
-		},
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      app.Name,
-			Namespace: app.Namespace,
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(app, schema.GroupVersionKind{
-					Group:   appsv1.SchemeGroupVersion.Group,
-					Version: appsv1.SchemeGroupVersion.Version,
-					Kind:    "AppService",
-				}),
-			},
-		},
-		Spec: corev1.ServiceSpec{
-			Type:  corev1.ServiceTypeNodePort,
-			Ports: app.Spec.Ports,
-			Selector: map[string]string{
-				"app": app.Name,
-			},
+			Env:             instance.Spec.Envs,
 		},
 	}
 }