基于Docker的应用负载均衡与服务发现

基于Docker的应用负载均衡与服务发现

概述

现在微服务架构越来越流行,阿里云容器服务对于微服务架构提供了很好的支撑,平台提供了便利的服务注册与发现机制,内置的服务负载均衡与路由功能,以及灵活的模板编排、全生命周期管理。

对于Web应用,下图是阿里云容器服务对弹性高可用Web应用负载均衡及路由支持的一种形式:

阿里云容器路由服务

假如你有一个Web应用需要运行多个实例,并对外提供服务。可以配置docker compose模板如下(以Java应用的Tomcat+Mysql为例), 这里通过Docker的link方式支持服务的依赖,部署后mysql的IP地址,端口,环境变量等信息会自动配置到Tomcat容器的环境变量中。

tomcat-default:
  environment:
    - CATALINA_HOME=/usr/local/tomcat
    - 'TOMCAT_TGZ_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.0.30/bin/apache-tomcat-8.0.30.tar.gz'
  expose:
    - 8080/tcp
  image: 'tomcat:latest'
  labels:
    aliyun.routing.port_8080: 'http://tomcat-sample'
    aliyun.scale: '3'
  restart: always
  links:
    - 'db:mysql'

db:
  image: registry.aliyuncs.com/acs-sample/mysql:5.7
  environment:
    MYSQL_ROOT_PASSWORD: password
  restart: always
  labels:
    aliyun.logs: /var/log/mysql
  • aliyun.scale: '3' 表示部署3个tomcat容器
  • aliyun.routing.port_8080: 'http://tomcat-sample' 配置路由服务(路由到3个容器的8080端口),并配置阿里云容器服务提供的测试域名。

或者在阿里云容器服务中通过界面部署应用:

选择镜像

配置域名


服务详情

访问域名

自定义负载均衡

很多的Web应用有自己的负载均衡Server, Nginx就是一个很流行的负载均衡及反向代理Server. 很多的Java应用也是采用Nginx+Tomcat架构,以提供负载均衡,静态资源代理,流控,ABTest等等服务支持。对于这样一个架构在Docker上我们应该怎样实现呢?下面我们看看几种不同的实现方式:

独立link

Nginx link到分立的多个Tomcat服务。Docker compose模板如下:

nginx:
  image: 'nginx:latest'
  labels:
    aliyun.routing.port_80: 'http://ngtomcat'
    aliyun.scale: '2'
  ports:
    - '80'
  links:
    - 'tomcat1:tomcat1'
    - 'tomcat2:tomcat2'
    - 'tomcat3:tomcat3'
  restart: always
  extra_hosts:
   - "tomcat1.if:162.242.195.82"

tomcat1:
  environment:
    - LANG=C.UTF-8
    - CATALINA_HOME=/usr/local/tomcat
    - TOMCAT_MAJOR=8
  image: 'tomcat:latest'
  labels:
    aliyun.routing.port_8080: 'http://tomcat1'
  ports:
    - '8080'
  restart: always

tomcat2:
  environment:
    - LANG=C.UTF-8
    - CATALINA_HOME=/usr/local/tomcat
    - TOMCAT_MAJOR=8
  image: 'tomcat:latest'
  labels:
    aliyun.routing.port_8080: 'http://tomcat1'
  ports:
    - '8080'
  restart: always

tomcat3:
  environment:
    - LANG=C.UTF-8
    - CATALINA_HOME=/usr/local/tomcat
    - TOMCAT_MAJOR=8
  image: 'tomcat:latest'
  labels:
    aliyun.routing.port_8080: 'http://tomcat1'
  ports:
    - '8080'
  restart: always

这里前面是2个Nginx,后面接入3个Tomcat.
Ngnix的upstream配置大致如下:

upstream tomcat {
      server tomcat1:8080;
      server tomcat2:8080;
      server tomcat3:8080;
}

server {
listen       80;
server_name localhost;
index index.html index.htm index.php;
access_log  /var/log/nginx/access.log;
location / {
proxy_pass  http://tomcat;
}
}

Nginx的配置也可以在模板中通过command自动配置:
command: sh -c "echo 'xxxx' >/etc/nginx/conf.d/default.conf"

这种方式是直接利用docker提供的link机制,link后docker会自动将link容器的ip配置到nginx容器中。阿里云容器服务针对ECS的经典网络及VPC都提供了夸主机通讯的能力,tomcat容器部署到多节点上,通讯也不会有问题。
这种方式是路由到容器的IP+Port,优点是配置简单,跟以前的应用部署比较类似,但不便于弹性扩展,增加tomcat就需要调整配置。

或者也可以只link到一个tomcat服务(多个容器),并配置路由到容器(容器 host为tomcat_n)。

路由到节点

阿里云容器服务在集群的每个ECS节点上都提供了一个路由服务,可以利用这个路由服务提供更弹性的负载均衡服务。Compose模板如下:

nginx:
  image: 'nginx:latest'
  labels:
    aliyun.routing.port_80: 'http://ngtomcat'
    aliyun.scale: '2'
  ports:
    - '80'
  links:
    - 'tomcat1:tomcat1'
    - 'tomcat2:tomcat2'
  restart: always
  extra_hosts:
   - "tomcat1.ir:123.56.80.151"
   - "tomcat2.ir:182.92.204.43"

tomcat1:
  environment:
    - LANG=C.UTF-8
    - CATALINA_HOME=/usr/local/tomcat
    - TOMCAT_MAJOR=8
  image: 'tomcat:latest'
  labels:
    aliyun.scale: '2'
    aliyun.routing.port_8080: 'http://tomcat.ir'
  ports:
    - '8080'
  restart: always

tomcat2:
  environment:
    - LANG=C.UTF-8
    - CATALINA_HOME=/usr/local/tomcat
    - TOMCAT_MAJOR=8
  image: 'tomcat:latest'
  labels:
    aliyun.scale: '2'
    aliyun.routing.port_8080: 'http://tomcat.ir'
  ports:
    - '8080'
  restart: always

这里配置了2个Nginx,Nginx连接了2个Tomcat服务,每个Tomcat服务运行2个实例。

nginx upstream配置大致如下:

upstream tomcat.ir {
      server tomcat.ir.1;
      server tomcat.ir.2;
}

server {
listen       80;
server_name tomcat.ir;
index index.html index.htm index.php;
access_log  /var/log/nginx/access.log;
location / {
proxy_pass  http://tomcat.ir;
}
}

这种方式利用阿里云容器提供的路由服务,能够自动服务发现与路由。当tomcat弹性调整容器数量的时候,并不需要调整模板或者Nginx的配置,会更加方便些。

利用API进行服务发现

阿里云容器也提供了服务发现的API,我们可以利用服务发现API定制自己的负载均衡。

获取某个服务的状态API如下(支持Stream):

API

/services/{serviceId}

样例


请求命令:curl -k --cert agent.pem  --key agent-key.pem https://DiscoveryServer:2379/services/ceshi-2_gitlab
结果:
{
    "Service": {
        "name": "gitlab",
        "project": "ceshi-2",
        "definition": {
            "image": "registry.aliyuncs.com/acs-sample/sameersbn-gitlab:7.14.1",
            "labels": {
                ...
                "aliyun.routing.port_80": "gitlab-test"
            },
            "links": ["redis:redisio", "postgresql:postgresql"],
            "ports": ["80", "10022:22"],
            "volumes": ["/srv/docker/gitlab/gitlab:/home/git/data"]
        },
        "extensions": {
            "scale": 1,
            "routing": [{
                "virtual_host": "gitlab-test.xxx.cn-hangzhou.alicontainer.com",
                "protocol": "http",
                "port": 80
            }]
        },
...
    },
    "Containers": {
        "13b3ee3e7ca247537756ad4db117d76f52d9a40efd84d561f1b865200597c97d": {
            "name": "/ceshi-2_gitlab_1",
            "node": "120.55.181.78",
            "ip": "172.64.0.8",
            "running": true,
            "status": "running",
            "health": "success"
        }
    }
}

这里是一个用Python脚本查询更新Nginx的样例:

def serviceSync():
    # Get setting
    projectName = os.getenv('COMPOSE_PROJECT_NAME')
    serviceServer = os.getenv('ETCD_NODES')
...

    # Get service data for contianers
    serviceData = getServiceData(serviceServe, serviceName )
    upStreamIPs = getUpstreamIps( serviceData )

    # Generate config from template
    upstreamServers = ''
    for ip in upStreamIPs:
        upstreamServers += "server %s:%s;\n" % (ip, port)

    config = getTemplate().substitute(upstreamServers=upstreamServers)

    updateConfig( config )

def main():
    options, arguments = getOpts()

    while True:
        serviceSync()
        time.sleep(60)

用这个脚本构建一个自动更新配置的Nginx的新镜像:

FROM nginx:1.9.8
MAINTAINER Chang Hai Yan <danielyanch@hotmail.com>
ADD serviceSync.py /usr/local/bin/serviceSync.py
ADD supervisord.conf /etc/supervisord.conf

RUN apt-get update && \
    apt-get install --force-yes -y curl python supervisor && \
    chmod +x /usr/local/bin/serviceSync.py 

CMD supervisord -n

Compose部署模板如下,注意访问API需要证书,需要在Label中添加 aliyun.addon ,有这个Label,部署的时候,集群管理会自动将服务发现Server的地址及证书配置到运行的容器中。

nginx:
  image: 'registry.aliyuncs.com/acs-sample/nginx-service-discovery'
  labels:
    aliyun.routing.port_80: 'http://ngservice'
    aliyun.scale: '2'
    aliyun.addon: "nginx"
  ports:
    - '80'
  links:
    - 'tomcat:tomcat'
  restart: always

tomcat:
  environment:
    - LANG=C.UTF-8
    - CATALINA_HOME=/usr/local/tomcat
    - TOMCAT_MAJOR=8
  image: 'tomcat:latest'
  labels:
    aliyun.scale: '3'
    aliyun.routing.port_8080: 'http://tomcat'
  ports:
    - '8080'
  restart: always

阿里云容器服务也支持通过NAT+SLB的方式来进行负载均衡及更简单的事件机制进行服务的生命周期管理,我们后面再介绍。

时间: 2022-12-14

基于Docker的应用负载均衡与服务发现的相关文章

基于Docker的负载均衡和服务发现

应用的容器化和微服务化带来的问题 在缺省网络模型中,容器每次重启后,IP会发生变动,在一个大的分布式系统保证IP地址不变是比较复杂的事情 IP频繁发生变动,动态应用部署无法预知容器的IP地址,client端如何发现server端的访问端点? 解决方案(根据客户端是否有感知进行分类) 客户端的发现.client 订阅注册中心,有一个固定的注册中心地址,client订阅某个服务的注册中心,注册中心根据服务的运行状态推送某个服务的访问端点列表给client端. 该方案的实现举例有dubbo,DNS的解

DockOne微信分享(七十一):基于Docker的负载均衡和服务发现

本文讲的是DockOne微信分享(七十一):基于Docker的负载均衡和服务发现[编者的话]Docker已经成为时下热门的容器技术,各大公司,中小创业者,都选择采用Docker技术架构其下一代的系统和应用. 随着系统规模扩大,单一Docker容器不能应对压力,需要横向扩展到多个容器,我们需要考虑负载均衡的问题:单一职责的Docker容器之间需要相互通信,而容器在每一次重启之后,它的IP都可能发生变化,那么服务和服务之间如何发现对方? 这一次我们一起来交流基于Docker的负载均衡和服务发现.内容

利用阿里云容器服务实现Docker微服务间的负载均衡和服务发现

基于容器服务实现Docker微服务间的负载均衡和自动服务发现的方法 在容器服务上可以通过acsrouting将基于域名的http的服务暴漏出去,而且能够配合健康检查自动的负载均衡和服务发现,当其中一个容器出现问题之后,routing会自动将健康检查失败的容器从后端摘除,所以能做到自动的服务发现. 然而这个是将服务暴漏到外网的,那么服务间如何通过这种方式做到自动的服务发现和的负载均衡呢?容器服务引入了负载均衡的功能,只需要使用.local结尾的域名,并在依赖的服务的external_links中增

Spring Boot与Docker(四):额外的微服务、更新容器、Docker Compose和负载均衡

本文讲的是Spring Boot与Docker(四):额外的微服务.更新容器.Docker Compose和负载均衡,[编者的话]本篇是<使用Spring Boot和Docker构建微服务架构>系列的第四篇,本篇我们我们将添加一些额外的服务/容器,并且更新容器,采用Docker Compose以及使用HAProxy容器进行负载均衡.原文作者为3Pillar环球旗下美国Adbanced技术集团的总监Dan Greene,Dan有十八年的软件设计和开发经验,包括在电子商务.B2B集成.空间分析.S

Docker Workflow(四):服务发现与负载均衡

本文讲的是Docker Workflow(四):服务发现与负载均衡,[编者的话]作者讲述了如何将服务发现(Consul.io与Consul-Template)与负载均衡(Nginx)相结合,实现灵活的配置和自动化重载,降低运维难度.当你还执着于给容器分配固定IP这件事上时,也许服务发现才是正道. 这是关于我们如何在IIIEPE的生产环境中使用Docker的系列文章的最后一部分.如果你还没看过第一(译文).第二(译文)和第三(译文)部分,请先前往阅读再继续.本文中,我将讨论如何配置服务发现和负载均

使用NGINX Plus负载均衡Kubernetes服务

本文讲的是使用NGINX Plus负载均衡Kubernetes服务,[编者的话]此篇文章是Nginx的Michael Pleshakov发表在Nginx官方博客的一篇博文,通过这篇文章概括回顾了Kubernetes暴露服务相关的解决方案,并对最新的Ingreess API进行了说明,最后给出了Kubernetes通过集成NGINX Plus来暴露服务到互联网的解决方案.这个方案解决了目前Kubernetes暴露服务的短板,整个实现过程也比较简单,步骤清晰,具有很强的参考性.我们华三目前也在调研这

来自东软的 OpenStack 负载均衡即服务开源项目

东软ADSG(应用交付安全网关,Application Delivery Security Gateway) LBaaS Driver 当前实现了对 OpenStack(Havana 版本或更高)负载均衡即服务(Load Balancer as a Service, LBaaS )的支持.通过将一个 LBaaS 驱动集成到 OpenStack LBaaS 组件中,ADSG 可以将负载均衡以服务的形式提供给用户.用户可以在 OpenStack 中进行负载均衡配置,从而对自己在 OpenStack

Docker网络和服务发现

本文讲的是Docker网络和服务发现[编者的话] 本文是<Docker网络和服务发现>一书的全文,作者是Michael Hausenblas.本文介绍了Docker世界中的网络和服务发现的工作原理,并提供了一系列解决方案. 前言 当你开始使用Docker构建应用的时候,对于Docker的能力和它带来的机会,你会感到很兴奋.它可以同时在开发环境和生产环境中运行,只需要将一切打包进一个Docker镜像中,然后通过Docker Hub分发镜像,这是很直接了当的.你会发现以下过程很令人满意:你可以快速

企业为什么要使用基于Docker的PaaS/CaaS平台

作者:精灵云 前言 早在十多年前国内外的一些大厂就开始投入研发和使用容器技术,比如Google,对他们来说,使用容器能够充分利用计算资源节省硬件成本.而这几年--众所周知--真正把容器技术发扬光大的是Docker.Docker的slogan"Build,Ship & Run anywhere"定位非常清晰,Docker的出现打破了传统运维模式里从打包到部署的过程中环境.语言.平台不一致的乱象,将这一整套开发运维模式标准化了,从而真正帮助企业实践了DevOps和微服务化. 但是,