Kubernetes之路 3 - 解决服务依赖

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 在容器服务的客户群中,一个经常被问起的问题就是如何处理服务间依赖。本文介绍了常见的解决方法来实现服务的依赖检查,还进一步用示例展示了如何利用init container, liveness/readiness探针等技术实现服务健康检查,依赖检查等等功能。

image

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

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

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

当采用 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 error
    maxAttempts := 20
    for 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/ 一文

image

首先在Pod中有三类容器

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

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

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress
spec:
  ports:
  - name: wordpress
    port: 80
    targetPort: 80
  selector:
    app: wordpress
  type: NodePort
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql 
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ALLOW_EMPTY_PASSWORD
          value: "true"
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping"]
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          exec:
            # Check we can execute queries over TCP (skip-networking is off).
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 2
          timeoutSeconds: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name: wordpress
        image: wordpress:4
        ports:
        - containerPort: 80
        env:
        - name: WORDPRESS_DB_HOST
          value: mysql
        - name: WORDPRESS_DB_PASSWORD
          value: ""
      initContainers:
      - name: init-mysql
        image: busybox
        command: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql; sleep 2; done;']

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

同时,在MySQL StatefulSet中我们也引入了readinessProbelivenessProbe探针,它们会判定是否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的开发者体验,帮助用户关注云端应用价值创新。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
20天前
|
Prometheus Kubernetes 监控
k8s部署针对外部服务器的prometheus服务
通过上述步骤,您不仅成功地在Kubernetes集群内部署了Prometheus,还实现了对集群外服务器的有效监控。理解并实施网络配置是关键,确保监控数据的准确无误传输。随着监控需求的增长,您还可以进一步探索Prometheus生态中的其他组件,如Alertmanager、Grafana等,以构建完整的监控与报警体系。
109 60
|
21天前
|
Prometheus Kubernetes 监控
k8s部署针对外部服务器的prometheus服务
通过上述步骤,您不仅成功地在Kubernetes集群内部署了Prometheus,还实现了对集群外服务器的有效监控。理解并实施网络配置是关键,确保监控数据的准确无误传输。随着监控需求的增长,您还可以进一步探索Prometheus生态中的其他组件,如Alertmanager、Grafana等,以构建完整的监控与报警体系。
127 62
|
29天前
|
Prometheus Kubernetes 监控
k8s学习--kubernetes服务自动伸缩之水平伸缩(pod副本伸缩)HPA详细解释与案例应用
k8s学习--kubernetes服务自动伸缩之水平伸缩(pod副本伸缩)HPA详细解释与案例应用
k8s学习--kubernetes服务自动伸缩之水平伸缩(pod副本伸缩)HPA详细解释与案例应用
|
26天前
|
负载均衡 Kubernetes 区块链
随机密码生成器+阿里k8s负载均衡型服务加证书方法+移动终端设计+ico生成器等
随机密码生成器+阿里k8s负载均衡型服务加证书方法+移动终端设计+ico生成器等
47 1
|
29天前
|
Kubernetes 应用服务中间件 nginx
k8s学习--kubernetes服务自动伸缩之水平收缩(pod副本收缩)VPA策略应用案例
k8s学习--kubernetes服务自动伸缩之水平收缩(pod副本收缩)VPA策略应用案例
|
29天前
|
Kubernetes 监控 调度
k8s学习--kubernetes服务自动伸缩之垂直伸缩(资源伸缩)VPA详细解释与安装
k8s学习--kubernetes服务自动伸缩之垂直伸缩(资源伸缩)VPA详细解释与安装
|
29天前
|
Kubernetes 应用服务中间件 nginx
k8s基础使用--使用k8s部署nginx服务
本文介绍了Kubernetes中核心概念Deployment、Pod与Service的基本原理及应用。Pod作为最小调度单元,用于管理容器及其共享资源;Deployment则负责控制Pod副本数量,确保其符合预期状态;Service通过标签选择器实现Pod服务的负载均衡与暴露。此外,还提供了具体操作步骤,如通过`kubectl`命令创建Deployment和Service,以及如何验证其功能。实验环境包括一台master节点和两台worker节点,均已部署k8s-1.27。
111 1
|
3月前
|
运维 Kubernetes 容器
【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client secret keys for app ****** are expired)
【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client secret keys for app ****** are expired)
【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client secret keys for app ****** are expired)
|
3月前
|
Kubernetes 安全 Docker
在K8S中,在服务上线的时候Pod起不来怎么进行排查?
在K8S中,在服务上线的时候Pod起不来怎么进行排查?
|
3月前
|
Kubernetes 网络安全 容器
在K8S中,有个服务使用service的nodeport进行暴露,发现访问不到如何排查?
在K8S中,有个服务使用service的nodeport进行暴露,发现访问不到如何排查?

热门文章

最新文章

相关产品

  • 容器服务Kubernetes版