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起来了

[email protected]:~/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起来了

[email protected]:~/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。

原文地址:https://www.cnblogs.com/nxlhero/p/11789006.html

时间: 2024-10-10 19:00:46

Dubbo与Kubernetes集成的相关文章

Mesos+Kubernetes集成安装部署

因为Docker本身没有提供集群管理能力,对于docker集群一台台的登陆操作不太现实,因此需要引进容器集群的管理工具,主流的有mesosphere的marathon.谷歌的Kubernetes.docker社区的swarm,目前成熟度最高的是Kubernetes.Kubernetes是Google开源的容器集群管理系统,其提供应用部署.维护. 扩展机制等功能,利用Kubernetes能方便地管理跨机器运行容器化的应用,其主要功能如下: 使用Docker对应用程序包装(package).实例化(

如何使用Dubbo服务和集成Spring

Dubbo是什么? Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点. Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案. 其核心部分包含: 1.远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及"请求-响应"模式的信息交换方式. 2.集群容错: 提供基于接口方法的透明远程过程调用,包括

Kubernetes集成Heapster监控

Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS.Kubernetes有个出名的监控agent-cAdvisor.在每个kubernetes Node上都会运行cAdvisor,它会收集本机以及容器的监控数据(cpu,memory,filesystem,network,uptime).在较新的版本中,K8S已经将cAdvisor功能集成到kubelet组件中.每个Node节点可以直接进行web访问. 1.镜像下载[[email protected]_ma

Dubbo和Spring集成Demo

Zookeeper安装和启动 http://mirrors.hust.edu.cn/apache/zookeeper/下载,我的版本是 3.4.5. 解压到 D:\zookeeper-3.4.5 配置 到目录conf 下创建 zoo.cfg 文件,默认就是加载这个文件,文件内容 我直接copy 的sample里面的 zoo.cfg 的内容 # 心跳检查的时间 2秒 tickTime=2000 # 初始化时 连接到服务器端的间隔次数,总时间10*2=20秒 initLimit=10 # ZK Le

kubernetes集成calico网络

1.物理环境 172.16.0.55 k8s1  master 172.16.0.57 k8s2  node 172.16.0.47 k8s3  node [[email protected] ~]# docker ps |grep per a394542f2340        alectolytic/netperf:latest                                   "sleep 36000000"         16 hours ago      

Dubbo集成步骤

dubbo协议实现与webservice一样的效果,用于服务调用之间的接口.dubbo可在中间实现真正意义上的中间调用管理,是一个中间管理系统. demo:http://www.devnote.cn/download/182 同步服务端集成 同步服务端统一试用dubbo服务端集成到业务系统.目前的场景试用的是dubbo协议. 1.加入dubbo jar包(附件2.4.10-jar.zip) 2.在spring配置文件中加入dubbo provider配置 <?xml version="1.

13. Dubbo原理解析-注册中心之Zookeeper协议注册中心

下面我们来看下开源dubbo推荐的业界成熟的zookeeper做为注册中心, zookeeper是hadoop的一个子项目是分布式系统的可靠协调者,他提供了配置维护,名字服务,分布式同步等服务.对于zookeeper的原理本文档不分析,后面有时间在做专题. zookeeper注册中心 Zookeeper对数据存储类似linux的目录结构,下面给出官方文档对dubbo注册数据的存储示例 假设读者对zookeeper有所了解,能够搭建zookeeper服务,其实不了解也没关系,谷歌百度下分分钟搞起.

Dubbo的使用简介

一.Dubbo是什么 官方定义 DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点. 详细理解,就是 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和spring框架无缝集成.是一个分布式服务框架,以及SOA治理方案.其功能主要包括:高性能NIO

易于混淆的两个技术:Kerberos与Kubernetes辨析

易于混淆的两个技术:Kerberos与Kubernetes辨析 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs Kerberos介绍 Kerberos是一个网络授权验证协议,源于麻省理工学院,其第一个公开发行版为Kerberos V4.在得到广泛使用后,继续发布了Kerberos V5版,随后Kerberos V5成为IETF的标准.Kerberos的设计目标是通过使用密钥加密技术,为客户端/服务器架构的应用提供一个