kubernetes Service与SpringBoot应用启动参数冲突

上下文

  1. 部署Springboot应用到kubernetes集群
  2. 创建了名为"server"的Service

描述

1.部署到kubernetes集群时,原因容器报错日志如下

```bash
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'tcp://192.168.1.55:8080'; nested exception is java.lang.NumberFormatException: For input string: "tcp://192.168.1.55:8080"
```

2.当单独使用Docker部署时,则不报错

3.报错表现为SpringBoot框架无法将字符串“tcp://192.168.1.55:8080”转换为数字类型

原因

  1. SpringBoot应用会读取POD中系统环境变量"SERVER_PORT"的值作为应用监听的端口,值应为数字类型

  2. 而当该应用在kubernetes中的Service名字命名为"server"时,kubernetes会默认在该命名空间下所有的POD中注入一个名叫"SERVER_PORT=tcp://service-ip地址:镜像Dockerfile暴露出来的端口"环境变量(该值为字符类型,报错示例中的为"SERVER_PORT=tcp://192.168.1.55:8080")来进行POD间的服务发现

解决方案

  1. 禁止SpringBoot应用部署在kubernetes中的Service名字命名为“server”,建议命名为“项目名-应用名”
  2. 在部署Deployment声明文件中添加"SERVER_PORT=8080"进行覆盖默认值

附录: Kubernetes中的服务发现

创建Pod资源时,kubelet会将其所属名称空间内的每个活动的Service对象以一系列环境变量的形式注入其中。它支持使用Kubernetes Service环境变量以及与Docker的links兼容的变量。

简单来说,服务发现就是服务或者应用之间互相定位的过程。不过,服务发现并非什么新概念,传统的单体应用架构时代也会用到,只不过单体应用的动态性不强,更新和重新发布频度较低,通常以月甚至以年计,基本不会进行自动伸缩,因此服务发现的概念无须显性强调。在传统的单体应用网络位置发生变化时,由IT运维人员手工更新一下相关的配置文件基本就能解决问题。但在微服务应用场景中,应用被拆分成众多的小服务,它们按需创建且变动频繁,配置信息基本无法事先写入配置文件中并及时跟踪反映动态变化,服务发现的重要性便随之凸显。

服务发现机制的基本实现,一般是事先部署好一个网络位置较为稳定的服务注册中心(也称为服务总线),服务提供者(服务端)向注册中心注册自己的位置信息,并在变动后及时予以更新,相应地,服务消费者则周期性地从注册中心获取服务提供者的最新位置信息从而“发现”要访问的目标服务资源。复杂的服务发现机制还能够让服务提供者提供其描述信息、状态信息及资源使用信息等,以供消费者实现更为复杂的服务选择逻辑。

实践中,根据其发现过程的实现方式,服务发现还可分为两种类型:客户端发现和服务端发现。

客户端发现:由客户端到服务注册中心发现其依赖到的服务的相关信息,因此,它需要内置特定的服务发现程序和发现逻辑。

服务端发现:这种方式额外要用到一个称为中央路由器或服务均衡器的组件;服务消费者将请求发往中央路由器或者负载均衡器,由它们负责查询服务注册中心获取服务提供者的位置信息,并将服务消费者的请求转发给服务提供者。

由此可见,服务注册中心是服务发现得以落地的核心组件。事实上,DNS可以算是最为原始的服务发现系统之一,不过,在服务的动态性很强的场景中,DNS记录的传播速度可能会跟不上服务的变更速度,因此它不并适用于微服务环境。另外,传统实践中,常见的服务注册中心是ZooKeeper和etcd等分布式键值存储系统。不过,它们只能提供基本的数据存储功能,距离实现完整的服务发现机制还有大量的二次开发任务需要完成。另外,它们更注重数据一致性,这与有着更高的服务可用性要求的微服务发现场景中的需求不太相吻合。

Netflix的Eureka是目前较流行的服务发现系统之一,它是专门开发用来实现服务发现的系统,以可用性目前为先,可以在多种故障期间保持服务发现和服务注册的功能可用,其设计原则遵从“存在少量的错误数据,总比完全不可用要好”。另一个同级别的实现是Consul,它是由HashiCorp公司提供的商业产品,不过还有一个开源基础版本提供。它于服务发现的基础功能之外还提供了多数据中心的部署能力等一众出色的特性。

尽管传统的DNS系统不适于微服务环境中的服务发现,但SkyDNS项目(后来称kubedns)却是一个有趣的实现,它结合古老的DNS技术和时髦的Go语言、Raft算法并构建于etcd存储系统之上,为Kubernetes系统实现了一种服务发现机制。Service资源为Kubernetes提供了一个较为稳定的抽象层,这有点类似于服务端发现的方式,于是也就不存在DNS服务的时间窗口的问题。

Kubernetes自1.3版本开始,其用于服务发现的DNS更新为了kubeDNS,而类似的另一个基于较新的DNS的服务发现项目是由CNCF(Cloud Native Computing Foundation)孵化的CoreDNS,它基于Go语言开发,通过串接一组实现DNS功能的插件的插件链进行工作。自Kubernetes 1.11版本起,CoreDNS取代kubeDNS成为默认的DNS附件。不过,Kubernetes依然支持使用环境变量进行服务发现。

Copyright Curiouser all right reserved,powered by Gitbook该文件最后修改时间: 2020-06-16 21:35:29

results matching ""

    No results matching ""