update
This commit is contained in:
parent
d644296a54
commit
28149b86a6
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@ -0,0 +1,4 @@
|
||||
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
|
||||
# Ignore build and test binaries.
|
||||
bin/
|
||||
testbin/
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@ -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
|
||||
*~
|
@ -33,7 +33,7 @@ type AppServiceSpec struct {
|
||||
// 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"`
|
||||
Resources *Resources `json:"resource,omitempty"`
|
||||
Envs []corev1.EnvVar `json:"envs,omitempty"`
|
||||
Ports []corev1.ServicePort `json:"ports,omitempty"`
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
316
config/crd/bases/app.treesir.pub.treesir.pub_appservices.yaml
Normal file
316
config/crd/bases/app.treesir.pub.treesir.pub_appservices.yaml
Normal file
@ -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: {}
|
33
config/rbac/role.yaml
Normal file
33
config/rbac/role.yaml
Normal file
@ -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
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user