阿里云Kubernetes稳定性最佳实践-阿里云开发者社区

开发者社区> 阿里云容器服务 ACK> 正文

阿里云Kubernetes稳定性最佳实践

简介: Kubernetes很酷,让我们的机器的资源利用率和运维效率都得到了提升。然而,要想用好Kubernetes,还是有些东西要注意的,否则可能会给自己带来一些小麻烦。在生产环境里,如何保证我们的应用能稳定可靠的运行在Kubernetes里呢?这篇文章将分享在阿里云容器服务上使用Kubernetes的一些有用的tips。

Kubernetes很酷,让我们的机器的资源利用率和运维效率都得到了提升。然而,要想用好Kubernetes,还是有些东西要注意的,否则可能会给自己带来一些小麻烦。在生产环境里,如何保证我们的应用能稳定可靠的运行在Kubernetes里呢?这篇文章将分享在阿里云容器服务上使用Kubernetes的一些有用的tips。

Master节点规格

通过容器服务创建出来的Kubernetes集群,Master节点上运行着etcd、kube-apiserver、kube-controller等核心组件,对于Kubernetes集群的稳定性有着至关重要的影响,对于生产环境的集群,必须慎重选择Master规格。Master规格跟集群规模有关,集群规模越大,所需要的Master规格也越大。当然,这里的“集群规模”是个很抽象的词,我们可以从多个维度衡量Kubernetes集群规模:节点数量/Pod数量/部署频率/访问量……这里简单的认为集群规模就是集群里的节点数量。对于常见的集群规模,可以参考这种如下的方式选择Master节点的规格(对于测试环境,规格可以小一些。下面的选择能尽量保证Master负载维持在一个较低的水平上):

  • 1-5个节点,Master规格:4C8G(不建议2C4G)
  • 6-20个节点,Master规格:4C16G
  • 21-100个节点,Master规格:8C32G
  • 100-200个节点,Master规格:16C64G

选择合理的磁盘大小

Kubernetes节点需要的磁盘空间也不小,docker镜像、系统日志、应用日志都保存在磁盘上。创建集群的时候,要考虑每个节点上要部署的Pod数量,每个Pod的日志大小、镜像大小、临时数据,再加上一些系统预留的值。

创建出来的ECS,OS占了大约3G多的空间,我们可以给它多留点,算8G。剩下的空间都可以用在Pod上。

使用多可用区

阿里云支持很多Region,每个Region下又有不同的可用区。可用区是指在同一地域内,电力和网络互相独立的物理区域。多可用区能够实现跨地域的容灾能力。当然,响应的会带来额外的网络延时。创建Kubernetes集群时,也可以创建一个包含多个可用区的集群。在容器服务集群创建页面,点击“创建Kubernetes”按钮右边的小三角可以看到。

Screen_Shot_2018_05_31_at_4_51_59_PM

声明每个Pod的resource

我最经常遇到的Kubernetes问题,就是一个节点上调度了太多的Pod,导致节点负载太高,完全没法对外提供服务。怎么避免这种情况出现呢?

在Kubernetes中部署Pod时,你可以指定这个Pod需要的资源,Kubernetes在部署这个Pod的时候,就会根据Pod的需求找一个具有充足空闲资源的节点部署这个Pod。下面的例子中,声明tomcat这个Pod需要0.25核CPU,64M的内存,运行中实际使用不能超过0.5核CPU和128M内存。

apiVersion: v1
kind: Pod
metadata:
  name: tomcat
spec:
  containers:
  - name: tomcat
    image: tomcat
    resources: # 资源声明
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Kubernetes采用静态资源调度方式,对于每个节点上的剩余资源,它是这样计算的:节点剩余资源=节点总资源-已经分配出去的资源,并不是实际使用的资源。如果你自己偷偷跑到节点上手工运行一个很耗资源的程序,Kubernetes并不能感知到。

另外所有Pod上都要声明resources。对于没有声明resources的Pod,它被调度到某个节点后,Kubernetes也不会在对应节点上扣掉这个Pod使用的资源。可能会导致节点上调度过去太多的Pod

配置监控

在Pod上配置了resource很大程度了避免了节点堆积太多Pod的问题,然而还不够。我们还可以再加一道保险:配置节点监控。通过添加监控告警规则,节点上的资源使用使用量很高的时候,我们可以知道出问题了。

通过容器服务创建Kubernetes集群时,会自动在云监控创建两个应用分组,一个对应Master节点,一个对应Worker节点。我们可以在这两个组下面添加一些报警规则,对组里所有的机器生效。后续加入的节点,也会自动出现在组里,不用单独再去配置报警规则。

Screen_Shot_2018_05_31_at_6_40_49_PM

主要配置ECS资源的报警规则就可以了。

Screen_Shot_2018_05_31_at_6_49_38_PM

启动时等待下游服务,不要直接退出

应用或多或少都有一些外部依赖,比如需要从db读取数据或者依赖另外一个服务的接口。应用启动的时候,未必外部依赖都能满足,过去手工运维的时候,通常采用依赖不满足立即退出的方式,也就是所谓的failfast,但是在Kubernetes中,这种策略就未必合适了。原因何在?Kubernetes中多数运维操作都是自动的,不需要人工介入,比如部署应用,你不用自己选择节点,再到节点上启动应用,应用挂了,也不用自己跑过去重启,Kubernetes会自动把应用拉起来,负载高了,还可以通过HPA自动扩容。

针对启动时依赖不满足这个场景,假设有两个应用A和B,A依赖B,刚好运行在同一个节点上。这个节点因为某些原因重启了,重启之后,A先被拉起来了,这个时候B还没启动,对A来说就是依赖不满足。如果A还是按照传统的方式直接退出了A,当B启动之后,A也不会再被拉起了,必须人工介入处理才行。

Kubernetes的最好的做法是启动时检查依赖,如果不满足,轮询等待,而不是直接退出。可以通过 Init Container完成这个功能。

配置restart policy

Pod运行过程中进程退出是个很常见的问题,无论是代码里的一个bug,还是占用内存太多被OOM killer干掉,都会导致应用进程退出,Pod挂掉。Pod退出了怎么办?既然用了Kubernetes,就不要再用手工重启这种很low的方式了,只要在Pod上配置restartPolicy,就能实现Pod挂掉之后自动拉起。

apiVersion: v1
kind: Pod
metadata:
  name: tomcat
spec:
  containers:
  - name: tomcat
    image: tomcat
    restartPolicy: OnFailure # 

restartPolicy有三个可选值

  • Always: 总是自动重启
  • OnFailure:异常退出才自动重启 (进程退出状态非0)
  • Never:永远不重启

配置Liveness Probe和Readiness Probe

Pod处于Running状态和Pod能正常提供服务是完全不同的概念,一个Running状态的Pod,里面的进程可能发生了死锁而无法提供服务。但是因为Pod还是Running的,Kubernetes也不会自动重启这个Pod。所以我们要在所有Pod上配置Liveness Probe,探测Pod是否真的存活,是否还能提供服务。如果Liveness Probe发现了问题,Kubernetes会重启Pod。

Readiness Probe用于探测Pod是不是可以对外提供服务了。应用启动过程中需要一些时间完成初始化,在这个过程中是没法对外提供服务的,通过Readiness Probe,我们可以告诉Ingress或者Service能不能把流量转发给这个Pod上。当Pod出现问题的时候,Readiness Probe能避免新流量继续转发给这个Pod。

apiVersion: v1
kind: Pod
metadata:
  name: tomcat
spec:
  containers:
  - name: tomcat
    image: tomcat
    livenessProbe:
      httpGet:
        path: /index.jsp
        port: 8080
      initialDelaySeconds: 3
      periodSeconds: 3
    readinessProbe:
      httpGet:
        path: /index.jsp
        port: 8080

每个进程一个容器

很多刚刚接触容器的人喜欢按照老习惯把容器当虚拟机用,在一个容器里塞入多个进程,监控进程、日志进程、sshd进程、甚至整个Systemd。这种方式有什么问题呢?首先,判断Pod整体的资源占用会变复杂,不方便实施前面提到resource limit。其次,容器内只有一个进程的情况,进程挂了,外面的容器引擎可以清楚的感知到,然后重启容器,如果容器内有多个进程,某个进程挂了,容器未必受影响,外部的容器引擎感知不到容器内进程挂了,也不会对容器做任何操作,但是容器实际上已经不能正常工作了。

如果确实有几个进程需要协同工作,在Kubernetes里也很容易实现,举个例子,nginx和php-fpm,通过unix domain socket通信,我们可以用一个包含两个容器的Pod,unix socket放在两个容器的共享volume中。

确保不存在SPOF

如果应用只有一个实例,当实例挂掉的时候,虽然Kubernetes能够将实例重新拉起,但是中间不可避免的存在一段时间的不可用。甚至更新应用,发布一个新版本的时候,也会出现这种情况。在Kubernetes里,尽量避免直接使用Pod,尽可能使用Deployment/StatefulSet,并且让应用的scale在两个以上。

版权声明:本文中所有内容均属于阿里云开发者社区所有,任何媒体、网站或个人未经阿里云开发者社区协议授权不得转载、链接、转贴或以其他方式复制发布/发表。申请授权请邮件developerteam@list.alibaba-inc.com,已获得阿里云开发者社区协议授权的媒体、网站,在转载使用时必须注明"稿件来源:阿里云开发者社区,原文作者姓名",违者本社区将依法追究责任。 如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
阿里云容器服务 ACK
使用钉钉扫一扫加入圈子
+ 订阅

云端最佳容器应用运行环境,安全、稳定、极致弹性

官方博客
官网链接