l-35 first code done

master
dongming 2 years ago
parent 38a04966b2
commit 7af5635165

@ -4,3 +4,32 @@ const (
ModeIngress = "ingress" ModeIngress = "ingress"
ModeNodePort = "nodeport" ModeNodePort = "nodeport"
) )
const (
ConditionTypeDeployment = "Deployment"
ConditionTypeService = "Service"
ConditionTypeIngress = "Ingress"
ConditionMessageDeploymentOKFmt = "Deployment %s is ready"
ConditionMessageDeploymentNotFmt = "Deployment %s is not ready"
ConditionMessageServiceOKFmt = "Service %s is ready"
ConditionMessageServiceNotFmt = "Service %s is not ready"
ConditionMessageIngressOKFmt = "Ingress %s is ready"
ConditionMessageIngressNotFmt = "Ingress %s is not ready"
ConditionReasonDeploymentReady = "DeploymentReady"
ConditionReasonDeploymentNotReady = "DeploymentNotReady"
ConditionReasonServiceReady = "ServiceReady"
ConditionReasonServiceNotReady = "ServiceNotReady"
ConditionReasonIngressReady = "IngressReady"
ConditionReasonIngressNotReady = "IngressNotReady"
ConditonStatusTrue = "True"
ConditonStatusFalse = "False"
)
const (
StatusReasonSuccess = "Success"
StatusMessageSuccess = "Success"
StatusPhaseComplete = "Complete"
)

@ -18,13 +18,16 @@ package controllers
import ( import (
"context" "context"
"fmt"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
networkv1 "k8s.io/api/networking/v1" networkv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"reflect" "reflect"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"strings" "strings"
"time"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
@ -34,6 +37,8 @@ import (
myAppsv1 "mashibing.com/pkg/mashibing-deployment/api/v1" myAppsv1 "mashibing.com/pkg/mashibing-deployment/api/v1"
) )
var WaitRequeue = 10 * time.Second
// MsbDeploymentReconciler reconciles a MsbDeployment object // MsbDeploymentReconciler reconciles a MsbDeployment object
type MsbDeploymentReconciler struct { type MsbDeploymentReconciler struct {
client.Client client.Client
@ -54,6 +59,14 @@ type MsbDeploymentReconciler struct {
// For more details, check Reconcile and its Result here: // For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile
func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// 状态更新策略
// 创建的时候
// 更新为创建
// 更新的时候
// 根据获取的状态来判断时候更新status
// 删除的时候
// 只有在操作 ingress 的时候,并且 mode 为 nodeport 的时候
logger := log.FromContext(ctx, "MsbDployment", req.NamespacedName) logger := log.FromContext(ctx, "MsbDployment", req.NamespacedName)
logger.Info("Reconcile is started.") logger.Info("Reconcile is started.")
@ -74,10 +87,26 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
// 2.1 不存在对象 // 2.1 不存在对象
// 2.1.1 创建 deployment // 2.1.1 创建 deployment
if err := r.createDeployment(ctx, mdCopy); err != nil { if errCreate := r.createDeployment(ctx, mdCopy); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, errCreate
}
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeDeployment,
fmt.Sprintf(myAppsv1.ConditionMessageDeploymentNotFmt, req.Name),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonDeploymentNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
} }
} else { } else {
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeDeployment,
fmt.Sprintf("Deployment %s, err: %s", req.Name, err.Error()),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonDeploymentNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} else { } else {
@ -86,6 +115,25 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
if err := r.updateDeployment(ctx, mdCopy, deploy); err != nil { if err := r.updateDeployment(ctx, mdCopy, deploy); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if deploy.Status.AvailableReplicas == mdCopy.Spec.Replicas {
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeDeployment,
fmt.Sprintf(myAppsv1.ConditionMessageDeploymentOKFmt, req.Name),
myAppsv1.ConditonStatusTrue,
myAppsv1.ConditionReasonDeploymentReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
} else {
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeDeployment,
fmt.Sprintf(myAppsv1.ConditionMessageDeploymentNotFmt, req.Name),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonDeploymentNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
}
} }
// ======= 处理 service ========= // ======= 处理 service =========
@ -109,7 +157,23 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
} else { } else {
return ctrl.Result{}, myAppsv1.ErrorNotSupportMode 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
}
} else { } else {
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeService,
fmt.Sprintf("Service %s, err: %s", req.Name, err.Error()),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonServiceNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} else { } else {
@ -129,6 +193,14 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
} else { } else {
return ctrl.Result{}, myAppsv1.ErrorNotSupportMode return ctrl.Result{}, myAppsv1.ErrorNotSupportMode
} }
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeService,
fmt.Sprintf(myAppsv1.ConditionMessageServiceOKFmt, req.Name),
myAppsv1.ConditonStatusTrue,
myAppsv1.ConditionReasonServiceReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
} }
// ======= 处理 ingress ========= // ======= 处理 ingress =========
@ -143,12 +215,28 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
if err := r.createIngress(ctx, mdCopy); err != nil { if err := r.createIngress(ctx, mdCopy); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeIngress,
fmt.Sprintf(myAppsv1.ConditionMessageIngressNotFmt, req.Name),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonIngressNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
} else if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeNodePort { } else if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeNodePort {
// 4.1.2 mode 为 nodeport // 4.1.2 mode 为 nodeport
// 4.1.2.1 退出 // 4.1.2.1 退出
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
} else { } else {
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeIngress,
fmt.Sprintf("Ingress %s, err: %s", req.Name, err.Error()),
myAppsv1.ConditonStatusFalse,
myAppsv1.ConditionReasonIngressNotReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} else { } else {
@ -159,15 +247,37 @@ func (r *MsbDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Reques
if err := r.updateIngress(ctx, mdCopy, ig); err != nil { if err := r.updateIngress(ctx, mdCopy, ig); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if _, errStatus := r.updateStatus(ctx,
mdCopy,
myAppsv1.ConditionTypeIngress,
fmt.Sprintf(myAppsv1.ConditionMessageIngressOKFmt, req.Name),
myAppsv1.ConditonStatusTrue,
myAppsv1.ConditionReasonIngressReady); errStatus != nil {
return ctrl.Result{}, errStatus
}
} else if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeNodePort { } else if strings.ToLower(mdCopy.Spec.Expose.Mode) == myAppsv1.ModeNodePort {
// 4.2.2 mode 为 nodeport // 4.2.2 mode 为 nodeport
// 4.2.2.1 删除 ingress // 4.2.2.1 删除 ingress
if err := r.deleteIngress(ctx, mdCopy); err != nil { if err := r.deleteIngress(ctx, mdCopy); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
r.deleteStatus(mdCopy, myAppsv1.ConditionTypeIngress)
} }
} }
// 最后检查状态时候最终完成
if sus, errStatus := r.updateStatus(ctx,
mdCopy,
"",
"",
"",
""); errStatus != nil {
return ctrl.Result{}, errStatus
} else if !sus {
logger.Info("Reconcile is ended.")
return ctrl.Result{RequeueAfter: WaitRequeue}, nil
}
logger.Info("Reconcile is ended.") logger.Info("Reconcile is ended.")
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
@ -341,3 +451,133 @@ func (r *MsbDeploymentReconciler) deleteIngress(ctx context.Context, md *myAppsv
} }
return r.Client.Delete(ctx, ig) return r.Client.Delete(ctx, ig)
} }
// 处理status
// return:
//
// bool: 资源是否完成,时候需要等待。如果是 true表示资源已经完成没不需要再次reconcile
// 如果是 false表示资源还未完成需要重新入队
// error执行 update 的状态
func (r *MsbDeploymentReconciler) updateStatus(ctx context.Context, md *myAppsv1.MsbDeployment, conditionType, message, status, reason string) (bool, error) {
if conditionType != "" {
// 1. 获取 status
//status := md.Status
// 2. 获取 conditions 字段
//conditions := status.Conditions
// 3. 根据当前的需求,获取指定的 condition
var condition *myAppsv1.Condition
for i := range md.Status.Conditions {
// 4. 是否获取到
if md.Status.Conditions[i].Type == conditionType {
// 4.1 获取到了
condition = &md.Status.Conditions[i]
}
}
if condition != nil {
// 4.1.1 获取当前线上的 conditon 状态与存储的condition进行比较如果相同跳过。不同替换
if condition.Status != status ||
condition.Message != message ||
condition.Reason != reason {
condition.Status = status
condition.Message = message
condition.Reason = reason
}
} else {
// 4.2 没获取到创建这个conditon更新到conditons中
md.Status.Conditions = append(md.Status.Conditions,
createCondition(conditionType, message, status, reason))
}
}
// 5. 继续处理其他的conditions
m, re, p, sus := isSuccess(md.Status.Conditions)
if sus {
// 6.1 如果所有conditions的状态都为成功则更新总的 status 为成功。
md.Status.Message = myAppsv1.StatusMessageSuccess
md.Status.Reason = myAppsv1.StatusReasonSuccess
md.Status.Phase = myAppsv1.StatusPhaseComplete
} else {
// 6.2 遍历所有的conditons 状态如果有任意一个condition不是完成的状态则将这个状态更新到总的 status 中。更待一定时间再次入队。
md.Status.Message = m
md.Status.Reason = re
md.Status.Phase = p
}
// 7. 执行更新
return sus, r.Client.Status().Update(ctx, md)
}
func isSuccess(conditions []myAppsv1.Condition) (message, reason, phase string, sus bool) {
if len(conditions) == 0 {
return "", "", "", false
}
for i := range conditions {
if conditions[i].Status == myAppsv1.ConditonStatusFalse {
return conditions[i].Message, conditions[i].Reason, conditions[i].Type, false
}
}
return "", "", "", true
}
func createCondition(conditionType, message, status, reason string) myAppsv1.Condition {
return myAppsv1.Condition{
Type: conditionType,
Message: message,
Status: status,
Reason: reason,
LastTransitionTime: metav1.NewTime(time.Now()),
}
}
// 需要是幂等的,可以多次执行,不管是否存在。如果存在就删除,不存在就什么也不做
// 只是删除对应的Condition不做更多的操作
func (r *MsbDeploymentReconciler) deleteStatus(md *myAppsv1.MsbDeployment, conditionType string) {
// 1. 遍历conditions
for i := range md.Status.Conditions {
// 2. 找到要删除的对象
if md.Status.Conditions[i].Type == conditionType {
// 3. 执行删除
md.Status.Conditions = deleteCondition(md.Status.Conditions, i)
}
}
}
// a := struct {
// len int
// cap int
// [cap]int [1,2,3,4]
// }
//
// b = a
//
// b
//
// a
// a = append(a, "b")
// conditions = deleteCondition(conditions, 2)
// a = [1,2,3,4,5]
// f(a)
//
// f(b []int) {
// b = n[0:4]
// }
func deleteCondition(conditions []myAppsv1.Condition, i int) []myAppsv1.Condition {
// 前提:切片中的元素顺序不敏感
// 1. 要删除的元素的索引值不能大于切片长度
if i >= len(conditions) {
return []myAppsv1.Condition{}
}
// 2. 如果切片长度为1且索引值为0直接清空
if len(conditions) == 1 && i == 0 {
return conditions[:0]
}
// 3. 如果长度-1等于索引值删除最后一个元素
if len(conditions)-1 == i {
return conditions[:len(conditions)-1]
}
// 4. 交换索引位置的元素和最后一个元素,删除最后一个元素
conditions[i], conditions[len(conditions)-1] = conditions[len(conditions)-1], conditions[i]
return conditions[:len(conditions)-1]
}

Loading…
Cancel
Save