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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 现在微服务架构越来越流行,阿里云容器服务对于微服务架构提供了很好的支撑,平台提供了便利的服务注册与发现机制,内置的服务负载均衡与路由功能,以及灵活的模板编排、全生命周期管理。

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

概述

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

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

阿里云容器路由服务

假如你有一个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端口),并配置阿里云容器服务提供的测试域名。

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

选择镜像

screenshot

配置域名

screenshot
screenshot

服务详情

screenshot

访问域名

screenshot

自定义负载均衡

很多的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的方式来进行负载均衡及更简单的事件机制进行服务的生命周期管理,我们后面再介绍。

相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
18天前
|
Kubernetes 开发者 Docker
构建高效微服务架构:Docker与Kubernetes的协同应用
【5月更文挑战第30天】 在当今软件开发领域,微服务架构已成为实现系统模块化、提升可维护性及扩展性的关键策略。本文深入探讨了如何通过Docker容器化技术和Kubernetes集群管理,共同构建一个既高效又可靠的后端微服务环境。我们将剖析Docker和Kubernetes的核心功能,以及它们如何相辅相成,支撑起现代化的云原生应用程序部署和管理。文章还将提供具体实践案例,帮助开发者理解将理论应用于实际开发过程中的步骤和考虑因素。
|
19天前
|
Kubernetes Cloud Native 开发者
构建高效的云原生应用:Docker与Kubernetes的完美搭档
【5月更文挑战第29天】 在现代软件开发领域,"云原生"这一术语已经成为高效、可扩展和弹性的代名词。本文将深入探讨如何通过Docker容器化技术和Kubernetes集群管理工具实现云原生应用的构建和管理。我们将剖析Docker的核心原理,揭示其轻量级和易于部署的特点,并进一步探索Kubernetes如何为这些容器提供编排,保证应用的高可用性与自动扩缩容。文章不仅讨论了二者的技术细节,还提供了实践案例,帮助开发者理解并运用这些技术构建和维护自己的云原生应用。
|
1月前
|
存储 安全 数据安全/隐私保护
【Docker 专栏】Docker 容器化应用的备份与恢复策略
【5月更文挑战第9天】本文探讨了Docker容器化应用的备份与恢复策略,强调了备份在数据保护、业务连续性和合规要求中的关键作用。内容涵盖备份的重要性、内容及方法,推荐了Docker自带工具和第三方工具如Portainer、Velero。制定了备份策略,包括频率、存储位置和保留期限,并详细阐述了恢复流程及注意事项。文章还提及案例分析和未来发展趋势,强调了随着技术发展,备份与恢复策略将持续演进,以应对数字化时代的挑战。
【Docker 专栏】Docker 容器化应用的备份与恢复策略
|
1月前
|
监控 Kubernetes Docker
【Docker 专栏】Docker 容器内应用的健康检查与自动恢复
【5月更文挑战第9天】本文探讨了Docker容器中应用的健康检查与自动恢复,强调其对应用稳定性和系统性能的重要性。健康检查包括进程、端口和应用特定检查,而自动恢复则涉及重启容器和重新部署。Docker原生及第三方工具(如Kubernetes)提供了相关功能。配置检查需考虑检查频率、应用特性和监控告警。案例分析展示了实际操作,未来发展趋势将趋向更智能和高效的检查恢复机制。
【Docker 专栏】Docker 容器内应用的健康检查与自动恢复
|
1天前
|
监控 Java 数据安全/隐私保护
性能监控之 JMX 监控 Docker 容器中的 Java 应用
【6月更文挑战9天】性能监控之 JMX 监控 Docker 容器中的 Java 应用
13 1
|
5天前
|
运维 Ubuntu Docker
深入理解容器化技术:Docker的应用与实践
在这个数字化转型迅速推进的时代,容器化技术为软件开发和部署提供了新的路径。本文将深入探讨Docker技术的基本原理、应用场景以及实际操作,旨在帮助读者全面理解并掌握这一关键技术。
32 2
|
10天前
|
关系型数据库 持续交付 数据库
简化多容器应用部署:深入理解 Docker Compose
简化多容器应用部署:深入理解 Docker Compose
|
11天前
|
Cloud Native Java Docker
java一分钟之-Docker化Java应用:Dockerfile与镜像构建
【6月更文挑战第6天】本文探讨了Docker在Java应用部署中的重要性,强调了Dockerfile在保证环境一致性和提升部署效率上的作用。Dockerfile是自动化构建Docker镜像的文本文件,它的使用能实现标准化、可重复性和透明度。文章指出了编写Dockerfile时的常见问题,如指令误用、镜像体积过大和安全性不足,并提供了相应的解决策略。通过一个Spring Boot应用的实战示例,展示了如何编写Dockerfile和构建镜像。总之,掌握Dockerfile和镜像构建技巧对于优化Java应用的云原生部署至关重要。
41 0
|
13天前
|
存储 运维 持续交付
介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用。
介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用。
15 0
|
14天前
|
负载均衡 运维 监控
负载均衡与容错性:集群模式在分布式系统中的应用
本文由小米分享,解释了分布式系统中的集群模式。集群模式是通过组合多个服务器节点,共同提供服务,实现高可用性、负载均衡和扩展性。文章介绍了主控节点的角色及其高可用性策略,如主备模式和选举机制,并以Zookeeper为例详细阐述了其工作机制。集群模式的优势在于高可用性、负载均衡、扩展性和数据一致性,但也面临节点通信、数据一致性、故障检测和管理等挑战。最后,作者鼓励读者讨论和交流相关技术问题。
173 5