自动化金丝雀部署:Flagger全面解读webhook(含源码)

这篇具有很好参考价值的文章主要介绍了自动化金丝雀部署:Flagger全面解读webhook(含源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

内容导读:

背景

上文通过下面的配置就实现了验收测试压力测试,对此有以下疑问:

  1. metadata定义脚本和类型,说明接口能执行shell,那它是怎么实现的?
  2. type未设置是怎样的执行逻辑?type有哪些值,各有什么作用?

自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

本文将通过源码来解答以上问题

源码粗读

本文采用粗读源码方式,因为webhook是一个功能点,不算Flagger核心流程。

源码下载

源码:https://github.com/fluxcd/flagger

git clone https://github.com/fluxcd/flagger.git

定位webhooks接口定义代码

接口定义信息:Kind为Canary,webhooks位于spec.analysis.webhooks

Canary代码位置:pkg/apis/flagger/v1beta1/canary.go:44

自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

接着点击CanarySpecCanaryAnalysis就找到了webhooks属性定义。

自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

webhooks对应的结构体为CanaryWebhook

// CanaryWebhook holds the reference to external checks used for canary analysis
type CanaryWebhook struct {
	// Type of this webhook
	Type HookType `json:"type"`

	// Name of this webhook
	Name string `json:"name"`

	// URL address of this webhook
	URL string `json:"url"`

	// false会触发告警,目前支持confirm-rollout、confirm-traffic-increase、confirm-promotion阶段
	MuteAlert bool `json:"muteAlert"`

	// Request timeout for this webhook
	Timeout string `json:"timeout,omitempty"`

	// Metadata (key-value pairs) for this webhook
	// +optional
	Metadata *map[string]string `json:"metadata,omitempty"`

	// Number of retries for this webhook
	// +optional
	Retries int `json:"retries,omitempty"`
}

定位CanaryWebhook相关代码

自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

只需关注两个函数:

  1. CallEventWebhook:位于pkg/controller/webhook.go:106
  2. CallWebhook:位于pkg/controller/webhook.go:87

说明:events.go为系统的创建Webhook(用户创建的由spec.analysis.webhooks定义),最终是调用CallEventWebhook
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

解读CallEventWebhook和CallWebhook

比较两个函数差异点和共同点如下图:
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

最终调用callWebhook:发起httpPOST请求的常规代码。
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

小结:问题1结论

Flagger Webhook会向目标地址发送方法的http POST请求,发送数据结构如下:

// CanaryWebhookPayload holds the deployment info and metadata sent to webhooks
type CanaryWebhookPayload struct {
	// Name of the canary
	Name string `json:"name"`
	// Namespace of the canary
	Namespace string `json:"namespace"`
	// Phase of the canary analysis
	Phase CanaryPhase `json:"phase"`
	// Hash from the TrackedConfigs and LastAppliedSpec of the Canary.
	// Can be used to identify a Canary for a specific configuration of the
	// deployed resources.
	Checksum string `json:"checksum"`
	// Metadata (key-value pairs) for this webhook
	Metadata map[string]string `json:"metadata,omitempty"`
}

以上就解答了问题1:Flagger仅发送http请求,具体逻辑由目标接口实现

分析loadtester接口实现代码

我们用到了http://flagger-loadtester.test/
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

loadtester服务启动入口
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops
找到接口http://flagger-loadtester.test/处理逻辑
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

最后按metadata.type执行任务。
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

解读Webhook type

用到Webhook type的相关代码如下

自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

一共有8个可选值,7个阶段

各值含义如下:

  1. confirm-rollout:在扩展金丝雀部署之前执行,可用于手动批准。Canary 将暂停,直到 webhook 返回成功的 HTTP 状态代码。
  2. pre-rollout:在将流量路由到金丝雀之前执行。如果预部署钩子失败,则金丝雀前进将暂停,并且如果失败数量达到阈值,金丝雀将回滚。
  3. rollout:在指标检查之前的每次迭代分析过程中执行。如果 rollout 调用失败,则金丝雀进度将暂停并最终回滚。
  4. confirm-traffic-increase:在金丝雀的权重增加之前执行。金丝雀前进将暂停,直到该钩子返回 HTTP 200。
  5. confirm-promotion:在升级步骤之前执行。金丝雀升级将暂停,直到挂钩返回 HTTP 200。升级暂停时,Flagger 将继续运行指标检查和推出挂钩。
  6. post-rollout:在金丝雀升级或回滚后执行。如果发布后 webhook 失败,则会记录错误。
  7. rollback:当金丝雀部署处于“正在进行”或“等待”状态时,会执行回滚钩子。这提供了在分析期间或等待确认时回滚的能力。如果回滚钩子返回成功的 HTTP 状态代码,Flagger 将停止分析并将金丝雀发布标记为失败。
  8. event:每次 Flagger 发出 Kubernetes 事件时都会执行事件挂钩。配置后,Flagger 在金丝雀部署期间执行的每个操作都将通过 HTTP POST 请求以 JSON 形式发送。

说明:前面7个值是Canary对应的七个阶段,event表示Canary创建了k8s事件就会触发。

Webhook type定义如下:
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

confirm-rollout 源码解读

  1. 类型为ConfirmRolloutHook
  2. 反向引用找到使用ConfirmRolloutHook代码(仅保留关键代码)
func (c *Controller) runConfirmRolloutHooks(canary *flaggerv1.Canary, canaryController canary.Controller) bool {
	for _, webhook := range canary.GetAnalysis().Webhooks {
		if webhook.Type == flaggerv1.ConfirmRolloutHook {
			err := CallWebhook(*canary, canary.Status.Phase, webhook)
            if err != nil {
				return false
			}
		}
	}
	return true
}
  1. 反向引用找到使用runConfirmRolloutHooks代码(仅保留关键代码)
func (c *Controller) checkCanaryStatus(canary *flaggerv1.Canary, canaryController canary.Controller, scalerReconciler canary.ScalerReconciler, shouldAdvance bool) bool {
	c.recorder.SetStatus(canary, canary.Status.Phase)
	if canary.Status.Phase == flaggerv1.CanaryPhaseProgressing ||
		canary.Status.Phase == flaggerv1.CanaryPhaseWaitingPromotion ||
		canary.Status.Phase == flaggerv1.CanaryPhasePromoting ||
		canary.Status.Phase == flaggerv1.CanaryPhaseFinalising {
		return true
	}

	var err error
	canary, err = c.flaggerClient.FlaggerV1beta1().Canaries(canary.Namespace).Get(context.TODO(), canary.Name, metav1.GetOptions{})
	if err != nil {
        // 按ns和name获取,err表示Canary不存在
		return false
	}

	if shouldAdvance {
		// 调用runConfirmRolloutHooks
		if isApproved := c.runConfirmRolloutHooks(canary, canaryController); !isApproved {
            // 接口返回false,即未通过审批
			return false
		}
        canaryPhaseProgressing := canary.DeepCopy()
        // 审批通过后,canary状态为CanaryPhaseProgressing(将由上面的逻辑直接返回true)
		canaryPhaseProgressing.Status.Phase = flaggerv1.CanaryPhaseProgressing
        if err := canaryController.SyncStatus(canary, flaggerv1.CanaryStatus{Phase: flaggerv1.CanaryPhaseProgressing}); err != nil {
			return false
		}
		return false
	}
	return false
}
  1. 值为true的条件:shouldAdvance为true的条件:canary状态为(Progressing、Waiting、WaitingPromotion、Promoting、Finalising)、worklod有变化、worklod依赖资源(ConfigMap+Secret)有变化。查看shouldAdvance代码:
func (c *Controller) shouldAdvance(canary *flaggerv1.Canary, canaryController canary.Controller) (bool, error) {
	if canary.Status.Phase == flaggerv1.CanaryPhaseProgressing ||
		canary.Status.Phase == flaggerv1.CanaryPhaseWaiting ||
		canary.Status.Phase == flaggerv1.CanaryPhaseWaitingPromotion ||
		canary.Status.Phase == flaggerv1.CanaryPhasePromoting ||
		canary.Status.Phase == flaggerv1.CanaryPhaseFinalising {
		return true, nil
	}

	// Make sure to sync lastAppliedSpec even if the canary is in a failed state.
	if canary.Status.Phase == flaggerv1.CanaryPhaseFailed {
			return false, err
		}
	}

	newTarget, err := canaryController.HasTargetChanged(canary)
	if err != nil {
		return false, err
	}
	if newTarget {
		return newTarget, nil
	}

	newCfg, err := canaryController.HaveDependenciesChanged(canary)
	if err != nil {
		return false, err
	}

	return newCfg, nil

}

pre-rollout 源码解读

  1. 类型为PreRolloutHook
  2. 反向引用找到使用PreRolloutHook代码(仅保留关键代码)
func (c *Controller) runPreRolloutHooks(canary *flaggerv1.Canary) bool {
	for _, webhook := range canary.GetAnalysis().Webhooks {
		if webhook.Type == flaggerv1.PreRolloutHook {
			err := CallWebhook(*canary, flaggerv1.CanaryPhaseProgressing, webhook)
			if err != nil {
				return false
			} else {
				c.recordEventInfof(canary, "Pre-rollout check %s passed", webhook.Name)
			}
		}
	}
	return true
}
  1. 反向引用找到使用runPreRolloutHooks代码(仅保留关键代码)
    // 灰度流量为0 且 canary的迭代数为0(0表示对业务有效,像AB测试和蓝绿测试迭代数非0) 且 非影子/镜像流量
	if canaryWeight == 0 && cd.Status.Iterations == 0 &&
		!(cd.GetAnalysis().Mirror && mirrored) {
		c.recordEventInfof(cd, "Starting canary analysis for %s.%s", cd.Spec.TargetRef.Name, cd.Namespace)

		// run pre-rollout web hooks
		if ok := c.runPreRolloutHooks(cd); !ok {
			if err := canaryController.SetStatusFailedChecks(cd, cd.Status.FailedChecks+1); err != nil {
				c.recordEventWarningf(cd, "%v", err)
			}
			return
		}
	} else {
        // rollout执行代码
		if ok := c.runAnalysis(cd); !ok {
			if err := canaryController.SetStatusFailedChecks(cd, cd.Status.FailedChecks+1); err != nil {
				c.recordEventWarningf(cd, "%v", err)
			}
			return
		}
	}

rollout(默认值) 源码解读

  1. 类型为RolloutHook
  2. 反向引用找到使用RolloutHook代码(仅保留关键代码)
func (c *Controller) runAnalysis(canary *flaggerv1.Canary) bool {
	// run external checks
	for _, webhook := range canary.GetAnalysis().Webhooks {
 // type为空也走此逻辑
		if webhook.Type == "" || webhook.Type == flaggerv1.RolloutHook {
			err := CallWebhook(*canary, flaggerv1.CanaryPhaseProgressing, webhook)
			if err != nil {
				return false
			}
		}
	}
	return true
}
  1. 执行runAnalysis代码位于pre-rollout执行代码处,执行条件为pre-rollout的相反条件
// 灰度流量为0 且 canary的迭代数为0(0表示对业务有效,像AB测试和蓝绿测试迭代数非0) 且 非影子/镜像流量
	if canaryWeight == 0 && cd.Status.Iterations == 0 &&
		!(cd.GetAnalysis().Mirror && mirrored) {
		c.recordEventInfof(cd, "Starting canary analysis for %s.%s", cd.Spec.TargetRef.Name, cd.Namespace)

		// run pre-rollout web hooks
		if ok := c.runPreRolloutHooks(cd); !ok {
			if err := canaryController.SetStatusFailedChecks(cd, cd.Status.FailedChecks+1); err != nil {
				c.recordEventWarningf(cd, "%v", err)
			}
			return
		}
	} else {
		if ok := c.runAnalysis(cd); !ok {
			if err := canaryController.SetStatusFailedChecks(cd, cd.Status.FailedChecks+1); err != nil {
				c.recordEventWarningf(cd, "%v", err)
			}
			return
		}
	}

confirm-traffic-increase 源码解读

  1. 类型为ConfirmTrafficIncreaseHook
  2. 反向引用找到使用ConfirmTrafficIncreaseHook代码(仅保留关键代码)
func (c *Controller) runConfirmTrafficIncreaseHooks(canary *flaggerv1.Canary) bool {
	for _, webhook := range canary.GetAnalysis().Webhooks {
		if webhook.Type == flaggerv1.ConfirmTrafficIncreaseHook {
			err := CallWebhook(*canary, flaggerv1.CanaryPhaseProgressing, webhook)
			if err != nil {
				return false
			}
		}
	}
	return true
}
  1. 反向引用找到使用runConfirmTrafficIncreaseHooks代码(仅保留关键代码)
    // 计算下次要增加流量
	if c.nextStepWeight(cd, canaryWeight) > 0 {
		if !mirrored &&
			(cd.Status.Phase != flaggerv1.CanaryPhasePromoting &&
				cd.Status.Phase != flaggerv1.CanaryPhaseWaitingPromotion &&
				cd.Status.Phase != flaggerv1.CanaryPhaseFinalising) {
			if promote := c.runConfirmTrafficIncreaseHooks(cd); !promote {
				return
			}
		}
		c.runCanary(cd, canaryController, meshRouter, mirrored, canaryWeight, primaryWeight, maxWeight)
	}

confirm-promotion 源码解读

  1. 类型为ConfirmPromotionHook
  2. 反向引用找到使用ConfirmPromotionHook代码(仅保留关键代码)
func (c *Controller) runConfirmPromotionHooks(canary *flaggerv1.Canary, canaryController canary.Controller) bool {
	for _, webhook := range canary.GetAnalysis().Webhooks {
		if webhook.Type == flaggerv1.ConfirmPromotionHook {
			err := CallWebhook(*canary, flaggerv1.CanaryPhaseProgressing, webhook)
			if err != nil {
				return false
			} else {
				c.recordEventInfof(canary, "Confirm-promotion check %s passed", webhook.Name)
			}
		}
	}
	return true
}
  1. 反向引用找到使用runConfirmPromotionHooks代码(仅保留关键代码)
if c.nextStepWeight(cd, canaryWeight) > 0 {
		// run hook only if traffic is not mirrored
		if !mirrored &&
			(cd.Status.Phase != flaggerv1.CanaryPhasePromoting &&
				cd.Status.Phase != flaggerv1.CanaryPhaseWaitingPromotion &&
				cd.Status.Phase != flaggerv1.CanaryPhaseFinalising) {
			if promote := c.runConfirmTrafficIncreaseHooks(cd); !promote {
				return
			}
		}
		c.runCanary(cd, canaryController, meshRouter, mirrored, canaryWeight, primaryWeight, maxWeight)
        
	}

func (c *Controller) runCanary(canary *flaggerv1.Canary, canaryController canary.Controller,
	meshRouter router.Interface, mirrored bool, canaryWeight int, primaryWeight int, maxWeight int) {
	// 灰度流量定义的最大灰度流量(analysis.maxWeight):下一步将把流量全部切换到primary
	if canaryWeight >= maxWeight {
		// check promotion gate
		if promote := c.runConfirmPromotionHooks(canary, canaryController); !promote {
			return
		}
	}
}

post-rollout 源码解读

  1. 类型为PostRolloutHook
  2. 反向引用找到使用PostRolloutHook代码(仅保留关键代码)

func (c *Controller) runPostRolloutHooks(canary *flaggerv1.Canary, phase flaggerv1.CanaryPhase) bool {
	for _, webhook := range canary.GetAnalysis().Webhooks {
		if webhook.Type == flaggerv1.PostRolloutHook {
			err := CallWebhook(*canary, phase, webhook)
			if err != nil {
				c.recordEventWarningf(canary, "Post-rollout hook %s failed %v", webhook.Name, err)
				return false
			} else {
				c.recordEventInfof(canary, "Post-rollout check %s passed", webhook.Name)
			}
		}
	}
	return true
}
  1. 反向引用找到使用runPostRolloutHooks代码(仅保留关键代码)
// scale canary to zero if promotion has finished
	if cd.Status.Phase == flaggerv1.CanaryPhaseFinalising {
		if scalerReconciler != nil {
			if err := scalerReconciler.PauseTargetScaler(cd); err != nil {
				c.recordEventWarningf(cd, "%v", err)
				return
			}
		}
		if err := canaryController.ScaleToZero(cd); err != nil {
			c.recordEventWarningf(cd, "%v", err)
			return
		}

		// set status to succeeded
		if err := canaryController.SetStatusPhase(cd, flaggerv1.CanaryPhaseSucceeded); err != nil {
			c.recordEventWarningf(cd, "%v", err)
			return
		}    
		c.recorder.SetStatus(cd, flaggerv1.CanaryPhaseSucceeded)
        // Canary状态为成功触发
		c.runPostRolloutHooks(cd, flaggerv1.CanaryPhaseSucceeded)
		c.recordEventInfof(cd, "Promotion completed! Scaling down %s.%s", cd.Spec.TargetRef.Name, cd.Namespace)
		c.alert(cd, "Canary analysis completed successfully, promotion finished.",
			false, flaggerv1.SeverityInfo)
		return
	}

rollback 源码解读

  1. 类型为RollbackHook
  2. 反向引用找到使用RollbackHook代码(仅保留关键代码)
func (c *Controller) runRollbackHooks(canary *flaggerv1.Canary, phase flaggerv1.CanaryPhase) bool {
	for _, webhook := range canary.GetAnalysis().Webhooks {
		if webhook.Type == flaggerv1.RollbackHook {
			err := CallWebhook(*canary, phase, webhook)
			if err != nil {
				c.recordEventInfof(canary, "Rollback hook %s not signaling a rollback", webhook.Name)
			} else {
				c.recordEventWarningf(canary, "Rollback check %s passed", webhook.Name)
				return true
			}
		}
	}
	return false
}
  1. 反向引用找到使用runRollbackHooks代码(仅保留关键代码)
	if cd.Status.Phase == flaggerv1.CanaryPhaseProgressing ||
		cd.Status.Phase == flaggerv1.CanaryPhaseWaiting ||
		cd.Status.Phase == flaggerv1.CanaryPhaseWaitingPromotion {
		if ok := c.runRollbackHooks(cd, cd.Status.Phase); ok {
			c.recordEventWarningf(cd, "Rolling back %s.%s manual webhook invoked", cd.Name, cd.Namespace)
			c.alert(cd, "Rolling back manual webhook invoked", false, flaggerv1.SeverityWarn)
            // 真正回滚逻辑
			c.rollback(cd, canaryController, meshRouter, scalerReconciler)
			return
		}
	}

event 源码解读

  1. 类型为EventHook
  2. 反向引用找到使用EventHook代码(仅保留关键代码)

func (c *Controller) sendEventToWebhook(r *flaggerv1.Canary, eventType, template string, args []interface{}) {
	webhookOverride := false
	for _, canaryWebhook := range r.GetAnalysis().Webhooks {
		if canaryWebhook.Type == flaggerv1.EventHook {
			webhookOverride = true
			err := CallEventWebhook(r, canaryWebhook, fmt.Sprintf(template, args...), eventType)
			if err != nil {
				c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Errorf("error sending event to webhook: %s", err)
			}
		}
	}

	// c.eventWebhook来源于环境变量"EVENT_WEBHOOK_URL"
	if c.eventWebhook != "" && !webhookOverride {
		hook := flaggerv1.CanaryWebhook{
			Name: "events",
			URL:  c.eventWebhook,
		}
		err := CallEventWebhook(r, hook, fmt.Sprintf(template, args...), eventType)
		if err != nil {
			c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Errorf("error sending event to webhook: %s", err)
		}
	}
}
  1. 反向引用找到使用sendEventToWebhook代码(仅保留关键代码):Canary产生的所有k8s Event都会执行sendEventToWebhook
func (c *Controller) recordEventInfof(r *flaggerv1.Canary, template string, args ...interface{}) {
	c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Infof(template, args...)
    // 记录event到k8s 
	c.eventRecorder.Event(r, corev1.EventTypeNormal, "Synced", fmt.Sprintf(template, args...))
	c.sendEventToWebhook(r, corev1.EventTypeNormal, template, args)
}

func (c *Controller) recordEventErrorf(r *flaggerv1.Canary, template string, args ...interface{}) {
	c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Errorf(template, args...)
	c.eventRecorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
	c.sendEventToWebhook(r, corev1.EventTypeWarning, template, args)
}

func (c *Controller) recordEventWarningf(r *flaggerv1.Canary, template string, args ...interface{}) {
	c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Infof(template, args...)
	c.eventRecorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
	c.sendEventToWebhook(r, corev1.EventTypeWarning, template, args)
}

附录

Goland本地启动服务

参考文档:https://docs.flagger.app/dev/dev-guide#manual-testing

增加启动参数:-kubeconfig=/Users/admin/.kube/config -log-level=info -mesh-provider=istio -metrics-server=http://prom.istio.cn:9090

启动配置
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

执行日志:
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

调试效果:
自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

结语

本文以Webhook疑问为出发点,通过粗读源码全面解读了Webhook相关知识,同时附上了Goland本地调试方法。

自动化金丝雀部署:Flagger全面解读webhook(含源码),DevOps,云原生,自动化,运维,devops

请用微信扫码关注下🙏 ,持续更新云原生DevOps最佳实践。文章来源地址https://www.toymoban.com/news/detail-847702.html

到了这里,关于自动化金丝雀部署:Flagger全面解读webhook(含源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • KubeSphere实现金丝雀发布(Canary Release)

    KubeSphere 基于 [Istio] 向用户提供金丝雀发布功能,即: 引入服务的新版本,并向其发送一小部分流量来进行测试 同时,旧版本负责处理其余的流量 如果一切顺利,就可逐渐增加向新版本发送的流量,同时逐步停用旧版本 如出现任何问题,可用 KubeSphere 更改流量比例来回滚至

    2024年02月02日
    浏览(35)
  • K8S Nginx Ingress实现金丝雀发布

    通过给 Ingress 资源指定 Nginx Ingress 所支持的 annotation 可实现金丝雀发布。 需给服务创建2个 Ingress,其中 1个常规 Ingress , 另1个为带  nginx.ingress.kubernetes.io/canary: \\\"true\\\"  固定的 annotation 的 Ingress,称为 Canary Ingress。 Canary Ingress 一般代表新版本的服务,结合另外针对流量切分策

    2024年02月11日
    浏览(32)
  • 【K8s】¹版本回退升级&金丝雀发布

    为了更好的解决服务编排的问题, 我们可以使用Deployment控制器。这种控制器不直接管理pod,他通过ReplicaSet来管理pod。 目录 1.使用yaml文件形式,创建deployment 2.扩缩容 3.镜像更新 4.版本回退 5.金丝雀发布 金丝雀发布的优点 金丝雀发布的缺点 Deployment主要功能: 支持ReplicaSet的

    2024年02月03日
    浏览(29)
  • 1W字长文:蓝绿发布、金丝雀发布、滚动发布、A/B测试 原理和实操

    蓝绿发布、金丝雀发布、滚动发布、A/B测试 ,是大家日常常见的发布工作。所以 发布的原理和实操 是一个 非常、非常核心的面试知识点 。 在40岁老架构师 尼恩的 读者交流群 (50+)中,其相关面试题是一个非常、非常高频的交流话题。 只要一面试,基本就会问: 对灰度发布

    2024年02月04日
    浏览(38)
  • 使用AWS和Kubernetes进行流程自动化:自动化部署和监控

    作者:禅与计算机程序设计艺术 机器学习、深度学习和自动化技术正在成为信息技术行业的新趋势。2017年以来,越来越多的企业开始采用机器学习技术解决业务上的实际问题。这项技术的应用已经从统计学模型逐渐转向基于数据的分析方法。随着云计算技术的蓬勃发展,越

    2024年02月07日
    浏览(33)
  • Github 自动化部署

    官方地址 点击进入 注册/登录 .githubworkflows 固定不变 develop.yml 文件名自定义 变量解释 secrets 是定义在github中的变量 通过 secerts.变量名 来取值 steps steps 是github action的 create_release 是上一个步骤的 id outputs.upload_url 是上一个步骤的返回结果 仓库地址:https://github.com/yi-

    2024年02月03日
    浏览(40)
  • 前端项目自动化部署

    一、Git仓库管理项目 二、购买云服务器 三、搭建服务器环境(重点) 四、Jenkins进行自动化部署(重点) 提示:本地项目自动化部署流程,如下图 一、Git仓库管理项目 Git的安装和配置在这里就不做说明了 1、首先在Git仓库中创建一个仓库,用来保存本地项目,这里使用Git

    2024年02月15日
    浏览(37)
  • jekins自动化部署

    为什么要用Jenkins?我说下我以前开发的痛点,在一些中小型企业,每次开发一个项目完成后,需要打包部署,可能没有专门的运维人员,只能开发人员去把项目打成一个exe包,可能这个项目已经上线了,需要把服务关,在部署到服务器上,将项目启动起来,这个时候可能某个

    2024年02月05日
    浏览(24)
  • Ansible自动化部署工具

    1、运维工具特点 Ansible 与 Saltstack 均是基于 Python 语言开发,Ansible 只需要在一台普通的服务器上运行即可,不需要在客户端服务器上安装客户端。因为 Ansible 是基于 SSH 远程管理,而Linux服务器大都离不开SSH,所以Ansible不需要为配置工作添加额外的支持。 Ansible 安装使用非常

    2024年02月01日
    浏览(35)
  • Docker 自动化部署(实践)

    docker search jenkins查看需要的jenkins镜像源 docker pull jenkins/jenkins 拉取jenkins镜像 docker images查看下载的镜像源 docker ps 查看包含启动以及未启动的容器 docker ps -a查看启动的容器 docker rm 容器id/容器名称 删除容器 docker rm -f 容器id/容器名称 删除容器(强制删除容器,运行状态也删除

    2024年02月07日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包