Dubbo与Kubernetes集成
Dubbo应用迁移到docker的问题
Dubbo是阿里开源的一套服务治理与rpc框架,服务的提供者通过zookeeper把自己的服务发布上去,然后服务调用方通过zk获取服务的ip和端口,dubbo客户端通过自己的软负载功能自动选择服务提供者并调用,整个过程牵涉到的三方关系如下图所示。
在正常的情况下,这三方都在同一个互通的网段,provider提供给zk的就是获取到的本机地址,consumer能访问到这个地址。
但是假如服务放在docker容器中,而调用者并不在docker中,它们的网段是不一样的。
这个时候就出现问题了,consumer无法访问到provider了。
Dubbo提供的解决方案
新版的Dubbo提供了四个配置来指定与注册服务相关的地址和端口。
DUBBO_IP_TO_REGISTRY: 要发布到注册中心上的地址
DUBBO_PORT_TO_REGISTRY: 要发布到注册中心上的端口
DUBBO_IP_TO_BIND: 要绑定的服务地址(监听的地址)
DUBBO_PORT_TO_BIND: 要绑定的服务端口
以IP地址为例,Dubbo先找是不是有DUBBO_IP_TO_BIND这个配置,如果有使用配置的地址,如果没有就取本机地址。然后继续找DUBBO_IP_TO_REGISTRY,如果有了配置,使用配置,否则就使用DUBBO_IP_TO_BIND。具体代码如下:
/**
* Register & bind IP address for service provider, can be configured separately.
* Configuration priority: environment variables -> java system properties -> host property in config file ->
* /etc/hosts -> default network address -> first available network address
*
* @param protocolConfig
* @param registryURLs
* @param map
* @return
*/
private static String findConfigedHosts(ServiceConfig<?> sc,
ProtocolConfig protocolConfig,
List<URL> registryURLs,
Map<String, String> map) {
boolean anyhost = false;
String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
}
// if bind ip is not found in environment, keep looking up
if (StringUtils.isEmpty(hostToBind)) {
hostToBind = protocolConfig.getHost();
if (sc.getProvider() != null && StringUtils.isEmpty(hostToBind)) {
hostToBind = sc.getProvider().getHost();
}
if (isInvalidLocalHost(hostToBind)) {
anyhost = true;
try {
logger.info("No valid ip found from environment, try to find valid host from DNS.");
hostToBind = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
logger.warn(e.getMessage(), e);
}
if (isInvalidLocalHost(hostToBind)) {
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
// skip multicast registry since we cannot connect to it via Socket
continue;
}
try (Socket socket = new Socket()) {
SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
socket.connect(addr, 1000);
hostToBind = socket.getLocalAddress().getHostAddress();
break;
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}
}
if (isInvalidLocalHost(hostToBind)) {
hostToBind = getLocalHost();
}
}
}
}
map.put(BIND_IP_KEY, hostToBind);
// registry ip is not used for bind ip by default
String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
} else if (StringUtils.isEmpty(hostToRegistry)) {
// bind ip is used as registry ip by default
hostToRegistry = hostToBind;
}
map.put(ANYHOST_KEY, String.valueOf(anyhost));
return hostToRegistry;
}
然后我们看这个getValueFromConfig(),它调用了下面的函数,可以看到,它是先找环境变量,再找properties。
public static String getSystemProperty(String key) {
String value = System.getenv(key);
if (StringUtils.isEmpty(value)) {
value = System.getProperty(key);
}
return value;
}
所以我们通过环境变量,就能修改Dubbo发布到zookeeper上的地址和端口。假如我们通过docker镜像启动了一个dubbo provider,并且它的服务端口是8888,假设主机地址为192.168.1.10,那么我们通过下面的命令,
docker run -e DUBBO_IP_TO_REGISTRY=192.168.1.10 -e DUBBO_PORT_TO_REGISTRY=8888 -p 8888:8888 dubbo_image
就能让内部的服务以192.168.1.10:8888的地址发布。
我们通过官方的实例来演示一下,因为官方提供的案例都很久了,所以我自己重新搞了一个示例,代码在https://github.com/XinliNiu/dubbo-docker-sample.git 。
先启动一个zookeeper,暴露2181端口。
docker run --name zkserver --rm -p 2181:2181 -d zookeeper:3.4.9
看一下zk起来了
niuxinli@niuxinli-B450M-DS3H:~/dubbo-samples-docker$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5efc1f17fba0 zookeeper:3.4.9 "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp zkserver
把代码导入IDE,修改dubbo-docker-provide.xml,把地址改成刚发布到zk的地址和端口,我的地址是192.168.1.8。
运行DubboApplication,这时候可以看到在zk上注册了服务。
修改dubbo-docker-consumer.xml里的zk地址,执行单元测试,能正常访问。
把DubboApplication导出成可以执行的jar包,名字叫app.jar,创建如下Dockerfile
FROM openjdk:8-jdk-alpine
ADD app.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -jar /app.jar
创建dubbo-demo镜像,在同样的目录里执行docker build。
docker build --no-cache -t dubbo-demo .
正常启动镜像
docker run -p 20880:20880 -it --rm dubbo-demo
发现是172.16.0.3的地址,这个是访问不了的。
传入环境变量重新启动,
docker run -e DUBBO_IP_TO_REGISTRY=192.168.1.8 -e DUBBO_PORT_TO_REGISTRY=20880 -p 20880:20880 -it --rm dubbo-demo
这时候就变成主机地址了。
docker run --name zkserver --rm -p 42181:2181 -d zookeeper:3.4.9
看一下zk起来了
niuxinli@niuxinli-B450M-DS3H:~/docker_dubbo_demo/dubbo-samples/dubbo-samples-docker$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5efc1f17fba0 zookeeper:3.4.9 "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 2888/tcp, 3888/tcp, 0.0.0.0:42181->2181/tcp zkserver
现在启动dubbo provider,使用link的方式连接zk,我的本机地址是192.168.1.8,provider自己暴露的端口为20880,主机暴露端口改成28888。
在Kubernetes中使用Dubbo
当在Kubernetes中启动多个副本的时候,指定具体的IP和具体的端口,都是不可行的,因为每个机器的IP都不一样,不能写很多个yaml文件,而且一旦指定了具体端口,那这台主机的这个端口就被占用了。
我们可以通过创建Service,使用NodePort的方式,把端口固定住,这样端口的问题就解决了。因为是对外服务,所以使用ClusterIP肯定是不行了,IP有两种解决办法:
(1)使用Kubernetes的downward api动态的传入主机的ip。
(2)传固定的loadbalancer的地址,例如在所有的node之外有一个F5。
不管哪种方法,都是一种妥协的办法,很不“云原生”,我演示一下使用downward api动态传入主机地址,并使用nodeport固定端口的方式。
我的kubernetes集群如下:
角色 | 地址 |
---|---|
master | 192.168.174.50 |
node1 | 192.168.174.51 |
node2 | 192.168.174.52 |
node3 | 192.168.174.53 |
zk的地址是192.168.1.8,它与集群的主机互通。
我没有建private镜像仓库,把我之前打好的dubbo-demo直接push到docker-hub上了,名字是nxlhero/dubbo-demo。
创建Service,使用的NodePort为30001,创建4个副本,这样3台机器上正好有一台起两个pod。
apiVersion: v1
kind: Service
metadata:
name: dubbo-docker
labels:
run: dubbo
spec:
type: NodePort
ports:
- port: 20880
targetPort: 20880
nodePort: 30001
selector:
run: dubbo-docker
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dubbo-docker
spec:
selector:
matchLabels:
run: dubbo
replicas: 4
template:
metadata:
labels:
run: dubbo
spec:
containers:
- name: dubbo-docker
image: nxlhero/dubbo-demo
env:
- name: DUBBO_IP_TO_REGISTRY
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: DUBBO_PORT_TO_REGISTRY
value: "30001"
tty: true
ports:
- containerPort: 20880
这个yaml最关键的地方就是环境变量,主机IP通过downward apid传入,端口使用固定的nodeport。
env:
- name: DUBBO_IP_TO_REGISTRY
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: DUBBO_PORT_TO_REGISTRY
value: "30001"
创建Service,启动后可以看到zookeeper上的地址都是主机的地址和nodeport。
Dubbo与Kubernetes集成的更多相关文章
- 如何使用Dubbo服务和集成Spring
Dubbo是什么? Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点. Dubbo是一个 ...
- containerd与kubernetes集成
kubernetes集群三步安装 概念介绍 cri (Container runtime interface) cri is a containerd plugin implementation of ...
- zookeeper acl认证机制及dubbo、kafka集成、zooviewer/idea zk插件配置
ZooKeeper的ACL机制 zookeeper通过ACL机制控制znode节点的访问权限. 首先介绍下znode的5种操作权限:CREATE.READ.WRITE.DELETE.ADMIN 也就是 ...
- CRI 与 ShimV2:一种 Kubernetes 集成容器运行时的新思路
摘要: 关于 Kubernetes 接口化设计.CRI.容器运行时.shimv2.RuntimeClass 等关键技术特性的设计与实现. Kubernetes 项目目前的重点发展方向,是为开发 ...
- containerd与kubernetes集成部署
概念介绍 cri (Container runtime interface) cri is a containerd plugin implementation of Kubernetes conta ...
- Dubbo和Spring集成Demo
Zookeeper安装和启动 http://mirrors.hust.edu.cn/apache/zookeeper/下载,我的版本是 3.4.5. 解压到 D:\zookeeper-3.4.5 配置 ...
- 干货 | 京东云托管Kubernetes集成镜像仓库并部署原生DashBoard
在上一篇"Cloud Native 实操系列"文章中,我们为大家介绍了如何通过京东云原生容器实现Eureka的部署(
- dubbo实战之二:与SpringBoot集成
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Dubbo集成步骤
dubbo协议实现与webservice一样的效果,用于服务调用之间的接口.dubbo可在中间实现真正意义上的中间调用管理,是一个中间管理系统. demo:http://www.devnote.cn/ ...
随机推荐
- Spring Data JPA 梳理 - JPA是什么
总结: JPA是java的标准,不是Spring的标准 java标准中一般通过Meta-INF文件规范开发层面的事情,JPA也不例外,使用persistence.xml JPA定义了Entity 到 ...
- 初识Hiberante框架和第一个案例
今天想回顾一下一个月前学的hibernate框架,也让我了解了持久层的概念(访问数据库). 一.ORM概念 首先提的是ORM概念,O表示Object, R表示Relation(关系),关系型数据库,如 ...
- 【爬虫小程序:爬取斗鱼所有房间信息】Xpath
# 本程序亲测有效,用于理解爬虫相关的基础知识,不足之处希望大家批评指正from selenium import webdriver import time class Douyu: "&q ...
- Flask基础(10)-->http的无状态协议解决办法一(客户端cookie)
http的无状态协议 http是一种无状态协议,浏览器请求服务器时无状态的 什么是无状态? 无状态:指的是一次用户请求时,浏览器.服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求. 无状态 ...
- SUSE CaaS Platform 4 - 安装技巧
1.虚拟化环境搭建 - 网络 首先,虚拟机其中一块网卡桥接到 VMnet8 上,通过 VMnet8 地址转换出去访问互联网,如果我们直接桥接到 WIFI 网卡上,由于在不同的的网络环境,地址会时长会 ...
- python 虚拟环境配置
刚学习 python 的同学经常会遇到一个问题: 已经安装了特定的包或者第三库,但是 pycharm 总是提示没有找到.
- ELK日志分析系统(3)-logstash数据处理
1. 概述 logspout收集数据以后,就会把数据发送给logstash进行处理,本文主要讲解logstash的input, filter, output处理 2. input 数据的输入处理 支持 ...
- c++ 对特定进程的内存监控
在工具实现的过程中,遇到了内存爆了的问题,部分模型的规模可以达到10的100次方方甚至1000次方.(工具的主要算法涉及到了递归,递归深度会很深,所以也用到了ulimit修改栈空间来缓解爆栈的问题,治 ...
- 如何写md格式的文档
一.标题 标题其实和HTML中的h系列很像,想要设置为标题的文字前面加#来表示一个#是一级标题,二个#是二级标题,以此类推.支持六级标题. 注:标准语法一般在#后跟个空格再写文字, 示例: 效果如下: ...
- 我在用的翻译软件 -> 微软翻译+网易有道词典+谷歌翻译
Windows网页翻译 因为微软翻译相对来说翻译网页更为准确,我也喜欢用谷歌的Chrome浏览器,但是我没找到微软翻译的扩展,这里只能放弃 这个需要配合Microsoft Edge浏览器进行使用,也是 ...