
主要负责阿里云容器服务产品的底层服务发现系统、集群管理系统的研发,从事容器的持续交付、持续集成的方案的设计与实现。在云计算、分布式系统、图像识别与虚拟现实方向有多年的开发经验。个人博客:abandonzoo.com
前言 弹性伸缩是Kubernetes中比较常用的功能。在Kubernetes中,弹性是分为两个层次的,一个是调度层(Pod)弹性,一个是资源层(Node)弹性。通常会通过HPA、CronHPA、VPA等模型进行Pod的横向或者纵向的伸缩,再通过cluster-autoscaler或者virtual-kubelet进行资源层伸缩。两层之间是通过无法调度的Pod进行解耦,这样设计的好处是两层职责明确,坏处是解耦后相互结合的策略过于简单,一旦当我们需要更精细的调度策略就无能为力了,因为在Kubernetes中最小的生命周期管理单元是一个Pod,而传统的Kubernetes负载控制器(例如:Deployment、StatefulSet)管理的Pod是共享相同的调度策略的。因此,当你希望控制一个负载在不同资源上的细粒度分配时,就无能为力了。然而这种场景又是在弹性伸缩中经常遇到的。因此,为了解决应用负载弹性场景下精细化调度的诉求,kubernetes-elastic-workload应运而生了。 弹性伸缩精细化调度的问题分析 假设:有一个应用经过容量规划,预计最多有4个副本运行在ECS上,平时低峰时保留2个副本,超过4个副本的场景弹性伸缩到虚拟节点,防止干扰其他正常容量规划的应用。 在Kubernetes中,任何一种负载都要解决两个问题,一个是调度问题,一个是生命周期管理问题。要想实现上面描述的场景,我们核心要解决的问题是两个: 如何控制副本到达一个数目后,调度策略的变化。 如何在生命周期管理时,优先处理某些Pod。 弹性负载kubernetes-elastic-workload介绍 接下来,我们针对上面的问题介绍下弹性负载的使用方式与解决方法。 # 一个简单的应用,默认使用2副本 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment-basic labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 那么这个场景如何用弹性负载表达呢? # 弹性负载定义 apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: ElasticWorkload metadata: name: elasticworkload-sample spec: sourceTarget: name: nginx-deployment-basic kind: Deployment apiVersion: apps/v1 min: 2 max: 4 replicas: 6 elasticUnit: - name: virtual-kubelet labels: virtual-kubelet: "true" annotations: virtual-kubelet: "true" nodeSelector: type: "virtual-kubelet" tolerations: - key: "virtual-kubelet.io/provider" operator: "Exists" # min: 0 每个单元也可以指定自己的上下限 # max: 10 上面就是这个场景的弹性负载定义,弹性负载的使用方式特别像HPA,他是通过外部挂载的方式使用,对原有的业务无侵入。一个典型的弹性负载主要分为两个部分: SourceTarget部分主要定义原始负载的类型、副本数目可变化的范围。 elasticUnit部分是一个数组,定义弹性单元的调度策略,如果有多个弹性单元,则按照模板的顺序定义。 在上面的例子中,SourceTarget的副本上下限位2-4,表示当ElasticWorkload的replicas为2-4个副本时,会分配到sourceTarget,当超过4个副本时,会分为给弹性单元virtual-kubelet,而在弹性单元virtual-kubelet中可以定义这个单元所独有的调度策略,包含label、annotation、nodeSelector、affinity、toleration等。 简单的理解就是,弹性负载会监听原始负载,并根据弹性单元设定的调度策略,克隆并生成弹性单元的负载,并且根据弹性负载中副本的变化,动态的分配原始负载和弹性单元上面的副本数目。执行弹性负载模板后,我们可以通过命令行查看当前的状态,其中status中的每个单元的Desired Replicas表示弹性负载的分配副本数目。 kubectl describe ew elasticworkload-sample # same as kubectl get elasticworkload Name: elasticworkload-sample Namespace: default Labels: <none> Annotations: <none> API Version: autoscaling.alibabacloud.com/v1beta1 Kind: ElasticWorkload Metadata: Creation Timestamp: 2020-05-06T03:43:41Z Generation: 27 Resource Version: 20635284 Self Link: /apis/autoscaling.alibabacloud.com/v1beta1/namespaces/default/elasticworkloads/elasticworkload-sample UID: 0e9205ff-38b8-43b7-9076-ffa130f26ef4 Spec: Elastic Unit: Annotations: Virtual - Kubelet: true Labels: Virtual - Kubelet: true Name: demo Node Selector: Type: virtual-kubelet Tolerations: Key: virtual-kubelet.io/provider Operator: Exists Replicas: 6 Source Target: API Version: apps/v1 Kind: Deployment Max: 2 Min: 0 Name: nginx-deployment-basic Status: Elastic Units Status: Desired Replicas: 4 Name: nginx-deployment-basic-unit-virtual-kubelet Update Timestamp: 2020-05-07T12:38:27Z Replicas: 6 Selector: app=nginx Source Target: API Version: apps/v1 Desired Replicas: 2 Kind: Deployment Name: nginx-deployment-basic Update Timestamp: 2020-05-07T12:38:27Z Events: <none> 当我们下发弹性负载的模板后,可以查看Pod的情况。可以发现弹性负载克隆出了新的Deployment与Pod,并且Deployment的Pod副本数目是根据上述的规则进行动态分配的。 kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-basic-7ff9955f89-djxwv 1/1 Running 0 138m 172.20.1.151 cn-hangzhou.10.0.5.212 <none> <none> nginx-deployment-basic-7ff9955f89-hrw2z 1/1 Running 0 138m 172.20.1.27 cn-hangzhou.10.0.5.208 <none> <none> nginx-deployment-basic-unit-demo-8bb586568-4f8xt 1/1 Running 0 138m 10.1.76.63 virtual-node-eci-1 <none> <none> nginx-deployment-basic-unit-demo-8bb586568-bl5pd 1/1 Running 0 138m 10.1.76.65 virtual-node-eci-0 <none> <none> nginx-deployment-basic-unit-demo-8bb586568-ndbp8 1/1 Running 0 138m 10.1.76.64 virtual-node-eci-0 <none> <none> nginx-deployment-basic-unit-demo-8bb586568-vx9jx 1/1 Running 0 138m 10.1.76.62 virtual-node-eci-2 <none> <none> 此外,弹性负载也支持与HPA配合使用,可以将HPA作用在弹性负载上,如下图,弹性负载会根据HPA的状态动态调整每个单元的副本分布,例如如果当前是从6个副本缩容到4个副本,那么会优先将弹性单元的副本进行缩容。 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: elastic-workload-demo namespace: default spec: scaleTargetRef: apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: ElasticWorkload name: elasticworkload-sample minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 总结一下,首先弹性负载是通过克隆和覆写调度策略的方式生成多个Deployment,实现了调度策略的管理。其次,通过上层的副本计算,调整原始负载和弹性单元的副本分配,实现了针对一部分Pod的优先处理。从而解决了上述的问题。 弹性负载的安装与使用 弹性负载在阿里云容器服务控制台已经默认集成,可以通过应用市场进行安装,在应用目录中搜索ack-kubernetes-elastic-workload即可。 无需修改参数,点击创建即可。 最后 弹性负载所能解决的问题还远不止文中提到的这些,如果我们从更抽象的角度来看到弹性负载,实际上,弹性负载主要是解决了精细化调度和控制器顺序的问题,因此开发者可以基于弹性负载在例如故障恢复、可用区容灾等等场景下进行进一步的开发和使用。在下一篇文章中,我们会来介绍弹性负载的弹性策略,如何通过弹性策略的设置实现容灾。
前言 在之前的文章中,我们介绍了kubernetes-cronhpa-controller是如何通过设置定时的方式触发容器的水平副本伸缩,但是在实际的场景下,虽然定时伸缩对于负载有规律的应用比较友好,但是应用为了防止突发的流量冲击,还是会配置HPA来做最后的保障的。那么CronHPA与HPA之间该怎么选择呢? 定时伸缩组件兼容HPA 在抉择什么时候需要CronHPA,什么时候使用HPA的时候,我们在思考是否可以将CronHPA与HPA一起使用,如果一起使用会有什么需要解决的问题呢?首先我们先看CronHPA的模板定义 apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: CronHorizontalPodAutoscaler metadata: labels: controller-tools.k8s.io: "1.0" name: cronhpa-sample spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-deployment-basic jobs: - name: "scale-down" schedule: "30 */1 * * * *" targetSize: 1 - name: "scale-up" schedule: "0 */1 * * * *" targetSize: 3 在CronHPA中是通过scaleTargetRef字段来获取伸缩对象的,并通过jobs的crontab规则定时伸缩实例的副本。 那么我们再来看下HPA的模板定义 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: php-apache spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-deployment-basic minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 HPA也是通过scaleTargetRef来定义伸缩的对象,并通过资源利用率来判断伸缩的情况。如果同时设置CronHPA与HPA,那么就会出现HPA与CronHPA同时操作一个scaleTargetRef的场景,而两者之间又相互独立无法感知,这样就会出现两个controller各自工作,后执行的会覆盖先执行的结果。 这个问题的本质是两个controller无法相互感知,从而造成了异常,当回过头来看这个问题的时候,其实我们可以发现HPA早期也有同样的问题,开发者如果希望通过用两个监控指标同时作用到HPA的时候,如果设置两个HPA对象,会出现类似的问题,在解决这个问题的时候,是通过在HPA对象中定义metrics字段,将多个metrics合并到一个HPA对象中来实现的,例如: apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: php-apache spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-deployment-basic minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 50 当两个metrics触发弹性的个数不同的时候,会根据稳定性第一的原则,优先弹出更多的副本或者在缩容时保留更多的副本。那么是否CronHPA和HPA也可以通过这个方案进行整合,答案是Yes and No。因为的确可以通过alibaba-cloud-metrics-adapter将定时的数据通过External Metrics的方式进行转换,然后通过HPA中使用External Metrics的方式进行整合和匹配。但是这样会带来的结果就是,我们需要通过HPA的结构去表达CronHPA的规则,然后再通过Metrics Adapter的模型去转换时间信息与副本计算。从模型上来看,这个方式看似兼容了HPA,但是实际上对定时伸缩的可读性、学习成本、出错诊断、审计与离线都带来了新的挑战。 那么是否还有其他的方法可以实现CronHPA与HPA的兼容呢?我们将视角放回scaleTargetRef,还记得HPA是怎么伸缩Deployment的Pod吗,是HPA将Deployment配置在了scaleTargetRef的字段下,然后Deployment通过自身定义查找到了ReplicaSet,在通过ReplicaSet调整了真实的副本数目。那么从这个角度出发,我们有了一个大胆的想法,是否可以将scaleTargetRef设置为HPA对象,然后通过HPA对象来寻找真实的scaleTargetRef。 apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: CronHorizontalPodAutoscaler metadata: labels: controller-tools.k8s.io: "1.0" name: cronhpa-sample spec: scaleTargetRef: apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler name: nginx-deployment-basic-hpa jobs: - name: "scale-down" schedule: "30 */1 * * * *" targetSize: 1 runOnce: true - name: "scale-up" schedule: "0 */1 * * * *" targetSize: 3 runOnce: true 这样设计的好处是,首先CronHPA可以感知HPA当前的状态,明确的知晓HPA的min、max、desired的数值,同时也知道HPA scaleTargetRef所对应的当前replicas。那么本着稳定性原则,我们要如何操控HPA呢? hpa(min/max) cronhpa deployment result 场景 1/10 5 5 hpa(1/10) deployment 5 定时和当前一致,无需变更 1/10 4 5 hpa(1/10) deployment 5 当前高于定时,保留当前副本 1/10 6 5 hpa(6/10) deployment 6 定时高于当前,保留定时副本定时高于HPA下限,修改HPA下限 5/10 4 5 hpa(4/10) deployment 5 定时低于当前,保留当前副本定时低于HPA下限,修改HPA下限 5/10 11 5 hpa(11/11) deployment 11 定时高于当前,保留定时副本定时高于HPA上限,修改HPA上限 如上图所以,CronHPA会通过调整HPA的方式进行感知,CronHPA要达到的副本和当前副本取大值,来判断是否要扩容以及修改HPA的上限。CronHPA要达到的副本和HPA的配置取小值,判断是否要修改HPA的下限。简单而言,CronHPA不会直接调整Deployment的副本数目,而是通过HPA来操作Deployment,这样就可以避免HPA和CronHPA的冲突问题了。 最后 定时伸缩CronHPA和HPA都是在线业务场景下非常重要的功能,不论使用何种的兼容与适配的方式,稳定性第一的原则是不能改变的,开发者如果对CronHPA感兴趣,欢迎提交PR
前言 kube-eventer是Kubernetes社区中针对事件监控、报警、chatOps场景的开源组件,更多信息可以点击查看。在早期的kube-eventer中已经支持了钉钉、微信、slack等即时通信软件机器人的接入,但是每个机器人的演进速度、功能支持有所不同,造成开发者无法在不同的即时通信机器人之间拥有一致性的体验。为了解决这个问题,在最新版本的kube-eventer推出了支持泛化能力的Webhook Sink。开发者可以通过自定义请求地址、鉴权方式、请求体结构等内容支持各种类Webhook的事件离线信道。 功能介绍 新推出的Webhook Sink支持根据事件的Kind、Reason、Level、Namespace进行过滤,支持通过泛化的逻辑将数据离线给自定义Webhook系统、钉钉、微信、贝洽(bear chat)、slack等等。那么如何使用泛化的Webhook来实现上述的逻辑呢?首先我们先来看下Webhook Sink的参数与定义。 --sink=webhook:<WEBHOOK_URL>?level=Warning&namespaces=ns1,ns2&kinds=Node,Pod&method=POST&header=customHeaderKey=customHeaderValue 参数全部声明如下 level - Level of event (optional. default: Warning. Options: Warning and Normal) namespaces - Namespaces to filter (optional. default: all namespaces,use commas to separate multi namespaces, Regexp pattern support) kinds - Kinds to filter (optional. default: all kinds,use commas to separate multi kinds. Options: Node,Pod and so on.) reason - Reason to filter (optional. default: empty, Regexp pattern support). You can use multi reason field in query. method - Method to send request (optional. default: GET)header - Header in request (optional. default: empty). You can use multi header field in query. custom_body_configmap - The configmap name of request body template. You can use Template to customize request body. (optional.) custom_body_configmap_namespace - The configmap namespace of request body template. (optional.) 其中level、namespaces、kinds、reason都是用来过滤的Filter,其中reson是支持正则的,可以通过标准的正则表达式提供更强大的过滤能力,并且reason可以在参数中设置多条,例如reaon=(a|b)&reson=(c|d)。默认情况下webhook的body为 { "EventType": "{{ .Type }}", "EventKind": "{{ .InvolvedObject.Kind }}", "EventReason": "{{ .Reason }}", "EventTime": "{{ .EventTime }}", "EventMessage": "{{ .Message }}" } 开发者可以通过解析这个Json格式的Body获取事件的内容,此外开发者也可以通过custom_body_configmap与custom_body_configmap_namespace字段进行自定义设置。其中configmap的结构如下,默认kube-eventer会从configmap的content字段中获取Body的内容。 apiVersion: v1 data: content: >- {"EventType": "{{ .Type }}","EventKind": "{{ .InvolvedObject.Kind }}""EventReason": "{{ .Reason }}","EventTime": "{{ .EventTime }}","EventMessage": "{{ .Message }}"} kind: ConfigMap metadata: name: custom-webhook-body namespace: kube-system 泛化Webhook配置例子 具体配置与效果如下 钉钉 参数例子 --sink=webhook:https://oapi.dingtalk.com/robot/send?access_token=token&level=Normal&kinds=Pod&header=Content-Type=application/json&custom_body_configmap=custom-body&custom_body_configmap_namespace=kube-system&method=POST configmap内容 {"msgtype": "text","text": {"content":"EventType:{{ .Type }}\nEventKind:{{ .InvolvedObject.Kind }}\nEventReason:{{ .Reason }}\nEventTime:{{ .EventTime }}\nEventMessage:{{ .Message }}"},"markdown": {"title":"","text":""}} 显示效果 微信 参数例子 --sink=webhook:http://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=633a31f6-7f9c-4bc4-97a0-0ec1eefa5898&level=Normal&kinds=Pod&header=Content-Type=application/json&custom_body_configmap=custom-body&custom_body_configmap_namespace=kube-system&method=POST configmap内容 {"msgtype": "text","text": {"content": "EventType:{{ .Type }}\nEventKind:{{ .InvolvedObject.Kind }}\nEventReason:{{ .Reason }}\nEventTime:{{ .EventTime }}\nEventMessage:{{ .Message }}"}} slack 参数例子 --sink=webhook:https://hooks.slack.com/services/d/B00000000/XXX?&level=Normal&kinds=Pod&header=Content-Type=application/json&custom_body_configmap=custom-body&custom_body_configmap_namespace=kube-system&method=POST configmap内容 {"channel": "testing","username": "Eventer","text":"EventType:{{ .Type }}\nEventKind:{{ .InvolvedObject.Kind }}\nEventReason:{{ .Reason }}\nEventTime:{{ .EventTime }}\nEventMessage:{{ .Message }}"} 显示效果 贝洽(bear chat) 参数例子 --sink=webhook:https://hook.bearychat.com/=bwIsS/incoming/xxxxxx?kinds=Pod&header=Content-Type=application/json&custom_body_configmap=custom-body&custom_body_configmap_namespace=kube-system&method=POST configmap内容 "text":"EventType:{{ .Type }}\nEventKind:{{ .InvolvedObject.Kind }}\nEventReason:{{ .Reason }}\nEventTime:{{ .EventTime }}\nEventMessage:{{ .Message }}" 显示效果 在容器服务中使用自定义Webhook 容器服务中已经在应用市场中提供了ack-node-problem-detector的Chart,默认提供了kube-eventer和npd的打包与集成。开发者可以通过在Chart中OtherSinks的字段进行自定义Webhook的使用。 最后 泛化Webhook的支持可以让更多的ChatBot无需修改代码即可进行接入,例如本文中未提到的Teams、WhatsApp等等。有兴趣的开发者可以提交案例到Github。
前言 kubernetes-cronhpa-controller是容器服务开源的一款面向Pod水平定时伸缩场景的CRD controller。在本系列的之前文章中已经向大家介绍了kubernetes-cronhpa-controller的基本用法了,今天我们来看下近期kubernetes-cronhpa-controller又增加了哪些新的功能。 新功能介绍 Helm Chart控制台集成一键安装 容器服务控制台增加了kubernetes-cronhpa-controller的Helm Chart的安装方式,提供一键安装的能力,开发者可以通过左侧菜单的应用目录快速集成定时伸缩能力。 单次运行(RunOnce)能力的支持 在kubernetes-cronhpa-controller的设计中,定时能力是通过类似crontab的语法来实现的,语法的格式如下: Field name | Mandatory? | Allowed values | Allowed special characters ---------- | ---------- | -------------- | -------------------------- Seconds | Yes | 0-59 | * / , - Minutes | Yes | 0-59 | * / , - Hours | Yes | 0-23 | * / , - Day of month | Yes | 1-31 | * / , - ? Month | Yes | 1-12 or JAN-DEC | * / , - Day of week | Yes | 0-6 or SUN-SAT | * / , - ? 举几个常见的用法,例如:"* * * 15 11 *"表示每年的11月15日,"* * 8 * * *"表示每天的9点钟等等。但是如果我们只希望明天9点钟运行一次该怎么处理呢?标准的crontab在表达能力上是无法实现的,kubernetes-cronhpa-controller在定时任务的定义上增加了RunOnce字段,实现了这个能力。 apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: CronHorizontalPodAutoscaler metadata: labels: controller-tools.k8s.io: "1.0" name: cronhpa-sample spec: scaleTargetRef: apiVersion: apps/v1beta2 kind: Deployment name: nginx-deployment-basic jobs: - name: "scale-up" schedule: "* * 8 * * *" targetSize: 10 runOnce: true - name: "scale-down" schedule: "* * 11 * * *" targetSize: 3 runOnce: true 当runOnce字段设置为true的时候,任务第一次执行完成后,无论成功与失败,这个任务都会停留在当前的状态。runOnce字段的设计更多的是考虑到接入的场景,当你希望通过SDK或者接口进行定时扩容的能力时,runOnce可以帮助你解决time schedule侧的逻辑。 日期过滤(excludeDates)能力的支持 应用有很多种不同的类型,有在线应用类型的,有离线任务类型的,他们的资源使用画像也是各不相同。很多行业领域的应用资源画像是非常独特的,比较有代表性的是游戏、证券等行业。例如:证券行业工作日上午9:30-11:30,下午13:00-15:00为交易时间,国家法定节假日休市。其他的时间,只能查询不提供交易。对于这个场景而言,工作日的周期性负载画像很明确,而法定节假日基本等同于波谷。那么kubernetes-cronhpa-controller要如何支持这个能力呢?kubernetes-cronhpa-controller在Spec中增加了excludeDates的字段,提供日期排除过滤功能。 例如,我们给一个定时伸缩的任务过滤十一的七天法定假期,Yaml如下: apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: CronHorizontalPodAutoscaler metadata: labels: controller-tools.k8s.io: "1.0" name: cronhpa-sample spec: scaleTargetRef: apiVersion: apps/v1beta2 kind: Deployment name: nginx-deployment-basic excludeDates: - "* * * 1-7 10 *" # exclude November 15th jobs: - name: "scale-up" schedule: "* 30 8 * * 1-5" targetSize: 50 - name: "scale-down" schedule: "* 30 10 * * 1-5 " targetSize: 5 其中excludeDates字段为一个数组,可以增加更多其他的过滤日期。这样一个典型的有过滤条件的定时伸缩能力就完成。 最后 kubernetes-cronhpa-controller的项目地址是https://github.com/AliyunContainerService/kubernetes-cronhpa-controller,非常欢迎大家提交issues和pr。
前言 Ingress Controller(Nginx)是深受Kubernetes开发者欢迎的接入层网关方案,具有功能丰富、配置简单等特点,特别是对于从前使用Nginx的开发者而言,可以快速掌握驾轻就熟。 当服务对外的流量被Ingress Controller统一接管后,如何更好的运维管理Ingress Controller,成为了很多运维开发者需要关心的重要内容。通常运维一个网关型的产品,我们需要关心的整体的流量状况、请求的时延、DAU的分布等等。在之前的文章中,向大家介绍了如何通过SLS进行Ingress的流量可视化,今天我们会介绍如何消费采集上来的这些Ingress指标,并实现一条完整的弹性闭环。 HPA云指标的数据源 - alibaba-cloud-metrics-adapter 当通过SLS将Ingress的请求日志进行采集、分析并展现为数据大盘后,一些单位时间PV很高(QPS高)、部分接口时延很长的应用都无处遁形,有经验的运维同学会根据具体的场景进行应用的调优,例如内核参数的调优,网关配置的调优等等,同时对于RT较高的应用同时也会增加相应的副本数,提高应用的响应速度。那么是否有自动的方式可以将这些对副本的调整进行标准化呢? 这里我们就要引出今天的主角alibaba-cloud-metrics-adapter了,在Kubernetes中,监控数据除了用来展现具体的指标和数据,还有一个重要的用途就是通过HPA进行数据消费。为了满足开发者不同层次的监控需求,Kubernetes定义了三种不同的监控数据接口,分别是Resource Metric,Custom Metric以及External Metric。Resource Metric通常是Metrics-Server进行采集的,提供的主要是Pod、Node、Namespcae等Kubernetes中内置逻辑对象的监控;Custom Metric顾名思义是客户自定义的监控指标,通常是通过Prometheus进行采集,在通过HPA进行消费;External Metric主要针对外部指标,通常是面向云场景的,例如如果希望在Kubernetes集群中获取SLB的最大连接数作为弹性指标或者其他云服务的监控指标,那么通常是通过云厂商的External Metric实现来提供的。 alibaba-cloud-metrics-adapter也不例外,目前提供了SLB、SLS(Ingress)、云监控等指标的透出,开发者可以通过alibaba-cloud-metrics-adapter使用云指标进行HPA。今天的例子,我们主要是通过alibaba-cloud-metrics-adapter实现Ingress指标的HPA。 使用Ingress QPS与RT指标进行弹性伸缩 步骤一:安装alibaba-cloud-metrics-adapter 在容器服务的应用目录中选择ack-alibaba-cloud-metrics-adapter,选择需要安装的集群,点击创建进行安装。 步骤二:创建一个通过Ingress暴露服务的应用 首先,我们创建一个应用,并暴露一个ClusterIP的Service。 apiVersion: apps/v1beta2 # for versions before 1.8.0 use apps/v1beta1 kind: Deployment metadata: name: nginx-deployment-basic labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: ClusterIP 通过控制台将刚才创建的Service,通过Ingress的方式进行暴露。 此时,我们可以通过生成的Ingress地址进行访问,确认部署的应用已经可以对外服务。 步骤三:使用PTS进行压力测试 PTS是阿里云上的一款压力测试的工具,提供一键压测的能力,开发者只需简单的配置,即可实现大部分通用场景的压测,今天我们测试的场景比较简单,使用PTS的快速压测即可。 压测配置中,我们设置最大并发为20,设置压测时长为10分钟,点击右上角保存去压测。 此时可以在PTS中查看到当前的QPS状态如下图所示。 在Ingress Dashboard中,我们可以实时看到对应路由的数据盯屏。 步骤四:设置HPA进行弹性伸缩 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: ingress-hpa spec: scaleTargetRef: apiVersion: apps/v1beta2 kind: Deployment name: nginx-deployment-basic minReplicas: 2 maxReplicas: 10 metrics: - type: External external: metric: name: sls_ingress_qps selector: matchLabels: sls.project: "k8s-log-c550367cdf1e84dfabab013b277cc6bc2" sls.logstore: "nginx-ingress" sls.ingress.route: "default-nginx-80" target: type: AverageValue averageValue: 10 - type: External external: metric: name: sls_ingress_latency_p9999 selector: matchLabels: # default ingress log project is k8s-log-clusterId sls.project: "k8s-log-c550367cdf1e84dfabab013b277cc6bc2" # default ingress logstre is nginx-ingress sls.logstore: "nginx-ingress" # namespace-svc-port sls.ingress.route: "default-nginx-80" target: type: Value # sls_ingress_latency_p9999 > 10ms value: 10 sls_ingress_qps与sls_ingress_latency_p9999是本次伸缩使用的两个指标,在target的type中,我们为sls_ingress_qps设置的是AverageValue,表示QPS要除以Pod的数目进行判断。而sls_ingress_latency_p9999这个指标使用时,我们使用的是Value,表示无需除以Pod的数目,这两种不同的type会在HPA的设置中经常用到。 其他HPA的配置主要涉及如下三个参数: sls.project: "k8s-log-c550367cdf1e84dfabab013b277cc6bc2" sls.logstore: "nginx-ingress" sls.ingress.route: "default-nginx-80" sls.project是指创建集群时开启日志服务的project地址,sls.logstore默认为nginx-ingress,sls.ingress.route是指具体要进行观测的路由,规则为namespace-svc-port。 设置好HPA后,我们通过命令行kubectl describe hpa ingress-hpa进行伸缩状态的检查。 Name: ingress-hpa Namespace: default Labels: <none> Annotations: <none> CreationTimestamp: Fri, 09 Aug 2019 23:31:07 +0800 Reference: Deployment/nginx-deployment-basic Metrics: ( current / target ) "sls_ingress_qps" (target average value): 8223m / 10 "sls_ingress_latency_p9999" (target value): 7 / 10 Min replicas: 2 Max replicas: 10 Deployment pods: 9 current / 9 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ScaleDownStabilized recent recommendations were higher than current one, applying the highest recent recommendation ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from external metric sls_ingress_qps(&LabelSelector{MatchLabels:map[string]string{sls.ingress.route: default-nginx-80,sls.logstore: nginx-ingress,sls.project: k8s-log-c550367cdf1e84dfabab013b277cc6bc2,},MatchExpressions:[],}) ScalingLimited False DesiredWithinRange the desired count is within the acceptable range Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 18s horizontal-pod-autoscaler New size: 4; reason: external metric sls_ingress_qps(&LabelSelector{MatchLabels:map[string]string{sls.ingress.route: default-nginx-80,sls.logstore: nginx-ingress,sls.project: k8s-log-c550367cdf1e84dfabab013b277cc6bc2,},MatchExpressions:[],}) above target Normal SuccessfulRescale 12s horizontal-pod-autoscaler New size: 8; reason: external metric sls_ingress_qps(&LabelSelector{MatchLabels:map[string]string{sls.ingress.route: default-nginx-80,sls.logstore: nginx-ingress,sls.project: k8s-log-c550367cdf1e84dfabab013b277cc6bc2,},MatchExpressions:[],}) above target Normal SuccessfulRescale 7s horizontal-pod-autoscaler New size: 9; reason: 可以发现Pod已经正常伸缩,这样一个应用基于Ingress QPS的伸缩就已经完成。 最后 alibaba-cloud-metrics-adapter已经正式开源,更多的伸缩指标和参数配置,可以访问github仓库获取更多信息,同业也欢迎开发者提交issue与PR。
2019年11月
2019年08月
RDC本身是可以和容器服务打通的,容器服务是钉钉云的基础服务
可以提交工单给HPC的团队,目前有多重的计费策略
阿里云网盘是哪个产品?
目前还没有单次使用的功能
是什么流水线,CodePipeline支持所有的ECS或者非ECS主机类型
需要安装插件,插件的搜查方式可以参考报错的类名
是没有eip的意思吗
是跨域的问题吗
看上面第一个错是超时,应该是业务逻辑没有超时处理,第二个错是异步的时候出错,都是代码逻辑的问题
可以通过LB路由的方式进行配置,使用方式和简单路由类似,可以使用随机端口
NLP,可以找下分词的包
并发可能比较高,可以考虑联系阿里云的架构师,帮你做做架构
在公众号后台绑定服务器ip即可
没有授权,另外你的命令怎么是在宿主机上执行的。
如果是RDS需要创建用户密码才可以
可以提交工单,或者重置密码
提交工单,投诉,人工电话都可以
一口价的都是可以直接秒的吧
这个是自己设置的
可以通过重置密码或者VNC重置