l-107 重构调用

master
dongming 2 years ago
parent 3c6a32c04b
commit 3067f3380f

@ -30,7 +30,6 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o ma
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
COPY controllers/ controllers/
USER 65532:65532

@ -36,7 +36,7 @@ type MsbDeploymentSpec struct {
Replicas int32 `json:"replicas,omitempty"`
// StartCmd 存储启动命令
// +optional
StartCmd string `json:"startCmd,omitempty"`
StartCmd []string `json:"startCmd,omitempty"`
// Args 存储启动命令参数
// +optional
Args []string `json:"args,omitempty"`

@ -1,84 +1,67 @@
package controllers
import (
"bytes"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"text/template"
networkv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/util/yaml"
"strings"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
networkv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/intstr"
myAppsv1 "mashibing.com/pkg/mashibing-deployment/api/v1"
)
func parseTemplate(md *myAppsv1.MsbDeployment, templateName string) ([]byte, error) {
tmpl, err := template.ParseFiles(fmt.Sprintf("controllers/templates/%s", templateName))
if err != nil {
return nil, err
}
b := &bytes.Buffer{}
if err := tmpl.Execute(b, md); err != nil {
return nil, err
}
return b.Bytes(), nil
}
var IngressClassName = "nginx"
var PathTypePrefix = networkv1.PathTypePrefix
func NewDeployment(md *myAppsv1.MsbDeployment) (*appsv1.Deployment, error) {
content, err := parseTemplate(md, "deployment.yaml")
if err != nil {
return nil, err
func NewDeployment(md *myAppsv1.MsbDeployment) appsv1.Deployment {
// 1. 创建基本的deployment
// 1.1 创建只含有metadata信息的对象
deploy := newBaseDeployment(md)
// 2. 创建附加的对象
// 2.1 在基本的deployment中添加其他的对象
deploy.Spec.Replicas = &md.Spec.Replicas
deploy.Spec.Selector = &metav1.LabelSelector{MatchLabels: newLabels(md)}
deploy.Spec.Template.ObjectMeta = metav1.ObjectMeta{Labels: newLabels(md)}
deploy.Spec.Template.Spec.Containers = []corev1.Container{
newBaseContainer(md),
}
deploy := new(appsv1.Deployment)
if err := yaml.Unmarshal(content, deploy); err != nil {
return nil, err
}
return deploy, nil
}
func NewIngress(md *myAppsv1.MsbDeployment) (*networkv1.Ingress, error) {
var (
content []byte
err error
)
if md.Spec.Expose.Tls {
// 添加 tls 的支持
content, err = parseTemplate(md, "ingress-with-tls.yaml")
} else {
content, err = parseTemplate(md, "ingress.yaml")
}
if err != nil {
return nil, err
}
ig := new(networkv1.Ingress)
if err := yaml.Unmarshal(content, ig); err != nil {
return nil, err
}
return ig, nil
return deploy
}
func NewService(md *myAppsv1.MsbDeployment) (*corev1.Service, error) {
content, err := parseTemplate(md, "service.yaml")
if err != nil {
return nil, err
func NewIngress(md *myAppsv1.MsbDeployment) networkv1.Ingress {
ig := newBaseIngress(md)
ig.Spec.IngressClassName = &IngressClassName
ig.Spec.Rules = []networkv1.IngressRule{
newIngressRule(md),
}
svc := new(corev1.Service)
if err := yaml.Unmarshal(content, svc); err != nil {
return nil, err
if md.Spec.Expose.Tls {
ig.Spec.TLS = []networkv1.IngressTLS{
newIngressTLS(md),
}
}
return svc, nil
return ig
}
func NewServiceNP(md *myAppsv1.MsbDeployment) (*corev1.Service, error) {
content, err := parseTemplate(md, "service-np.yaml")
if err != nil {
return nil, err
}
svc := new(corev1.Service)
if err := yaml.Unmarshal(content, svc); err != nil {
return nil, err
func NewService(md *myAppsv1.MsbDeployment) corev1.Service {
svc := newBaseService(md)
svc.Spec.Selector = newLabels(md)
servicePort := newServicePort(md)
switch strings.ToLower(md.Spec.Expose.Mode) {
case myAppsv1.ModeIngress:
svc.Spec.Ports = []corev1.ServicePort{servicePort}
case myAppsv1.ModeNodePort:
svc.Spec.Type = corev1.ServiceTypeNodePort
servicePort.NodePort = md.Spec.Expose.NodePort
svc.Spec.Ports = []corev1.ServicePort{servicePort}
default:
return corev1.Service{}
}
return svc, nil
return svc
}
// NewIssuer 实现创建issuer资源对象
@ -149,3 +132,114 @@ func NewCert(md *myAppsv1.MsbDeployment) (*unstructured.Unstructured, error) {
},
}, nil
}
func newBaseContainer(md *myAppsv1.MsbDeployment) corev1.Container {
c := corev1.Container{
Name: md.Name,
Image: md.Spec.Image,
Ports: []corev1.ContainerPort{
{
ContainerPort: md.Spec.Port,
},
},
}
if len(md.Spec.StartCmd) != 0 {
c.Command = md.Spec.StartCmd
}
if len(md.Spec.Args) != 0 {
c.Args = md.Spec.Args
}
if len(md.Spec.Environments) != 0 {
c.Env = md.Spec.Environments
}
return c
}
func newBaseDeployment(md *myAppsv1.MsbDeployment) appsv1.Deployment {
return appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: md.Name,
Namespace: md.Namespace,
Labels: newLabels(md),
},
}
}
func newServicePort(md *myAppsv1.MsbDeployment) corev1.ServicePort {
return corev1.ServicePort{
Protocol: corev1.ProtocolTCP,
Port: md.Spec.Expose.ServicePort,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: md.Spec.Port,
},
}
}
func newBaseService(md *myAppsv1.MsbDeployment) corev1.Service {
return corev1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: md.Name,
Namespace: md.Namespace,
},
}
}
func newIngressTLS(md *myAppsv1.MsbDeployment) networkv1.IngressTLS {
return networkv1.IngressTLS{
Hosts: []string{md.Spec.Expose.IngressDomain},
SecretName: md.Name,
}
}
func newIngressRule(md *myAppsv1.MsbDeployment) networkv1.IngressRule {
return networkv1.IngressRule{
Host: md.Spec.Expose.IngressDomain,
IngressRuleValue: networkv1.IngressRuleValue{
HTTP: &networkv1.HTTPIngressRuleValue{
Paths: []networkv1.HTTPIngressPath{
{
PathType: &PathTypePrefix,
Path: "/",
Backend: networkv1.IngressBackend{
Service: &networkv1.IngressServiceBackend{
Name: md.Name,
Port: networkv1.ServiceBackendPort{
Number: md.Spec.Expose.ServicePort,
},
},
},
},
},
},
},
}
}
func newBaseIngress(md *myAppsv1.MsbDeployment) networkv1.Ingress {
return networkv1.Ingress{
TypeMeta: metav1.TypeMeta{
Kind: "Ingress",
APIVersion: "networking.k8s.io/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: md.Name,
Namespace: md.Namespace,
},
}
}
func newLabels(md *myAppsv1.MsbDeployment) map[string]string {
return map[string]string{"app": md.Name}
}

@ -61,37 +61,30 @@ func TestNewDeployment(t *testing.T) {
md *myAppsv1.MsbDeployment
}
tests := []struct {
name string // 测试用例的名称
args args // 测试函数的参数
want *appsv1.Deployment // 期望的结果
wantErr bool // 我们进行测试时候函数是否需要出错
name string // 测试用例的名称
args args // 测试函数的参数
want *appsv1.Deployment // 期望的结果
}{
{
name: "测试使用ingress mode 时候生成Deployment资源。",
args: args{
md: newMsbDeployment("msb-ingress-cr.yaml"),
},
want: newDeployment("msb-ingress-deployment-expect.yaml"),
wantErr: false,
want: newDeployment("msb-ingress-deployment-expect.yaml"),
},
{
name: "测试使用nodeport mode 时候生成Deployment资源",
args: args{
md: newMsbDeployment("msb-nodeport-cr.yaml"),
},
want: newDeployment("msb-nodeport-deployment-expect.yaml"),
wantErr: false,
want: newDeployment("msb-nodeport-deployment-expect.yaml"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewDeployment(tt.args.md)
if (err != nil) != tt.wantErr {
t.Errorf("NewDeployment() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewDeployment() got = %v, want %v", got, tt.want)
got := NewDeployment(tt.args.md)
if !reflect.DeepEqual(got, *tt.want) {
t.Errorf("NewDeployment() got = %v, want %v", got, *tt.want)
}
})
}
@ -102,29 +95,23 @@ func TestNewIngress(t *testing.T) {
md *myAppsv1.MsbDeployment
}
tests := []struct {
name string
args args
want *networkv1.Ingress
wantErr bool
name string
args args
want *networkv1.Ingress
}{
{
name: "测试使用ingress mode 时候生成ingress资源",
args: args{
md: newMsbDeployment("msb-ingress-cr.yaml"),
},
want: newIngress("msb-ingress-ingress-expect.yaml"),
wantErr: false,
want: newIngress("msb-ingress-ingress-expect.yaml"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewIngress(tt.args.md)
if (err != nil) != tt.wantErr {
t.Errorf("NewIngress() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewIngress() got = %v, want %v", got, tt.want)
got := NewIngress(tt.args.md)
if !reflect.DeepEqual(got, *tt.want) {
t.Errorf("NewIngress() got = %v, want %v", got, *tt.want)
}
})
}
@ -135,62 +122,23 @@ func TestNewService(t *testing.T) {
md *myAppsv1.MsbDeployment
}
tests := []struct {
name string
args args
want *corev1.Service
wantErr bool
name string
args args
want *corev1.Service
}{
{
name: "测试使用ingress mode 时候,生成 service 资源",
args: args{
md: newMsbDeployment("msb-ingress-cr.yaml"),
},
want: newService("msb-ingress-service-expect.yaml"),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewService(tt.args.md)
if (err != nil) != tt.wantErr {
t.Errorf("NewService() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewService() got = %v, want %v", got, tt.want)
}
})
}
}
func TestNewServiceNP(t *testing.T) {
type args struct {
md *myAppsv1.MsbDeployment
}
tests := []struct {
name string
args args
want *corev1.Service
wantErr bool
}{
{
name: "测试使用 nodeport mode时候生成 nodeport 类型的 service 资源",
args: args{
md: newMsbDeployment("msb-nodeport-cr.yaml"),
},
want: newService("msb-nodeport-service-expect.yaml"),
wantErr: false,
want: newService("msb-ingress-service-expect.yaml"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewServiceNP(tt.args.md)
if (err != nil) != tt.wantErr {
t.Errorf("NewServiceNP() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewServiceNP() got = %v, want %v", got, tt.want)
got := NewService(tt.args.md)
if !reflect.DeepEqual(got, *tt.want) {
t.Errorf("NewService() got = %v, want %v", got, *tt.want)
}
})
}

@ -165,29 +165,9 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
svc := new(corev1.Service)
if err := r.Client.Get(ctx, req.NamespacedName, svc); err != nil {
if errors.IsNotFound(err) {
// 3.1 不存在
// 3.1.1 mode 为 ingress
if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeIngress {
// 3.1.1.1 创建普通service
if err := r.createService(ctx, mdCopy); err != nil {
return ctrl.Result{}, err
}
} else if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeNodePort {
// 3.1.2 mode 为 nodeport
// 3.1.2.1 创建 nodeport 模式的 service
if err := r.createNPService(ctx, mdCopy); err != nil {
return ctrl.Result{}, err
}
} else {
return ctrl.Result{}, myAppsv1.ErrorNotSupportMode
}
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeService,
fmt.Sprintf(myAppsv1.ConditionMessageServiceNotFmt, req.Name),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonServiceNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
// 3.1 不存在 创建 service
if err := r.createService(ctx, mdCopy); err != nil {
return ctrl.Result{}, err
}
} else {
if _, errStatus := r.updateStatus(ctx,
@ -201,22 +181,12 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, err
}
} else {
// 3.2 存在
if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeIngress {
// 3.2.1 mode 为 ingress
// 3.2.1.1 更新普通的 service
if err := r.updateService(ctx, mdCopy, svc); err != nil {
return ctrl.Result{}, err
}
} else if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeNodePort {
// 3.2.2 mode 为 nodeport
// 3.2.2.1 更新nodeport模式的service
if err := r.updateNPService(ctx, mdCopy, svc); err != nil {
return ctrl.Result{}, err
}
} else {
return ctrl.Result{}, myAppsv1.ErrorNotSupportMode
// 3.2 存在 更新 service
if err := r.updateService(ctx, mdCopy, svc); err != nil {
return ctrl.Result{}, err
}
// 检查 现有状态来更新 status
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeService,
@ -339,32 +309,26 @@ func (r *MsbDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
}
func (r *MsbDeploymentReconciler) createDeployment(ctx context.Context, md *myAppsv1.MsbDeployment) error {
deploy, err := NewDeployment(md)
if err != nil {
return err
}
deploy := NewDeployment(md)
// 设置 deployment 所属于 md
if err := controllerutil.SetControllerReference(md, deploy, r.Scheme); err != nil {
if err := controllerutil.SetControllerReference(md, &deploy, r.Scheme); err != nil {
return err
}
return r.Client.Create(ctx, deploy)
return r.Client.Create(ctx, &deploy)
}
func (r *MsbDeploymentReconciler) updateDeployment(ctx context.Context, md *myAppsv1.MsbDeployment, dp *appsv1.Deployment) error {
deploy, err := NewDeployment(md)
if err != nil {
return err
}
deploy := NewDeployment(md)
// 设置 deployment 所属于 md
if err := controllerutil.SetControllerReference(md, deploy, r.Scheme); err != nil {
if err := controllerutil.SetControllerReference(md, &deploy, r.Scheme); err != nil {
return err
}
// 预更新deployment得到更新后的数据
if err := r.Update(ctx, deploy, client.DryRunAll); err != nil {
if err := r.Update(ctx, &deploy, client.DryRunAll); err != nil {
return err
}
@ -373,50 +337,30 @@ func (r *MsbDeploymentReconciler) updateDeployment(ctx context.Context, md *myAp
return nil
}
return r.Client.Update(ctx, deploy)
return r.Client.Update(ctx, &deploy)
}
func (r *MsbDeploymentReconciler) createService(ctx context.Context, md *myAppsv1.MsbDeployment) error {
svc, err := NewService(md)
if err != nil {
return err
}
// 设置 service 所属于 md
if err := controllerutil.SetControllerReference(md, svc, r.Scheme); err != nil {
return err
}
return r.Client.Create(ctx, svc)
}
func (r *MsbDeploymentReconciler) createNPService(ctx context.Context, md *myAppsv1.MsbDeployment) error {
svc, err := NewServiceNP(md)
if err != nil {
return err
}
svc := NewService(md)
// 设置 service 所属于 md
if err := controllerutil.SetControllerReference(md, svc, r.Scheme); err != nil {
if err := controllerutil.SetControllerReference(md, &svc, r.Scheme); err != nil {
return err
}
return r.Client.Create(ctx, svc)
return r.Client.Create(ctx, &svc)
}
func (r *MsbDeploymentReconciler) updateService(ctx context.Context, md *myAppsv1.MsbDeployment, service *corev1.Service) error {
svc, err := NewService(md)
if err != nil {
return err
}
svc := NewService(md)
// 设置 service 所属于 md
if err := controllerutil.SetControllerReference(md, svc, r.Scheme); err != nil {
if err := controllerutil.SetControllerReference(md, &svc, r.Scheme); err != nil {
return err
}
// 预更新service得到更新后的数据
if err := r.Update(ctx, svc, client.DryRunAll); err != nil {
if err := r.Update(ctx, &svc, client.DryRunAll); err != nil {
return err
}
@ -425,55 +369,25 @@ func (r *MsbDeploymentReconciler) updateService(ctx context.Context, md *myAppsv
return nil
}
return r.Client.Update(ctx, svc)
}
func (r *MsbDeploymentReconciler) updateNPService(ctx context.Context, md *myAppsv1.MsbDeployment, service *corev1.Service) error {
svc, err := NewServiceNP(md)
if err != nil {
return err
}
// 设置 service 所属于 md
if err := controllerutil.SetControllerReference(md, svc, r.Scheme); err != nil {
return err
}
// 预更新service得到更新后的数据
if err := r.Update(ctx, svc, client.DryRunAll); err != nil {
return err
}
// 和之前的数据进行比较,如果相同,说明更新不需要。
if reflect.DeepEqual(service.Spec, svc.Spec) {
return nil
}
return r.Client.Update(ctx, svc)
return r.Client.Update(ctx, &svc)
}
func (r *MsbDeploymentReconciler) createIngress(ctx context.Context, md *myAppsv1.MsbDeployment) error {
ig, err := NewIngress(md)
if err != nil {
return err
}
ig := NewIngress(md)
// 设置 ingress 所属于 md
if err := controllerutil.SetControllerReference(md, ig, r.Scheme); err != nil {
if err := controllerutil.SetControllerReference(md, &ig, r.Scheme); err != nil {
return err
}
return r.Client.Create(ctx, ig)
return r.Client.Create(ctx, &ig)
}
func (r *MsbDeploymentReconciler) updateIngress(ctx context.Context, md *myAppsv1.MsbDeployment, ingress *networkv1.Ingress) error {
ig, err := NewIngress(md)
if err != nil {
return err
}
ig := NewIngress(md)
// 设置 ingress 所属于 md
if err := controllerutil.SetControllerReference(md, ig, r.Scheme); err != nil {
if err := controllerutil.SetControllerReference(md, &ig, r.Scheme); err != nil {
return err
}
@ -487,15 +401,13 @@ func (r *MsbDeploymentReconciler) updateIngress(ctx context.Context, md *myAppsv
return nil
}
return r.Client.Update(ctx, ig)
return r.Client.Update(ctx, &ig)
}
func (r *MsbDeploymentReconciler) deleteIngress(ctx context.Context, md *myAppsv1.MsbDeployment) error {
ig, err := NewIngress(md)
if err != nil {
return err
}
return r.Client.Delete(ctx, ig)
ig := NewIngress(md)
return r.Client.Delete(ctx, &ig)
}
// 处理status

@ -1,22 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .ObjectMeta.Name }}
namespace: {{ .ObjectMeta.Namespace }}
labels:
app: {{ .ObjectMeta.Name }}
spec:
replicas: {{ .Spec.Replicas }}
selector:
matchLabels:
app: {{ .ObjectMeta.Name }}
template:
metadata:
labels:
app: {{ .ObjectMeta.Name }}
spec:
containers:
- name: {{ .ObjectMeta.Name }}
image: {{ .Spec.Image }}
ports:
- containerPort: {{ .Spec.Port }}

@ -1,22 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .ObjectMeta.Name }}
namespace: {{ .ObjectMeta.Namespace }}
spec:
ingressClassName: nginx
tls:
- hosts:
- {{ .Spec.Expose.IngressDomain }}
secretName: {{ .ObjectMeta.Name }}
rules:
- host: {{ .Spec.Expose.IngressDomain }}
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: {{ .ObjectMeta.Name }}
port:
number: {{ .Spec.Expose.ServicePort }}

@ -1,18 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .ObjectMeta.Name }}
namespace: {{ .ObjectMeta.Namespace }}
spec:
ingressClassName: nginx
rules:
- host: {{ .Spec.Expose.IngressDomain }}
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: {{ .ObjectMeta.Name }}
port:
number: {{ .Spec.Expose.ServicePort }}

@ -1,16 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .ObjectMeta.Name }}
namespace: {{ .ObjectMeta.Namespace }}
spec:
type: NodePort
selector:
app: {{ .ObjectMeta.Name }}
ports:
# 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
- port: {{ .Spec.Expose.ServicePort }}
targetPort: {{ .Spec.Port }}
# 可选字段
# 默认情况下为了方便起见Kubernetes 控制平面会从某个范围内分配一个端口号默认30000-32767
nodePort: {{ .Spec.Expose.NodePort }}

@ -1,12 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .ObjectMeta.Name }}
namespace: {{ .ObjectMeta.Namespace }}
spec:
selector:
app: {{ .ObjectMeta.Name }}
ports:
- protocol: TCP
port: {{ .Spec.Expose.ServicePort }}
targetPort: {{ .Spec.Port }}

@ -8,4 +8,5 @@ spec:
replicas: 2
expose:
mode: ingress
ingressDomain: www.mashingbing-test.com
ingressDomain: www.mashingbing-test.com
servicePort: 80
Loading…
Cancel
Save