摘要: 在容器服务的客户群中,一个经常被问起的问题就是如何处理服务间依赖。本文介绍了常见的解决方法来实现服务的依赖检查,还进一步用示例展示了如何利用init container, liveness/readiness探针等技术实现服务健康检查,依赖检查等等功能。

本系列文章记录了企业客户在应用Kubernetes时的一些常见问题

  • 第一篇:Java应用资源限制的迷思
  • 第二篇:利用LXCFS提升容器资源可见性
  • 第三篇:解决服务依赖

在容器服务的客户群中,一个经常被问起的问题就是如何处理服务间依赖。

在应用中,一个组件依赖指定的中间件服务和业务服务。在传统的软件部署方式中,应用启动、停止都要依照特定的顺序完成。

当采用 Kubernetes/Docker Swarm等容器编排技术在分布式环境下部署应用时,一方面不同组件之间并行启动无法保证其启动顺序,另一方面在应用运行时,其所依赖的服务实现有可能发生失败和迁移。如何解决容器之间的服务依赖就是一个非常常见的问题。

方法1 - 应用端服务依赖检查

我们可以在应用的启动逻辑中添加服务依赖检查逻辑,如果应用依赖的服务不可访问就重试,当错误超过一定次数后就自动退出。Kubernetes/Docker会根据所容器的重启策略(Restart Policy)在等待一段时间之后自动拉起。

下面就是一个简单的Golang应用示例,来检测所依赖的MySQL服务是否就绪。

  ...// Connect to database.hostPort := net.JoinHostPort(config.Host, config.Port)log.Println("Connecting to database at", hostPort)dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?timeout=30s",config.Username, config.Password, hostPort, config.Database)db, err = sql.Open("mysql", dsn)if err != nil {log.Println(err)}var dbError errormaxAttempts := 20for attempts := 1; attempts <= maxAttempts; attempts++ {dbError = db.Ping()if dbError == nil {break}log.Println(dbError)time.Sleep(time.Duration(attempts) * time.Second)}if dbError != nil {log.Fatal(dbError)}log.Println("Application started successfully.")...

注: 
"Fail Fast" (快速失败),是Design by Contract契约式设计的一种重要的原则,可以很好地保障系统的健壮性和可预测性。比如上文代码中,如果重试失败,就会由log.Fatal(dbError) 退出执行。而K8S/Docker的容器重启的回退机制可以保障不会因频繁拉起失败应用导致系统资源耗尽。

方法2 - 独立的服务依赖检查逻辑

在现实世界里,有些遗留应用或者框架无法进行调整。我们就会希望将依赖检查策略和应用逻辑进行解耦。

一个常见的方法是在容器的Dockerfile的启动脚本里加入相应的服务依赖检查逻辑,可以参见Docker文档获得更多信息。另一种方法是利用Kubernetes Pod自身机制添加依赖检查逻辑。

首先我们需要对Pod的生命周期有一定的理解,下图来自于 https://blog.openshift.com/kubernetes-pods-life/ 一文

首先在Pod中有三类容器

  • infra container: 这就是著名的pause容器
  • init container: 初始化容器 通常用于应用的初始化准备,只有等所有的初始化容器正常执行完毕之后,才会启动应用容器
  • main container: 应用容器

Kubernetes的最佳实践中,通常是利用初始化容器来进行依赖服务的检查。下面我们通过一个Wordpress的实例来展示其使用方法。

apiVersion: v1
kind: Service
metadata:name: mysql
spec:clusterIP: Noneports:- name: mysqlport: 3306selector:app: mysql
---
apiVersion: v1
kind: Service
metadata:name: wordpress
spec:ports:- name: wordpressport: 80targetPort: 80selector:app: wordpresstype: NodePort
---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: mysql
spec:selector:matchLabels:app: mysqlserviceName: mysql replicas: 1template:metadata:labels:app: mysqlspec:containers:- name: mysqlimage: mysql:5.7env:- name: MYSQL_ALLOW_EMPTY_PASSWORDvalue: "true"livenessProbe:exec:command: ["mysqladmin", "ping"]initialDelaySeconds: 30periodSeconds: 10timeoutSeconds: 5readinessProbe:exec:# Check we can execute queries over TCP (skip-networking is off).command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]initialDelaySeconds: 5periodSeconds: 2timeoutSeconds: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:name: wordpress
spec:replicas: 1selector:matchLabels:app: wordpresstemplate:metadata:labels:app: wordpressspec:containers:- name: wordpressimage: wordpress:4ports:- containerPort: 80env:- name: WORDPRESS_DB_HOSTvalue: mysql- name: WORDPRESS_DB_PASSWORDvalue: ""initContainers:- name: init-mysqlimage: busyboxcommand: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql; sleep 2; done;']

我们在Wordpress Deployment的Pod定义中添加了initContainers,它会通过检查 mysql 域名是否可以解析来判断所依赖的mysql服务是否就绪。

同时,在MySQL StatefulSet中我们也引入了readinessProbe 和 livenessProbe探针,它们会判定是否MySQL进程已经业务就绪。在K8S中,只有健康的Pod才可以通过ClusterIP访问或者DNS解析。

$ kubectl create -f wordpress.yaml
service "mysql" created
service "wordpress" created
statefulset "mysql" created
deployment "wordpress" created
$ kubectl get pods
NAME                         READY     STATUS     RESTARTS   AGE
mysql-0                      0/1       Running    0          5s
wordpress-797655cf44-w4p87   0/1       Init:0/1   0          5s
$ kubectl get pods
NAME                         READY     STATUS     RESTARTS   AGE
mysql-0                      1/1       Running    0          11s
wordpress-797655cf44-w4p87   0/1       Init:0/1   0          11s
$ kubectl get pods
NAME                         READY     STATUS            RESTARTS   AGE
mysql-0                      1/1       Running           0          14s
wordpress-797655cf44-w4p87   0/1       PodInitializing   0          14s
$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
mysql-0                      1/1       Running   0          17s
wordpress-797655cf44-w4p87   1/1       Running   0          17s
$ kubectl describe pods wordpress-797655cf44-w4p87
...

注:

  • Liveness探针:主要用于判断Container是否处于运行状态,比如当服务死锁或者响应缓慢等情况。
  • Readiness探针:主要用于判断服务是否已经正常工作。
  • 在init container中不允许使用readiness探针。
  • 如果Pod重启了,其所有init Container都需重新运行。

总结

本文介绍了常见的解决方法来实现服务的依赖检查,还进一步用示例展示了如何利用init container, liveness/readiness探针等技术实现服务健康检查,依赖检查等等功能。

Kubernetes提供了非常灵活的Pod生命周期管理机制,由于篇幅有限我们就不再展开介绍 postStart/preStop等生命周期钩子方法。

阿里云Kubernetes服务 全球首批通过Kubernetes一致性认证,简化了Kubernetes集群生命周期管理,内置了与阿里云产品集成,也将进一步简化Kubernetes的开发者体验,帮助用户关注云端应用价值创新。

原文链接

干货好文,请关注扫描以下二维码:


Kubernetes之路 3 - 解决服务依赖相关推荐

  1. kubernetes如何解决服务依赖呢?

    在微服务的世界里,任何应用都需要注意,其所依赖的服务是会中断的.所以当应用发现某服务(如数据库)出现了故障,应该每隔一端时间去重试.而上层框架(如k8s)会检测到服务故障,并尝试恢复这个服务. 但在现 ...

  2. Kubernetes之健康检查与服务依赖处理

    本文讲的是Kubernetes之健康检查与服务依赖处理[编者的话]对线上业务来说,保证服务的正常稳定是重中之重,对故障服务的及时处理避免影响业务以及快速恢复一直是开发运维的难点.Kubernetes提 ...

  3. Kubernetes之路 2 - 利用LXCFS提升容器资源可见性

    本系列文章记录了企业客户在应用Kubernetes时的一些常见问题 第一篇:Java应用资源限制的迷思 第二篇:利用LXCFS提升容器资源可见性 第三篇:解决服务依赖 这是本系列的第2篇内容,将介绍在 ...

  4. [KubeCon+CloudNativeCon China 2018] 在Kubernetes上运行区块链服务(BaaS)

    笔者注:本文是在2018年11月15日由Linux基金会CNCF主办的KubeCon & CloudNativeCon China 2018大会的"Running Blockchai ...

  5. 在Kubernetes上运行区块链服务(BaaS)

    本文是在2018年11月15日由Linux基金会CNCF主办的KubeCon & CloudNativeCon China 2018大会的"Running Blockchain as ...

  6. kubernetes 简介:kube-dns 和服务发现

    服务发现 kubernetes 提供了 service 的概念可以通过 VIP 访问 pod 提供的服务,但是在使用的时候还有一个问题:怎么知道某个应用的 VIP?比如我们有两个应用,一个 app,一 ...

  7. 用Docker和Kubernetes将MongoDB作为微服务来运行

    想要在你的手提电脑上尝试MongoDB吗?执行一个命令,然后拥有一个轻量级,独立的沙箱:再执行一个命令,删除你完成之后所有的痕迹.是不是需要一个在多个环境中都跟你的应用程序堆栈一样的应用程序?创建一你 ...

  8. 分布式架构演变之路,微服务、限流、熔断....

    本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件.本文侧重于简明地表达微服务架构的全局图景,因此不会涉及具体如何使用组件等细节. 要理解微服务,首先要先理解不是微服 ...

  9. 和Sidecars说再见,看eBPF如何解决服务网格

    和Sidecars说再见,看eBPF如何解决服务网格 How eBPF will solve Service Mesh - Goodbye Sidecars https://isovalent.com ...

最新文章

  1. 滴滴业务研发的精益实践
  2. linux 日志文件utmp、wtmp、lastlog、messages介绍
  3. jackson的jar包下载
  4. 借助JVM生日的时机,说说关于JVM你所不知道的那些事
  5. Android fastjson
  6. 使用BaaS更快地构建Xamarin应用程序
  7. Android App优化之提升你的App启动速度之实例挑战
  8. linux之iftop命令
  9. leetcode 39. Combination Sum(回溯算法)
  10. iOS APP 比较版本号,检测更新
  11. 未能加载文件或程序集“System.Data.SQLite.DLL”或它的某一个依赖项
  12. PHP高并发高负载下的3种实战场景解决方法
  13. ActiveX:ActiveX控件安装、dllregisterserver的调用失败
  14. 小米8装magisk
  15. Docker-Harbor:推送镜像/登录失败(Error response from daemon: Get https://reg.harbor.com/v2/: dial tcp 192...)
  16. 江南时报:百度有啊命名堪比可口可乐
  17. Android友盟统计
  18. 学计算机需要会拼音吗,不会拼音如何学习电脑?
  19. 追加安装sticky模块
  20. Appium移动端自动化测试--搭建模拟器和真机环境一

热门文章

  1. 【LeetCode笔记】470. 用Rand7()实现Rand10()(Java、概率)
  2. java 编码实现内存拷贝_java提高篇(六)-----使用序列化实现对象的拷贝
  3. php socket keepalive,linux keepalive探测对应用层socket api的影响
  4. ubuntu mysql 初始化_Ubuntu初始化MySQL碰到的坑
  5. python怎么退出调试模式_python – 在验尸调试时如何退出ipdb?
  6. dorado 刷新_dorado7常用内容
  7. AI算法连载19:统计之最大熵算法
  8. 阿里达摩院发布2019年十大科技趋势
  9. 加加减减的奥秘——从数学到魔术的思考(一)
  10. activeMQ发送与接受消息模板代码