Kubernetes的抗脆弱性

2018-03-21 09:50:00
Bartłomiej Antoniak
转贴:
infoq
6339

许多工程师都有很乐观的想法:让服务完美进行。他们在一开始就考虑好最终情况,不去想一些可能引起灾难的变化或不可预测的事件,也就无法从这些变化和不可预测性中获利,使服务变得更好。

那么问题来了,我们如何才能利用好不稳定性,随机性和无序性?

有很多抗脆弱性相关的 博客,但其中少有涉及现有技术的。这里我们把所有东西打包一下。

抗脆弱性

抗脆弱性这个词最先由Nassim Nicholas Taleb在他的书《Antifragile: Things That Gain from Disorder》中首次引入。


有些事物从冲击中受益,当面对不稳定性、随机性、无序性和压力源的时候,它们能生长繁荣;它们热爱冒险、风险和不确定性。然而,尽管这种现象很普遍,却没有一个说法能准确描述脆弱的反面。我们就管它叫抗脆弱性吧。抗脆弱性不仅仅是指弹性和稳健性,有弹性的事物能抵抗冲击保持原样,而抗脆弱的事物却能利用冲击变得更好。

Kubernetes的抗脆弱性

如何量化服务的脆弱性?服务失败了会发生什么?Kubernetes能起到什么作用?

这些问题都关系到抗脆弱性的几个关键概念。

简易性

复杂的系统难以监测和维护。系统越大,变更起来就越难,任何突发事件都可能引起难以追踪和调试的不良后果甚至连锁故障。

Kubernetes提供名为Pod的部署单元。Pod是运行在同一节点上有相同生命周期的容器集合。我们可以假设一个容器负责一个特定事件。

 

apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
    - name: web
      image: nginx
      ports:
      - name: web
        containerPort: 80
        protocol: TCP
    - name: database
      image: postgres
      ports:
      - name: psql
        containerPort: 5432
        protocol: TCP

显然,还有其他种类的Kubernetes资源,比如: 部署DaemonSetStatefulSet等。

可观察性

监测和日志记录是理解服务运行和表现的关键机制,尤其是在类似Kubernetes的动态分布式环境中。

Kubernetes上运行的所有容器都应当在stdout或stderr上记录应用程序输出日志。这能帮助形成独立的存储,并在容器崩溃时能让你及时了解情况。 


I0221 00:40:02.060314 version: 1.14.8
I0221 00:40:02.133217 Using configuration read from directory: /kube-dns-config with period 10s
I0221 00:40:02.133299 FLAG: --alsologtostderr="false"
I0221 00:40:02.133312 FLAG: --config-dir="/kube-dns-config"
I0221 00:40:02.133320 FLAG: --config-map=""
I0221 00:40:02.133325 FLAG: --config-map-namespace="kube-system"
I0221 00:40:02.133331 FLAG: --config-period="10s"
I0221 00:40:02.133338 FLAG: --dns-bind-address="0.0.0.0"
I0221 00:40:02.133344 FLAG: --dns-port="10053"
I0221 00:40:02.133353 FLAG: --domain="cluster.local."
I0221 00:40:02.133361 FLAG: --federations=""
I0221 00:40:02.133368 FLAG: --healthz-port="8081"
I0221 00:40:02.133373 FLAG: --initial-sync-timeout="1m0s"
I0221 00:40:02.133378 FLAG: --kube-master-url=""
I0221 00:40:02.133385 FLAG: --kubecfg-file=""
I0221 00:40:02.133390 FLAG: --log-backtrace-at=":0"
I0221 00:40:02.133400 FLAG: --log-dir=""
I0221 00:40:02.133406 FLAG: --log-flush-frequency="5s"
I0221 00:40:02.133411 FLAG: --logtostderr="true"
I0221 00:40:02.133416 FLAG: --nameservers=""
I0221 00:40:02.133421 FLAG: --stderrthreshold="2"
I0221 00:40:02.133426 FLAG: --v="2"
I0221 00:40:02.133431 FLAG: --version="false"
I0221 00:40:02.133440 FLAG: --vmodule=""
I0221 00:40:02.133520 Starting SkyDNS server (0.0.0.0:10053)
I0221 00:40:02.133827 Skydns metrics enabled (/metrics:10055)
I0221 00:40:02.133836 Starting endpointsController
I0221 00:40:02.133841 Starting serviceController


PrometheusSoundCloud研发的开源监控报警系统。它能和 Grafana一起让你完全了解Kubernetes集群的健康状况。


容忍性和错误


想想自然母亲也没有那么“安全”,她可以肆意摧毁,替换,选择和重组。考虑到完全的稳健性几乎不可能达到,我们需要这样一种机制:它可以从随机事件、不可预测的冲击、压力源以及不稳定性中不断自我更新,而非从中受损。


同样的原则也适用于Kubernetes的环境。当由于某些原因节点死亡,所有的容器都将通过平衡资源利用重新分配到其他健康节点上。

关于容器还有 liveness和readiness探针。Liveliness在应用程序进程无法继续时启动重启,Readiness则用来判断一个容器何时可以开始接受流量。 


apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
    readinessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5


另外一个重要技巧是故障注入,有时也是混沌工程学方法的一部分,能让系统不断演进,避免混沌状态。


混沌工程学这门学科在分布式系统上进行实验,以提升系统容量,在生产中应对混乱状态。
《PRINCIPLES OF CHAOS ENGINEERING》

kube-monkeyNetflix Chaos Monkey在Kubernetes集群中的一个实现。它在鼓励和验证故障恢复服务开发的集群中随机删除Kubernetes的Pod。

去中心化和隔离

分布式系统和生物体很像。心理学上有一种过度补偿机制,指个体不仅要弥补某一方面的不足,实现正常的补偿,还要努力使自己补偿的结果超越普通人,形成一种优势。如果分布式系统也存在过度补偿机制,显然能对突发事件作出更好的响应,再结合适当的隔离,就能限制 爆炸半径


Kubernetes提供 命名空间的概念。可以认为它们是有访问控制策略(基于属性的访问控制( ABAC)或更颗粒化的基于角色的访问控制( RBAC))的区域虚拟集群。 


kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]


具体命名空间也可以通过 网络策略(说明哪些Pod集合可以相互交流以及和其他网络端点交流)限制在网络层。

 

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978


非预期

有时在不确定的情况下很难做决定,比如,为了应对出乎意料的高流量,我们应该分配多少资源?我们需要多少在云中运行的实例?但很遗憾我们无法预测稀少事件的发生。


Kubernetes的一个优点是根据特定情况实现按比例缩放,比如在资源利用中,通过 cluster-autoscaler调整节点数量,包括删除没有被充分利用的节点。



关于应用层的比例缩放,可以使用 Horizontal Pod Autoscaler,它能够根据资源利用或自定义指标自动调整Pod的个数。

总结

最后我们还是诚实一点:完全不脆弱是不可能实现的,但是频繁快速的出现故障能使系统对错误有更强的抵抗力。

为了降低脆弱性,应该不断给部署过程以及在Kubernetes上运行的服务施以压力。


译者:张婵 ,感谢徐川对本文的审校。

发表评论
贰 加 壹 =
评论通过审核后显示。
文章分类
联系方式
联系人: 王春生
Email: chunsheng@cnezsoft.com