Docker容器互联方法

翔宇 发表了文章 • 0 个评论 • 321 次浏览 • 2019-05-28 22:34 • 来自相关话题

【编者的话】本文为Eddy Mavungu博士于DEIS官方博客中发布的系列文章的第二部分,Eddy博士在本篇系列文章中分享了Docker容器间互联的方法,并且做了演示。Eddy博士是DEIS公司的创始人,同时也是一位高级研究顾问。本文根据他于DEIS官方博客 ...查看全部
【编者的话】本文为Eddy Mavungu博士于DEIS官方博客中发布的系列文章的第二部分,Eddy博士在本篇系列文章中分享了Docker容器间互联的方法,并且做了演示。Eddy博士是DEIS公司的创始人,同时也是一位高级研究顾问。本文根据他于DEIS官方博客上发布的文章翻译而成。

这篇系列文章的第二部分会看一下如何连接Docker各容器。

我们在第一节谈及了Docker的bridge接口,它可以让我们连接所有在相同Docker宿主机上的容器。特别需要指出的是,我们看了三个基本并且比较早先的网络驱动技术:端口公开(port exposure),端口绑定(port binding)以及链接(linking)。如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

在本文,我们将来看这些更高级并且最新的基于bridge接口的使用案例。

同时,我们也会看看使用overlay技术来将不同宿主机上的Docker容器连接起来。
#用户定义的网络(User-Defined Networks)
Docker公司在2015年11月初发布了Docker 1.9.0,随之而来整合了一些令人兴奋的关于网络方面的新内容。通过这些更新,如果我们现在为了让两个容器间可以相互通信,那么只需要将他们放在同一网络或者子网中。

让我们来证明一次。

首先,来看看我们准备了哪些:
$ sudo docker network ls
NETWORK ID NAME DRIVER
362c9d3713cc bridge bridge
fbd276b0df0a singlehost bridge
591d6ac8b537 none null
ac7971601441 host host

现在,让我们来创建网络:
$ sudo docker network create backend

如果起作用了,我们的网络列表上会显示刚才新建立的网络:
$ sudo docker network ls
NETWORK ID NAME DRIVER
362c9d3713cc bridge bridge
fbd276b0df0a singlehost bridge
591d6ac8b537 none null
ac7971601441 host host
d97889cef288 backend bridge

我们可以看到在这里backend已经被bridge驱动创建出来了。这是一个桥接(bridge)网络,就像在前文的第一部分中提到的一样,它也同样适用于所有在该宿主机上的容器。

我们将会用到上一节中创建的client_img和server_img镜像。如果你还没有在你的主机上配置好他们,可以现在查阅第一节并且设置好,这并不会花费太长时间。

什么?你说你已经设置好了?太棒了。

让我们从server_img镜像中运行一个服务器容器并且通过--net选项把它放置于之前配置的backend网络中。

就像下面命令一样:
$ sudo docker run -itd --net=backend --name=server server_img /bin/bash

像之前一样,登录到该容器:
$ sudo docker attach server

如果你看不见shell提示符,按键盘方向键的上箭头。

现在让我们启动在该容器里基于Apache的HTTP服务:
$ /etc/init.d/apache2 start

到这里为止,任何位于backend网络中的容器将可以连接到我们刚才创建的Apache HTTP服务器上。

我们可以通过在另一个终端上开启一个客户端容器并且把它至于backend网络进行测试。

就像这样:
$ sudo docker run -itd --net=backend --name=client client_img /bin/bash

进入容器:
$ sudo docker attach client

同样地,如果你看不见shell提示符,按键盘方向键的上箭头。
接着运行:
$ curl server

你应该可以看见默认的HTML页面。这意味着我们配置的网络是可以正常运行的。

就像在本系列文章的第一节中提及到的一样,Docker负责设置容器名称便于解析,这就是为什么我们可以直接用curl server 这个命令而不用知晓它的IP地址。

我们可以创建多个用户定义的网络,并且可以根据应用程序的拓扑结构把这些容器放在单个或多个网络中。这是非常灵活的,特别是对于那些需要交付微服务(microservices),多租户(multitenancy)及微分段(micro-segmentation)的人员来说是非常有用的。
#多主机网络(Multi-Host Networking)
如果我们想要建立一个跨越多台主机的网络该怎么做呢?当然,自从Docker1.9.0之后,你就可以这么做了!

目前为止,我们已经使用了基于本地范围的bridge网络驱动,这意味着桥接网络是在Docker宿主机本地的。Docker现在提供了一个新的全局范围的overlay网络驱动,这意味着overlay的网络可以跨越多台Docker宿主机。并且这些Docker宿主机可以存在于不同的数据中心,甚至不同的云服务提供商中!

为了设置一个overlay网络,以下几点是必须的:

* 一台内核版本高于3.16的主机
* 关键的key-value存储(例如 etcd, ConsulApache ZooKeeper
* 集群内的主机可以保证连接到以上的key-value存储
* 每一个集群内的主机都正确配置了基于 Docker Engine的后台实例

让我们来看一个案例吧。

我将会使用multihost-local.sh脚本和Docker Machine这个命令去开启三台虚拟主机。

这个脚本是用于虚拟机的而不是用于容器的。在这之后,我们在这些虚拟机上面运行Docker命令去模拟一个Docker宿主机集群。

在运行过脚本之后,可以看到我现在有的主机清单:
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM ERRORS
mhl-consul - virtualbox Running tcp://192.168.99.100:2376
mhl-demo0 - virtualbox Running tcp://192.168.99.101:2376
mhl-demo1 - virtualbox Running tcp://192.168.99.102:2376

好了,那么让我们倒退回去看下刚才发生了些什么。

这个脚本利用了Docker Machine,这意味着你必须安装它。在本篇文章中,我们安装了0.5.2版本的Docker Machine。你可以参考该版本的发行注释说明来下载并安装它。

该脚本(multihost-local.sh)使用了Docker Machine去部署三台基于VirtualBox的虚拟机并且安装并适当的配置了Docker Engine。

Docker Machine可以与很多主流虚拟化管理程序以及云服务提供商一起协助。它现在支持AWS、Digital Ocean、Google Cloud Platform、IBM Softlayer、Microsoft Azure和Hyper-V、OpenStack、Rachspace、VitrualBox、VMware Fusion®、vCloud® Air™ and vSphere®。

我们现在有了三个虚拟机:

* mhl-consul: 运行 Consul
* mhl-demo0: Docker 集群节点
* mhl-demo1: Docker 集群节点

这些Docker集群节点是被配置为协调通过VM来运行Consul,我们的key-value仓库。这也就是这些集群所涉及到的。

很酷吧,让我们再快速地往前看一看。

现在,让我们设置一个overlay网络。

首先,我们需要用一个在mhl-demo0这个VM上的终端,像这样:
$ eval $(docker-machine env mhl-demo0)

然后运行:
$ docker network create -d overlay myapp

该命令建立了一个名为myapp的跨越所有集群中主机的overlay网络。由于Docker通过key-value与该集群上的其他主机协调使得该操作变成了可能。

为了确保它正常的工作,我们可以通过终端登录到每一个集群中的VM去列出这些Docker网络。

复制下面所有的eval命令,然后用相对应的主机名去替换mhl-demo0。

然后运行:
$ docker network ls
NETWORK ID NAME DRIVER
7b9e349b2f01 host host
1f6a49cf5d40 bridge bridge
38e2eba8fbc8 none null
385a8bd92085 myapp overlay

到这里你就看到名为myapp的overlay网络了。

咱们成功啦!

但请记住:我们目前仅仅是创建了一个基于Docker 虚拟机的集群并配置了用于共享的overlay网络。我们实际上并没有创建任何Docker容器。所以让我们接着创建它们并来试一下这个overlay网络。

我们将做以下步骤:

1. 在mhl-demo0宿主机上运行默认地nginx镜像(这提供给了我们一个预先配置好的Nginx HTTP服务器)
2. 在mhl-demo1宿主机上运行默认的busybox镜像(它提供给我们一个基本的操作系统并且还包含一个类似于基于GNU的Wget工具)
3. 将两个容器添加进myapp网络
4. 测试他们之间的网络连通性

首先,让我们调出在mhl-demo0宿主机上的终端:
$ eval $(docker-machine env mhl-demo0)

然后启动nginx镜像:
$ docker run --name ng1 --net=myapp -d nginx

简而言之,我们现在有以下环境:

* 一台基于Nginx的HTTP服务器
* 该服务跑在名为ng1的容器里
* 它处在myapp网络中
* 该容器位于mhl-demo0宿主机上

让我们从其他宿主机上的另外一个容器试着去访问该环境,去验证它是可用的。

这一次调出mhl-demo1宿主机上的终端:
$ eval $(docker-machine env mhl-demo1)

然后运行:
$ docker run -it --net=myapp busybox wget -qO- ng1

以上命令其实做了以下几点:

* 从busybox镜像中创建了一个未命名的容器
* 将它添加进了myapp网络
* 运行了wget -qO- ng1命令
* 并且停止了该容器(我们在这之前是让容器运行的)

在以上的Wget命令中,ng1是我们Nginx的容器名称。Docker可以让我们使用解析到的主机名作为容器名称,甚至该容器是运行在不同的Docker宿主机上。

如果所有操作都是成功的,那么我们应该会看见以下类似的内容:






Welcome to nginx!

你看吧!我们现在拥有了一个基于多主机的容器网络。
#总结
Docker给予了诸如轻量级且独立地并能隔离的环境这样的优点。然而,要使容器对我们而言有用途,容器之间以及容器与主机网络之间要能互相通信才是至关重要的。

在这一系列文章中,我们探索了一些容器间本地互联和跨多个宿主机互联的方法。同样地,我们也聊了聊该如何在主机网络中去连接多个容器。

原文链接:Connecting Docker Containers, Part Two (翻译:薛开成)

===========================================
译者介绍
薛开成,趋势科技南京研发中心工程工具服务事业部基础架构高级工程师,负责容器仓库实施及落地。

使用Spring Cloud和Docker构建微服务架构

老马 发表了文章 • 0 个评论 • 242 次浏览 • 2019-05-28 22:27 • 来自相关话题

【编者的话】如何使用Spring Boot、Spring Cloud、Docker和Netflix的一些开源工具来构建一个微服务架构。本文通过使用Spring Boot、Spring Cloud和Docker构建的概念型应用示例,提供了了解常见的微服务架构模式 ...查看全部
【编者的话】如何使用Spring Boot、Spring Cloud、Docker和Netflix的一些开源工具来构建一个微服务架构。本文通过使用Spring Boot、Spring Cloud和Docker构建的概念型应用示例,提供了了解常见的微服务架构模式的起点。

该代码可以在GitHub上获得,并且在Docker Hub上提供了镜像。您只需要一个命令即可启动整个系统。

我选择了一个老项目作为这个系统的基础,它的后端以前是单一应用。此应用提供了处理个人财务、整理收入开销、管理储蓄、分析统计和创建简单预测等功能。如果你想和更多Spring Cloud技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#功能服务
整个应用分解为三个核心微服务。它们都是可以独立部署的应用,围绕着某些业务功能进行组织。
1.png


账户服务

包含一般用户输入逻辑和验证:收入/开销记录、储蓄和账户设置。
2.png


统计服务

计算主要的统计参数,并捕获每一个账户的时间序列。数据点包含基于货币和时间段正常化后的值。该数据可用于跟踪账户生命周期中的现金流量动态。
3.png


通知服务

存储用户的联系信息和通知设置(如提醒和备份频率)。安排工作人员从其它服务收集所需的信息并向订阅的客户发送电子邮件。
4.png


注意

* 每一个微服务拥有自己的数据库,因此没有办法绕过API直接访问持久数据。
* 在这个项目中,我使用MongoDB作为每一个服务的主数据库。拥有一个多种类持久化架构(polyglot persistence architecture)也是很有意义的。
* 服务间(Service-to-service)通信是非常简单的:微服务仅使用同步的REST API进行通信。现实中的系统的常见做法是使用互动风格的组合。例如,执行同步的GET请求检索数据,并通过消息代理(broker)使用异步方法执行创建/更新操作,以便解除服务和缓冲消息之间的耦合。然而,这带给我们是最终的一致性

#基础设施服务
分布式系统中常见的模式,可以帮助我们描述核心服务是怎样工作的。Spring Cloud提供了强大的工具,可以增强Spring Boot应用的行为来实现这些模式。我会简要介绍一下:
5.png

##配置服务
Spring Cloud Config是分布式系统的水平扩展集中式配置服务。它使用了当前支持的本地存储、Git和Subversion等可拔插存储库层(repository layer)。

在此项目中,我使用了native profile,它简单地从本地classpath下加载配置文件。您可以在配置服务资源中查看shared目录。现在,当通知服务请求它的配置时,配置服务将响应回shared/notification-service.yml和shared/application.yml(所有客户端应用之间共享)。

客户端使用

只需要使用sprng-cloud-starter-config依赖构建Spring Boot应用,自动配置将会完成其它工作。

现在您的应用中不需要任何嵌入的properties,只需要提供有应用名称和配置服务url的bootstrap.yml即可:
spring:
application:
name: notification-service
cloud:
config:
uri: http://config:8888
fail-fast: true

使用Spring Cloud Config,您可以动态更改应用配置

比如,EmailService bean使用了@RefreshScope注解。这意味着您可以更改电子邮件的内容和主题,而无需重新构建和重启通知服务应用。

首先,在配置服务器中更改必要的属性。然后,对通知服务执行刷新请求:curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh。

您也可以使用webhook来自动执行此过程

注意

* 动态刷新存在一些限制。@RefreshScope不能和@Configuraion类一同工作,并且不会作用于@Scheduled方法。
* fail-fast属性意味着如果Spring Boot应用无法连接到配置服务,将会立即启动失败。当您一起启动所有应用时,这非常有用。
* 下面有重要的安全提示

##授权服务
负责授权的部分被完全提取到单独的服务器,它为后端资源服务提供OAuth2令牌。授权服务器用于用户授权以及在周边内进行安全的机器间通信。

在此项目中,我使用密码凭据作为用户授权的授权类型(因为它仅由本地应用UI使用)和客户端凭据作为微服务授权的授权类型。

Spring Cloud Security提供了方便的注解和自动配置,使其在服务器端或者客户端都可以很容易地实现。您可以在文档中了解到更多信息,并在授权服务器代码中检查配置明细。

从客户端来看,一切都与传统的基于会话的授权完全相同。您可以从请求中检索Principal对象、检查用户角色和其它基于表达式访问控制和@PreAuthorize注解的内容。

PiggyMetrics(帐户服务、统计服务、通知服务和浏览器)中的每一个客户端都有一个范围:用于后台服务的服务器、用于浏览器展示的UI。所以我们也可以保护控制器避免受到外部访问,例如:
@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)
public List getStatisticsByAccountName(@PathVariable String name) {
return statisticsService.findByAccountName(name);
}

##API网关
您可以看到,有三个核心服务。它们向客户端暴露外部API。在现实系统中,这个数量可以非常快速地增长,同时整个系统将变得非常复杂。实际上,一个复杂页面的渲染可能涉及到数百个服务。

理论上,客户端可以直接向每个微服务直接发送请求。但是这种方式是存在挑战和限制的,如果需要知道所有端点的地址,分别对每一段信息执行http请求,将结果合并到客户端。另一个问题是,这不是web友好协议,可能只在后端使用。

通常一个更好的方法是使用API网关。它是系统的单个入口点,用于通过将请求路由到适当的后端服务或者通过调用多个后端服务并聚合结果来处理请求。此外,它还可以用于认证、insights、压力测试、金丝雀测试(canary testing)、服务迁移、静态响应处理和主动变换管理。

Netflix开源这样的边缘服务,现在用Spring Cloud,我们可以用一个@EnabledZuulProxy注解来启用它。在这个项目中,我使用Zuul存储静态内容(UI应用),并将请求路由到适当的微服务。以下是一个简单的基于前缀(prefix-based)路由的通知服务配置:
zuul:
routes:
notification-service:
path: /notifications/**
serviceId: notification-service
stripPrefix: false

这意味着所有以/notification开头的请求将被路由到通知服务。您可以看到,里面没有硬编码的地址。Zuul使用服务发现机制来定位通知服务实例以及断路器和负载均衡器,如下所述。
##服务发现
另一种常见的架构模式是服务发现。它允许自动检测服务实例的网络位置,由于自动扩展、故障和升级,它可能会动态分配地址。

服务发现的关键部分是注册。我使用Netflix Eureka进行这个项目,当客户端需要负责确定可以用的服务实例(使用注册服务器)的位置和跨平台的负载均衡请求时,Eureka就是客户端发现模式的一个很好的例子。

使用Spring Boot,您可以使用spring-cloud-starter-eureka-server依赖、@EnabledEurekaServer注解和简单的配置属性轻松构建Eureka注册中心(Eureka Registry)。

使用@EnabledDiscoveryClient注解和带有应用名称的bootstrap.yml来启用客户端支持:
spring:
application:
name: notification-service

现在,在应用启动时,它将向Eureka服务器注册并提供元数据,如主机和端口、健康指示器URL、主页等。Eureka接收来自从属于某服务的每个实例的心跳消息。如果心跳失败超过配置的时间表,该实例将从注册表中删除。

此外,Eureka还提供了一个简单的界面,您可以通过它来跟踪运行中的服务和可用实例的数量:http://localhost:8761
6.png

##负载均衡器、断路器和Http客户端
Netflix OSS提供了另一套很棒的工具。

Ribbon

Ribbon是一个客户端负载均衡器,可以很好地控制HTTP和TCP客户端的行为。与传统的负载均衡器相比,每次线上调用都不需要额外的跳跃——您可以直接联系所需的服务。

它与Spring Cloud和服务发现是集成在一起的,可开箱即用。Eureka客户端提供了可用服务器的动态列表,因此Ribbon可以在它们之间进行平衡。

Hystrix

Hystrix是断路器模式的一种实现,它可以通过网络访问依赖来控制延迟和故障。中心思想是在具有大量微服务的分布式环境中停止级联故障。这有助于快速失败并尽快恢复——自我修复在容错系统中是非常重要的。

除了断路器控制,在使用Hystrix,您可以添加一个备用方法,在主命令失败的情况下,该方法将被调用以获取默认值。

此外,Hystrix生成每个命令的执行结果和延迟的度量,我们可以用它来监视系统的行为

Feign

Feign是一个声明式HTTP客户端,能与Ribbon和Hystrix无缝集成。实际上,通过一个spring-cloud-starter-feign依赖和@EnabledFeignClients注解,您可以使用一整套负载均衡器、断路器和HTTP客户端,并附带一个合理的的默认配置。

以下是账户服务的示例:
@FeignClient(name = "statistics-service")
public interface StatisticsServiceClient {
@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void updateStatistics(@PathVariable("accountName") String accountName, Account account);
}


* 您需要的只是一个接口
* 您可以在Spring MVC控制器和Feign方法之间共享@RequestMapping部分
* 以上示例仅指定所需要的服务ID——statistics-service,这得益于Eureka的自动发现(但显然您可以使用特定的URL访问任何资源)。

##监控仪表盘
在这个项目配置中,Hystrix的每一个微服务都通过Spring Cloud Bus(通过AMQP broker)将指标推送到Turbine。监控项目只是一个使用了TurbineHystrix仪表盘的小型Spring Boot应用。

让我们看看系统行为在负载下:账户服务调用统计服务和它在一个变化的模拟延迟下的响应。响应超时阈值设置为1秒。
7.png

##日志分析
集中式日志记录在尝试查找分布式环境中的问题时非常有用。Elasticsearch、Logstash和Kibana技术栈可让您轻松搜索和分析您的日志、利用率和网络活动数据。在我的另一个项目中已经有现成的Docker配置。
##安全

高级安全配置已经超过了此概念性项目的范围。为了更真实地模拟真实系统,请考虑使用https和JCE密钥库来加密微服务密码和配置服务器的properties内容(有关详细信息,请参阅文档)。
#基础设施自动化

部署微服务比部署单一的应用的流程要复杂得多,因为它们相互依赖。拥有完全基础设置自动化是非常重要的。我们可以通过持续交付的方式获得以下好处:

* 随时发布软件的能力。
* 任何构建都可能最终成为一个发行版本。
* 构建工件(artifact)一次,根据需要进行部署。

这是一个简单的持续交付工作流程,在这个项目的实现:

在此配置中,Travis CI为每一个成功的Git推送创建了标记镜像。因此,每一个微服务在Docker Hub上的都会有一个latest镜像,而较旧的镜像则使用Git提交的哈希进行标记。如果有需要,可以轻松部署任何一个,并快速回滚。
8.png

#如何运行全部?
这真的很简单,我建议您尝试一下。请记住,您将要启动8个Spring Boot应用、4个MongoDB实例和RabbitMq。确保您的机器上有4GB的内存。您可以随时通过网关、注册中心、配置、认证服务和账户中心运行重要的服务。

运行之前

* 安装Docker和Docker Compose。
* 配置环境变量:CONFIG_SERVICE_PASSWORD, NOTIFICATION_SERVICE_PASSWORD, STATISTICS_SERVICE_PASSWORD, ACCOUNT_SERVICE_PASSWORD, MONGODB_PASSWORD

生产模式

在这种模式下,所有最新的镜像都将从Docker Hub上拉取。只需要复制docker-compose.yml并执行docker-compose up -d即可。

开发模式

如果您想自己构建镜像(例如,在代码中进行一些修改),您需要克隆所有仓库(repository)并使用Mavne构建工件(artifact)。然后,运行docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

docker-compose.dev.yml继承了docker-compose.yml,附带额外配置,可在本地构建镜像,并暴露所有容器端口以方便开发。

重要的端点(Endpoint)

* localhost:80 —— 网关
* localhost:8761 —— Eureka仪表盘
* localhost:9000 —— Hystrix仪表盘
* localhost:8989 —— Turbine stream(Hystrix仪表盘来源)
* localhost:15672 —— RabbitMq管理

注意

所有Spring Boot应用都需要运行配置服务器才能启动。得益于Spring Boot的fail-fast属性和docker-compsoe的restart:always选项,我们可以同时启动所有容器。这意味着所有依赖的容器将尝试重新启动,直到配置服务器启动运行为止。

此外,服务发现机制在所有应用启动后需要一段时间。在实例、Eureka服务器和客户端在其本地缓存中都具有相同的元数据之前,任何服务都不可用于客户端发现,因此可能需要3次心跳。默认的心跳周期为30秒。

原文链接:Microservice Architectures With Spring Cloud and Docker(翻译:Oopsguy

Docker五大优势:持续集成、版本控制、可移植性、隔离性和安全性

Andy_Lee 发表了文章 • 0 个评论 • 192 次浏览 • 2019-05-28 22:18 • 来自相关话题

【编者的话】 随着Docker技术的不断成熟,越来越多的企业开始考虑使用Docker。Docker有很多的优势,本文主要讲述了Docker的五个最重要优势,即持续集成、版本控制、可移植性、隔离性和安全性。 对于Docker,应该不需要 ...查看全部
【编者的话】 随着Docker技术的不断成熟,越来越多的企业开始考虑使用Docker。Docker有很多的优势,本文主要讲述了Docker的五个最重要优势,即持续集成、版本控制、可移植性、隔离性和安全性。

对于Docker,应该不需要进行详细的介绍了。它是最火热的开源项目之一,通过在容器中增加一个抽象层(a layer of abstraction),就可以将应用程序部署到容器中。在看似稳定而成熟的场景下,使用Docker的好处越来越多。在这篇文章中,我不谈论Docker是什么或者Docker是怎么工作的,取而代之,我会提出使用这个不断成长的平台的五大好处。
#持续部署与测试
Docker在开发与运维的世界中具有极大的吸引力,因为它能保持跨环境的一致性。在开发与发布的生命周期中,不同的环境具有细微的不同,这些差异可能是由于不同安装包的版本和依赖关系引起的。然而,Docker可以通过确保从开发到产品发布整个过程环境的一致性来解决这个问题*Docker容器通过相关配置,保持容器内部所有的配置和依赖关系始终不变。最终,你可以在开发到产品发布的整个过程中使用相同的容器来确保没有任何差异或者人工干预。

使用Docker,你还可以确保开发者不需要配置完全相同的产品环境,他们可以在他们自己的系统上通过VirtualBox建立虚拟机来运行Docker容器。Docker的魅力在于它同样可以让你在亚马逊EC2实例上运行相同的容器。如果你需要在一个产品发布周期中完成一次升级,你可以很容易地将需要变更的东西放到Docker容器中,测试它们,并且使你已经存在的容器执行相同的变更。这种灵活性就是使用Docker的一个主要好处。和标准部署与集成过程一样,Docker可以让你构建、测试和发布镜像,这个镜像可以跨多个服务器进行部署。哪怕安装一个新的安全补丁,整个过程也是一样的。你可以安装补丁,然后测试它,并且将这个补丁发布到产品中。如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#多云平台
Docker最大的好处之一就是可移植性。在过去的几年里,所有主流的云计算提供商,包括亚马逊AWS和谷歌的GCP,都将Docker融入到他们的平台并增加了各自的支持。Docker容器能运行在亚马逊的EC2实例、谷歌的GCP实例、Rackspace服务器或者VirtualBox这些提供主机操作系统的平台上。举例来说,如果运行在亚马逊EC2实例上的Docker容器能够很容易地移植到其他几个平台上,比如说VirtualBox,并且达到类似的一致性和功能性,那这将允许你从基础设施层中抽象出来。除了AWS和GCP,Docker在其他不同的IaaS提供商也运行的非常好,例如微软的Azure、OpenStack和可以被具有不同配置的管理者所使用的Chef、Puppet、Ansible等。
#环境标准化和版本控制
通过上面的讨论,Docker容器可以在不同的开发与产品发布生命周期中确保一致性,进而标准化你的环境。除此之外,Docker容器还可以像git仓库一样,可以让你提交变更到Docker镜像中并通过不同的版本来管理它们。设想如果你因为完成了一个组件的升级而导致你整个环境都损坏了,Docker可以让你轻松地回滚到这个镜像的前一个版本。这整个过程可以在几分钟内完成,如果和虚拟机的备份或者镜像创建流程对比,那Docker算相当快的,它可以让你快速地进行复制和实现冗余。此外,启动Docker就和运行一个进程一样快。
#隔离性
Docker可以确保你的应用程序与资源是分隔开的。几个月前,Gartner发表了一篇报告,这份报告说明了运行Docker 容器进行资源隔离的效果和虚拟机(VM)管理程序一样的好,但是管理与控制方面还需要进行完善。

我们考虑这样一个场景,你在你的虚拟机中运行了很多应用程序,这些应用程序包括团队协作软件(例如Confluence)、问题追踪软件(例如JIRA)、集中身份管理系统(例如Crowd)等等。由于这些软件运行在不同的端口上,所以你必须使用Apache或者Nginx来做反向代理。到目前为止,一切都很正常,但是随着你的环境向前推进,你需要在你现有的环境中配置一个内容管理系统(例如Alfresco)。这时候有个问题发生了,这个软件需要一个不同版本的Apache Tomcat,为了满足这个需求,你只能将你现有的软件迁移到另一个版本的Tomcat上,或者找到适合你现有Tomcat的内容管理系统(Alfresco)版本。

对于上述场景,使用Docker就不用做这些事情了。Docker能够确保每个容器都拥有自己的资源,并且和其他容器是隔离的。你可以用不同的容器来运行使用不同堆栈的应用程序。除此之外,如果你想在服务器上直接删除一些应用程序是比较困难的,因为这样可能引发依赖关系冲突。而Docker可以帮你确保应用程序被完全清除,因为不同的应用程序运行在不同的容器上,如果你不在需要一款应用程序,那你可以简单地通过删除容器来删除这个应用程序,并且在你的宿主机操作系统上不会留下任何的临时文件或者配置文件。

除了上述好处,Docker还能确保每个应用程序只使用分配给它的资源(包括CPU、内存和磁盘空间)。一个特殊的软件将不会使用你全部的可用资源,要不然这将导致性能降低,甚至让其他应用程序完全停止工作。
#安全性
如上所述,Gartner也承认Docker正在快速地发展。从安全角度来看,Docker确保运行在容器中的应用程序和其他容器中的应用程序是完全分隔与隔离的,在通信流量和管理上赋予你完全的控制权。Docker容器不能窥视运行在其他容器中的进程。从体系结构角度来看,每个容器只使用着自己的资源(从进程到网络堆栈)。

作为紧固安全的一种手段,Docker将宿主机操作系统上的敏感挂载点(例如/proc和/sys)作为只读挂载点,并且使用一种写时复制系统来确保容器不能读取其他容器的数据。Docker也限制了宿主机操作系统上的一些系统调用,并且和SELinux与AppArmor一起运行的很好。此外,在Docker Hub上可以使用的Docker镜像都通过数字签名来确保其可靠性。由于Docker容器是隔离的,并且资源是受限制的,所以即使你其中一个应用程序被黑,也不会影响运行在其它Docker容器上的应用程序。
#结语
将云计算一起考虑,上面提到的这些好处能够清楚地证明Docker是一个有效的开源平台。使用Docker的好处越来越多,今天我只想强调这前五大好处。如果你使用了Docker,欢迎分享你的使用案例或者任何你觉得使用Docker带来的好处。

原文链接:5 Key Benefits of Docker: CI, Version Control, Portability, Isolation and Security(翻译:肖远昊 校对:魏小红)

五个Docker监控工具的对比

aoxiang 发表了文章 • 0 个评论 • 192 次浏览 • 2019-05-28 22:10 • 来自相关话题

【编者的话】这篇文章作者是Usman,他是服务器和基础架构工程师,有非常丰富的分布式构建经验。该篇文章主要分析评估了五种Docker监控工具,包括免费的和不免费的:Docker Stats、CAdvisor、Scout、Data Dog以及Sensu。不过作者 ...查看全部
【编者的话】这篇文章作者是Usman,他是服务器和基础架构工程师,有非常丰富的分布式构建经验。该篇文章主要分析评估了五种Docker监控工具,包括免费的和不免费的:Docker Stats、CAdvisor、Scout、Data Dog以及Sensu。不过作者还是推荐使用Data Dog。另外还有两个工具:Prometheus与Sysdig Cloud会在下一篇做介绍分析,敬请期待。

随着Docker被大规模的部署应用,如何通过可视化的方式了解Docker环境的状态以及健康变得越来越重要。这篇文章我们来回顾下监控容器的常用工具。我会基于以下标准评估这些工具:

1. 易于部署
2. 信息呈现的详细度
3. 整个部署过程中日志的聚集程度
4. 数据报警能力
5. 是否可以监控非Docker的资源
6. 成本

这些评估标准可能并不全面,但是我试图强调的是最常用的工具以及优化此六项评估标准的工具。
Docker Stats命令

本文中所有使用的命令只在亚马逊EC2上的RancherOS实例中测试过。但是我想它们应该可以在任何的Docker容器中运行。如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

我将讨论的第一个工具是Docker本身。你可能不知道Docker客户端已经提供了基本的命令行工具来检查容器的资源消耗。想要查看容器统计信息只需运行`docker stats [CONTAINER_NAME]`。这样就可以查看每个容器的CPU利用率、内存的使用量以及可用内存总量。请注意,如果你没有限制容器内存,那么该命令将显示您的主机的内存总量。但它并不意味着你的每个容器都能访问那么多的内存。另外,还可以看啊都容器通过网络发送和接收的数据总量。

$ docker stats determined_shockley determined_wozniak prickly_hypatia
CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O
determined_shockley 0.00% 884 KiB/1.961 GiB 0.04% 648 B/648 B
determined_wozniak 0.00% 1.723 MiB/1.961 GiB 0.09% 1.266 KiB/648 B
prickly_hypatia 0.00% 740 KiB/1.961 GiB 0.04% 1.898 KiB/648 B

如果想要看到更为详细的容器属性,还可以通过netcat,使用Docker远程API来查看(见下文)。发送一个HTTP GET请求`/containers/[CONTAINER_NAME]`,其中`CONTAINER_NAME`是你想要统计的容器名称。你可以从这里看到一个容器stats请求的完整响应信息。在上述的例子中你会得到缓存、交换空间以及内存的详细信息。如果要了解什么是metrics,那么你就需要精读Docker文档的Run Metrics部分

##评分:

  1. 易于部署程度:※※※※※
  2. 信息详细程度:※※※※※
  3. 集成度:无
  4. 生成警报的能力:无
  5. 监测非Docker的资源的能力:无
  6. 成本:免费

CAdvisor

我们可以使用`docker stats`命令和远程API来获取容器的状态信息。但是,如果你想要在图形界面中直接查看这些信息,那你就需要诸如CAdvisor这类的工具。CAdvisor提供了早`docker stats`命令所显示的数据的可视化界面。运行以下Docker命令,并在浏览器里访问`http://:8080/`可以看到CAdvisor的界面。你将看到CPU的使用率、内存使用率、网络吞吐量以及磁盘空间利用率。然后,你可以通过点击在网页顶部的`Docker Containers`链接,然后选择某个容器来详细了解它的使用情况。

docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest

1.png

CAdvisor是一个易于设置并且非常有用的工具,我们不用非要SSH到服务器才能查看资源消耗,而且它还给我们生成了图表。此外,当集群需要额外的资源时,压力表(pressure gauges )提供了快速预览。而且,与本文中的其他的工具不一样的是CAdvisor是免费的,并且还开源。另外,它的资源消耗也比较低。但是,它有它的局限性,它只能监控一个Docker主机。因此,如果你是多节点的话,那就比较麻烦了,你得在所有的主机上都安装一个CAdvisor,者肯定特别不方便。值得注意的是,如果你使用的是Kubernetes,你可以使用heapster来监控多节点集群。另外,在图表中的数据仅仅是时长一分钟的移动窗口,并没有方法来查看长期趋势。如果资源使用率在危险水平,它却没有生成警告的机制。如果在Docker节点的资源消耗方面,你没有任何可视化界面,那么CAdvisor是一个不错的开端来带你步入容器监控,然而如果你打算在你的容器中运行任何关键任务,那你就需要一个更强大的工具或者方法。
##评分:(忽略了heapster,因为它仅支持Kubernetes)


  1. 易于部署程度:※※※※※
  2. 信息详细程度:※※
  3. 集成度:※
  4. 生成警报的能力:无
  5. 监测非Docker的资源的能力:无
  6. 成本:免费

Scout

下一个Docker监控的方法是Scout,它解决了CAdvisor的局限性。 Scout是一个应用监控服务,它能够从很多主机和容器中获得各项监测数据,并将数据呈现在有更长时间尺度的图标中。它也可以基于这些指标生成警报。要获取Scout并运行,第一步,在scoutapp.com注册一个Scout帐户,免费的试用账号足以用来集成测试。一旦你创建了自己的帐户并登录,点击右上角的帐户名称,然后点击Account Basics来查看你的Account Key,你需要这个Key从Docker服务器来发送指标。
2.png

3.png

现在在你的主机上,创建一个名为scouts.yml的文件并将下面的文字复制到该文件中,用上边得到的Key替换到account_key。您可以对主机指定任何有意义的变量:display_name、environment与roles等属性。当他们在scout界面上呈现时,这些将用于分离各种指标。我假设有一组网站服务器列表正在运行Docker,它们都将采用如下图所示的变量。

# account_key is the only required value
account_key: YOUR_ACCOUNT_KEY
hostname: web01-host
display_name: web01
environment: production
roles: web

现在,你可以使用scout配置文件通过Docker-scout插件来运行scout。

docker run -d --name scout-agent \
-v /proc:/host/proc:ro \
-v /etc/mtab:/host/etc/mtab:ro \
-v /var/run/docker.sock:/host/var/run/docker.sock:ro \
-v `pwd`/scoutd.yml:/etc/scout/scoutd.yml \
-v /sys/fs/cgroup/:/host/sys/fs/cgroup/ \
--net=host --privileged \
soutapp/docker-scout

这样你查看Scout网页就能看到一个条目,其中display_name参数(web01)就是你在scoutd.yml里面指定的。
4.png

如果你点击它(web01)就会显示主机的详细信息。其中包括任何运行在你主机上的进程计数、cpu使用率以及内存利用率,值得注意的是在docker内部并没有进程的限制。
5.png

如果要添加Docker监控服务,需要单击Roles选项卡,然后选择所有服务。现在点击+插件模板按钮,接下来的Docker监视器会加载详细信息视图。一旦详细信息呈现出来,选择安装插件来添加到您的主机。接着会给你提供一个已安装插件的名称以及需指定要监视的容器。如果该字段是空的,插件将监控主机上所有的容器。点击完成按钮,一分钟左右你就可以在[Server Name] > Plugins中看到从Docker监控插件中获取的详细信息。该插件为每个主机显示CPU使用率、内存使用率、网络吞吐量以及容器的数量。
6.png

你点击任何一个图表,都可以拉取该指标的详细视图,该视图可以让你看到时间跨度更长的趋势。
7.png

该视图还支持过滤基于环境和服务器角色的指标。此外,你可以创建“Triggers”或警报,如果指标高于或低于配置的阈值它就给你发送电子邮件。这就允许您设置自动警报来通知您,比如,如果你的一些容器异常关闭以及容器计数低于一定数量。您还可以设置对平均CPU利用率的警报,举例来说,如果你正在运行的容器超过CPU利用率而发热,你会得到一个警告,当然你可以开启更多的主机到你的Docker集群。

要创建触发器,请选择顶部菜单的Roles>All Servers,然后选择plugins部分的Docker monitor。然后在屏幕的右侧的Plugin template Administration菜单里选择triggers。您现在应该看到一个选项“Add a Trigger”,它将应用到整个部署。
8.png

下面是一个触发器的例子,如果部署的容器数量低于3就会发出警报。
9.png

它的创建是为“所有的服务器”,当然你也可以用不同的角色标记你的主机使用服务器上创建的scoutd.yml文件。使用角色。你可以通过使用不同角色来应用触发器到部署的服务器的一个子集上。例如,你可以设置一个当在你的网络的节点的容器数量低于一定数量时的警报。即使是基于角色的触发器我仍然觉得Scout的警报系统可能做的更好。这是因为许多Docker部署具有相同主机上的多种多样的容器。在这种情况下为特定类型的容器设置触发器将是不可能的由于角色被应用到主机上的所有容器。

比起CAdvisor,使用Scout的另一个优点是,它有大量的插件,除了Docker信息他们可以吸收其他有关你的部署的数据。这使得Scout是你的一站式监控系统,而无需对系统的各种资源来安装各种不同的监控系统。

Scout的一个缺点是,它不显示有关每个主机上像CAdvisor的单独容器的详细信息。这是个问题,如果你在同一台服务器上运行大量的容器。例如,如果你想有一个触发器来提醒您的Web容器的警报,但不是Jenkins容器,这时Scout就无法支持该情况。尽管有这个缺点,Scout还是一个相当有用的工具来监控你的Docker部署。当然这要付出一些代价,每个监控的主机十美元。如果你要运行一个有多台主机的超大部署,这个代价会是个考虑因素。
##评分:


  1. 易于部署程度:※※※※
  2. 信息详细程度:※※
  3. 集成度:※※※
  4. 生成警报的能力:※※※
  5. 监测非Docker的资源的能力:支持
  6. 成本:每个主机$10

Data Dog

从Scout移步到另一个监控服务——DataDog,它既解决几个Scout的缺点又解除了CAdvisor的局限性。要使用DataDog,先在https://www.datadoghq.com/注册一个DataDog账户。一旦你登录到您的帐户,您将看到支持集成的每种类型的指令列表。从列表中选择Docker,你会得到一个Docker run命令(如下),将其复制到你的主机。该命令需要你的预先设置的API密钥,然后你可以运行该命令。大约45秒钟后您的代理将开始向DataDog系统报告。

docker run -d --privileged --name dd-agent \
-h `hostname` \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /proc/mounts:/host/proc/mounts:ro \
-v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro \
-e API_KEY=YOUR_API_KEY datadog/docker-dd-agent \

此时,容器提示你可以在DataDog Web的Events tab上处理和查看有关集群的所有动态。所有容器的启动和终止都是事件流的一部分。
10.png

您也可以点击Dashboards标签并点击创建仪表板以合计您整个群集的指标。 Datadog收集在系统中运行的所有容器的CPU使用率、内存以及I/O的指标。此外,也可以获得容器运行和停止次数以及Docker的镜像数量。Dashboard视图可以创建任何数据的图标,或者设置整个部署、主机群、容器镜像指标的图表。例如下图显示了运行容器的数量并加以镜像类型分类,此刻在我的集群运行了9个Ubuntu:14.04的容器。
11.png

您还可以通过主机分类同样的数据,如下图所示,7个容器在我的Rancher主机上运行,其余的在我的本地的笔记本电脑。
12.png

DataDog还支持一种称为Monitors的警报功能。DataDog的一个monitor相当于Scout的一个触发器,并允许您定义各种指标的阈值。 比起Scout,DataDog的警报系统相当灵活与详细。下面的例子说明如何指定您监视的Ubuntu容器的终止,因此你会监视从Ubuntu:14.04的Docker镜象所创建容器的docker.containers.running信息。
13.png

然后,特定的警报情况是,如果在我们的部署中最后5分钟有(平均)少于十个Ubuntu容器,你就会被警报。尽管这里没有显示,你会被要求填写发送出去时的指定消息在这个警报被触发后,而且还有受到此警报的目标。在当前的例子中,我用一个简单的绝对阈值。您也可以指定一个基于增量的警报,比如是在最后五分钟里停止的容器的平均计数是四的警报。
14.png

最后,使用Metrics Explorer选项卡可以临时聚集你的指标来帮助调试问题或者提取具体的数据信息。该视图允许您基于对容器镜像或主机绘制任何指标的图表。您可以将输出的数据组合成一个单一的图形或者通过镜像或主机的分组来生成一组图形。
15.png

DataDog相比scout在某些功能上做了显著地改善,方便使用以及用户友好的设计。然而这一级别伴随着额外的成本,因为每个DataDog agent价格为$15。

##评分:


  1. 易于部署程度:※※※※※
  2. 信息详细程度:※※※※※
  3. 集成度:※※※※※
  4. 生成警报的能力:支持
  5. 监测非Docker的资源的能力:※※※※※
  6. 成本:每个主机$15

Sensu Monitoring Framework

Scout和Datadog提供集中监控和报警系统,然而他们都是被托管的服务,大规模部署的话成本会很突出。如果你需要一个自托管、集中指标的服务,你可以考虑sensu open source monitoring framework。要运行Sensu服务器可以使用hiroakis/docker-sensu-server容器。这个容器会安装sensu-server、uchiwa Web界面、Redis、rabbitmq-server以及sensu-api。不幸的是sensu不支持Docker。但是,使用插件系统,您可以配置支持容器指标以及状态检查。

在开启sensu服务容器之前,你必须定义一个可以加载到服务器中检查。创建一个名为check-docker.json的文件并添加以下内容到此文件。这个文件告诉Sensu服务器在所有有docker标签的客户端上每十秒运行一个名为load-docker-metrics.sh的脚本。

{
"checks": {
"load_docker_metrics": {
"type": "metric",
"command": "load-docker-metrics.sh",
"subscribers": [
"docker"
],
"interval": 10
}
}
}

现在,您可以使用下面的命令通过我们的检查配置文件来运行Sensu服务器Docker容器。一旦你运行该命令,你就可以在浏览器输入`http://YOUR_SERVER_IP:3000`来访问uchiwa界面。

docker run -d --name sensu-server \
-p 3000:3000 \
-p 4567:4567 \
-p 5671:5671 \
-p 15672:15672 \
-v $PWD/check-docker.json:/etc/sensu/conf.d/check-docker.json \
hiroakis/docker-sensu-server

这样Sensu服务器就开启了,你就可以对每个运行有我们的Docker容器的主机上开启sensu客户端。你告诉容器将有一个名为load-docker-metrics.sh的脚本,所以让我们创建脚本,并将其放到我们的客户端容器内。创建该文件并添加如下所示的文本,将HOST_NAME替换为您的主机的逻辑名称。下面的脚本是为运行容器、所有容器以及镜像而使用Docker远程API来拉取元数据。然后它打印出来sensu的键值标示的值。该sensu服务器将读取标准输出并收集这些指标。这个例子只拉取这三个值,但根据需要,你可以使脚本尽可能详细。请注意,你也可以添加多个检查脚本,如thos,只要早前在服务配置文件中你引用过它们。你也可以定义你想要检查运行Docker容器数量降至三个以下的失败。你还可以使检查通过从检查脚本返回一个非零值失败。

#!/bin/bash
set -e

# Count all running containers
running_containers=$(echo -e "GET /containers/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock \
| tail -n +5 \
| python -m json.tool \
| grep \"Id\" \
| wc -l)
# Count all containers
total_containers=$(echo -e "GET /containers/json?all=1 HTTP/1.0\r\n" | nc -U /var/run/docker.sock \
| tail -n +5 \
| python -m json.tool \
| grep \"Id\" \
| wc -l)

# Count all images
total_images=$(echo -e "GET /images/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock \
| tail -n +5 \
| python -m json.tool \
| grep \"Id\" \
| wc -l)

echo "docker.HOST_NAME.running_containers ${running_containers}"
echo "docker.HOST_NAME.total_containers ${total_containers}"
echo "docker.HOST_NAME.total_images ${total_images}"

if [ ${running_containers} -lt 3 ]; then
exit 1;
fi

现在你已经定义了Docker载入指标检查,那就需要使用usman/sensu-client容器来启动sensu客户端。您可以使用如下所示的命令启动sensu客户端。需要注意的是,容器必须以privileged来运行以便能够访问Unix sockets,它必须有Docker socket挂载以及你上面定义的load-docker-metrics.sh脚本。确保load-docker-metrics.sh脚本在你的主机的权限标记为可执行。容器也需要将SENSU_SERVER_IP、RABIT_MQ_USER、RABIT_MQ_PASSWORD、CLIENT_NAME以及CLIENT_IP作为参数,请指定这些参数到您设置的值。其中RABIT_MQ_USER与RABIT_MQ_PASSWORD默认值是sensu和password。

docker run -d --name sensu-client --privileged \
-v $PWD/load-docker-metrics.sh:/etc/sensu/plugins/load-docker-metrics.sh \
-v /var/run/docker.sock:/var/run/docker.sock \
usman/sensu-client SENSU_SERVER_IP RABIT_MQ_USER RABIT_MQ_PASSWORD CLIENT_NAME CLIENT_IP

16.png

运行完此命令,一会儿你应该看到客户端计数增加1在uchiwa界面。如果您点击客户端图标,你应该看到,包括你刚才添加的客户端的客户端名单。我的客户端1是client-1以及指定的主机IP为192.168.1.1。
17.png

如果你点击客户端名称你应该得到检查的进一步细节。你可以看到load_docker_metrics检查在3月28日的10:22运行过。
18.png

如果你点击检查名称就可以看到检查运行的进一步细节。零表明没有错误,如果脚本失败(例如,如果您的Docker守护进程死掉),你会看到一个错误代码(非零)值。虽然在目前的文章中没有涉及这个,你也还可以使用Handlers在sensu设置这些检查失败处理程序来提醒您。此外,uchiwa只显示检查的值,而不是收集的指标。需要注意的是sensu不存储所收集的指标,它们必须被转发到一个时间序列的数据库如InfluxDB或Graphite。这也是通过Handlers做到的。如何配置指标转发到graphite可以参考这里
19.png

Sensu支持我们所有的评价标准,你可以对我们Docker容器和主机收集尽可能多的细节。此外,你能够聚合所有主机的值到一个地方,并对这些检查发出警报。这些警报并没有DataDog或Sc​​out的先进,因为你仅能够提​​醒单独的主机上检查失败。然而,Sensu的大缺点是部署的难度。虽然我已经使用Docker容器自动部署许多步骤,Sensu仍然是一个需要我们安装,启动和分开维护Redis、RabitMQ、Sensu API、uchiwa与Sensu Core的复杂系统。此外,你将需要更多的工具,如Graphite来呈现指标值以及生产部署需要定制容器,今天我已经使用了一个容器为了密码的安全以及自定义的SSL证书。除了您重启容器后才能添加更多的检查,你将不得不重新启动Sensu服务,因为这是它开始收集新的标准的唯一途径。由于这些原因,我对Sensu的在易于部署的评价相当的低。
##评分:


  1. 易于部署程度:※
  2. 信息详细程度:※※※※
  3. 集成度:※※※※
  4. 生成警报的能力:支持但有限
  5. 监测非Docker的资源的能力:※※※※※
  6. 成本:免费

总结

今天的文章涵盖了多种选项用于监控Docker容器,从免费的选择, 如Docker stats、CAdvisor或Sensu,到有偿服务,如Scout和DataDog。我的研究到目前为止DataDog似乎是用于监控Docker部署的最好的系统。只需几秒的安装以及单行命令,所有主机都在同一个地方报告指标,在UI方面,历史趋势是显而易见的,并且Datadog支持更深层次的指标以及报警。然而,$15一个主机系统对于大型部署是昂贵的。对于较大规模,自托管部署,Sensu是能够满足大多数的要求,不过在建立和管理一个Sensu集群的复杂性可能让人望而却步。很显然,有很多其他的自托管的选项,如Nagios或Icinga,他们都类似Sensu。

但愿今天这篇文章会给你一些想法对于监视容器的选择。我会继续调查其他选项,包括使用CollectD、Graphite或InfluxDB与Grafana的更精简的自我管理的容器监控系统。敬请关注更多的细节。

其他信息:发布本文后,我有一些建议去评估Prometheus和Sysdig云,两个非常好的监控Docker的选择。我在这两个服务上花了一些时间,并添加了第二部分到这个文章中。你可以在这里(译注:过后会翻译这篇)找到它。

想要了解更多关于监控和管理Docker,请参加我们的下一个Rancher在线meetup。

原文:Comparing Five Monitoring Options for Docker (翻译:田浩浩 校对:魏小红)

===========================
译者介绍
田浩浩,USYD研究生,目前在珠海从事手机应用开发工作。业余时间专注Docker的学习与研究,希望通过DockOne把最新最优秀的译文贡献给大家,与读者一起畅游Docker的海洋。

你好,SMI:Service Mesh 互操作性说明书

YiGagyeong 发表了文章 • 0 个评论 • 267 次浏览 • 2019-05-27 23:36 • 来自相关话题

【编者的话】本文主要介绍了最近发布的 Service Mesh Interface(SMI),SMI 为 Service Mesh 技术提供了通用的 API 规范,并且是生态系统友好的,为后续新兴工具的集成提供了保障。 今 ...查看全部
【编者的话】本文主要介绍了最近发布的 Service Mesh Interface(SMI),SMI 为
Service Mesh 技术提供了通用的 API 规范,并且是生态系统友好的,为后续新兴工具的集成提供了保障。

今天,我们兴奋地发布了 `Service Mesh Interface(SMI)`,它定义了一组通用的可移植 API,为开发人员提供跨不同 Service Mesh(服务网格)技术的互操作性,其中包括 Istio,Linkerd 和 Consul Connect。SMI 是一个与微软,Linkerd,HashiCorp,Solo.io,Kinvolk 和 Weaveworks 合作开展的开放项目;同样也得到了 Aspen Mesh,Canonical,Docker,Pivotal,Rancher,Red Hat 和 VMware 的支持。

多年来,网络架构的真言是让网络管道尽可能愚蠢,并在应用中构建智能。网络的职责是转发数据包,而任何关于加密,压缩或身份的逻辑则存在于网络端点内。互联网是以此真言为前提的,所以你会觉得它可以运转良好。如果你想和更多 Service Mesh 技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

但是,如今随着微服务、容器以及编排系统如 `Kubernetes` 的爆炸式增长,工程团队将要保障、管理和监控越来越多的网络端点。Service Mesh 技术通过使网络更加智能,来解决上述问题。Service Mesh 技术不是教授所有服务来加密会话,授权客户端,发出合理的遥测,并在应用程序版本之间无缝转换流量,而是将此逻辑推入网络,由一组单独的管理 API 控制。

这是 `cloud-native` 系统中比较流行的模式。我们发现,随着许多供应商为应用开发人员提供了令人兴奋的新选择,Service Mesh 技术也随之激增。问题是,转向 Service Mesh 的开发人员必须选择一个供应商,并直接对接其 API。他们被束缚在了某种 Service Mesh 的实现中。如果没有通用接口,开发人员就会失去可移植性以及灵活性,并且从广泛的生态系统中获益的能力也会受限。

SMI 提供了如下功能:

  • Kubernetes 网格的标准界面
  • 最常见的网格用例的基本功能集
  • 随着时间的推移灵活地支持新的网格功能
  • 为生态系统提供利用网格技术进行创新的空间
# SMI 覆盖了哪些功能我们与 HashiCorp,Buoyant,Solo.io 以及其他公司合作,为企业级客户所希冀的三大 Service Mesh 功能构建初始规范:[list=1]
  • 流量策略:应用跨服务应用身份和传输加密等策略
  • 流量遥测:捕获关键指标,如错误率和服务之间的延迟
  • 流量管理:在不同服务之间转移和加权流量

  • 这些只是我们希望通过 SMI 初步实现的功能。由于开发过程中有许多令人兴奋的网格功能,我们完全希望随着时间的推移,不断发展 SMI API,并期待通过新功能扩展当前规范。
    # SMI是如何工作的
    Service Mesh Interface 背后的观点并非新创。它追寻 Ingress,Network Policy 和 CNI 等现有 Kubernetes 资源的足迹。与 Ingress 或 Network Policy 一样,SMI 不提供具体实现。相反,SMI 规范定义了一组通用 API,允许网格提供者提供自己的最佳实现。与 SMI 集成可以通过两种方式实现,工具和网格提供者可以直接使用SMI API,也可以构建运算符将 SMI 转换为原生 API。

    SMI 是 Linkerd 迈向 Service Mesh 大众化的一大步,我们很高兴能够向更多的 Kubernetes 用户提供简洁和易用的 Linker 服务。
    > ——William Morgan,Linkerd 维护者



    对于跨技术和生态系统协作来说,接口的标准化对确保最佳用户体验至关重要。凭借这种精神,我们很高兴能与微软和其他公司合作开发 SMI 规范,并已经通过 Service Mesh Hub 和 SuperGloo 项目提供了首个参考实现。
    > ——Solo.io 创始人兼首席执行官,Idit Levine。



    # 生态系统友好
    对于 Service Mesh 等早期技术,我们必须为其生态系统创造创新空间,并探索解决客户问题的不同方法。随着 service mesh 技术的不断发展,SMI 提供的互操作性将有助于新兴工具和实用程序与现有网格供应商集成,而不是单独集成每个网格,像 flagger 和 SuperGloo 这样的工具就可以与 SMI 集成,从而获得跨网格功能。

    “Service Mesh 的兴趣和动力已达到了行业需要在一系列标准上进行协作的程度,这些标准可以帮助确保他们的成功。”VMware 服务网络首席架构师 Sushil Singh 表示,“Service Meshe 为应用程序的未来提供了丰富的基础功能。现在是制定标准 API 的最佳时机,这些 API 可以简化 Service Mesh 技术的消耗和功能,从而实现健康的生态系统。VMware 很高兴参与这项非常重要的工作。“



    客户和社区成员都在寻求一种方法来更好地标准化 Service Mesh 的配置和操作。随着 Service Mesh Interface(SMI)的出现,我们认为这是一种可以帮助我们最大化 Red Hat OpenShift 客户选择和灵活性的方法。这种灵活性使用户能够优先考虑实现细节的功能。
    > ——Brian Redbeard Harrington,Red Hat Service Mesh 首席产品经理



    原文链接:Hello Service Mesh Interface (SMI): A specification for service mesh interoperability (翻译:李加庆

    浅谈几种常用负载均衡架构

    Andy_Lee 发表了文章 • 0 个评论 • 193 次浏览 • 2019-05-27 17:16 • 来自相关话题

    在网站创立初期,我们一般都使用单台机器对台提供集中式服务,但随着业务量越来越大,无论性能还是稳定性上都有了更大的挑战。这时候我们就会想到通过扩容的方式来提供更好的服务。我们一般会把多台机器组成一个集群对外提供服务。然而,我们的网站对外提供的访问入口都是一个的, ...查看全部
    在网站创立初期,我们一般都使用单台机器对台提供集中式服务,但随着业务量越来越大,无论性能还是稳定性上都有了更大的挑战。这时候我们就会想到通过扩容的方式来提供更好的服务。我们一般会把多台机器组成一个集群对外提供服务。然而,我们的网站对外提供的访问入口都是一个的,比如www.taobao.com。那么当用户在浏览器输入www.taobao.com的时候如何将用户的请求分发到集群中不同的机器上呢,这就是负载均衡在做的事情。

    当前大多数的互联网系统都使用了服务器集群技术,集群即将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是Web应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器集群等。

    在实际应用中,在Web服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为Web服务器流量的入口,挑选最合适的一台Web服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的是后端的集群。

    软件负载解决的两个核心问题是:选谁、转发,其中最著名的是LVS(Linux Virtual Server)。
    1.png

    一个典型的互联网应用的拓扑结构是这样的:
    2.png

    #负载均衡分类

    现在我们知道,负载均衡就是一种计算机网络技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁碟驱动器或其它资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。那么,这种计算机技术的实现方式有多种。大致可以分为以下几种,其中最常用的是四层和七层负载均衡:
    ##二层负载均衡

    负载均衡服务器对外依然提供一个VIP(虚IP),集群中不同的机器采用相同IP地址,但机器的MAC地址不一样。当负载均衡服务器接受到请求之后,通过改写报文的目标MAC地址的方式将请求转发到目标机器实现负载均衡。
    ##三层负载均衡

    和二层负载均衡类似,负载均衡服务器对外依然提供一个VIP(虚IP),但集群中不同的机器采用不同的IP地址。当负载均衡服务器接受到请求之后,根据不同的负载均衡算法,通过IP将请求转发至不同的真实服务器。
    ##四层负载均衡

    四层负载均衡工作在OSI模型的传输层,由于在传输层,只有TCP/UDP协议,这两种协议中除了包含源IP、目标IP以外,还包含源端口号及目的端口号。四层负载均衡服务器在接受到客户端请求后,以后通过修改数据包的地址信息(IP+端口号)将流量转发到应用服务器。
    ##七层负载均衡

    七层负载均衡工作在OSI模型的应用层,应用层协议较多,常用http、radius、DNS等。七层负载就可以基于这些协议来负载。这些应用层协议中会包含很多有意义的内容。比如同一个Web服务器的负载均衡,除了根据IP加端口进行负载外,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。
    3.png

    图:四层和七层负载均衡

    对于一般的应用来说,有了Nginx就够了。Nginx可以用于七层负载均衡。但是对于一些大的网站,一般会采用DNS+四层负载+七层负载的方式进行多层次负载均衡。
    4.png

    #常用负载均衡工具

    硬件负载均衡性能优越,功能全面,但价格昂贵,一般适合初期或者土豪级公司长期使用。因此软件负载均衡在互联网领域大量使用。常用的软件负载均衡软件有Nginx、LVS、HaProxy等。

    Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件。
    ##LVS

    LVS(Linux Virtual Server),也就是Linux虚拟服务器,是一个由章文嵩博士发起的自由软件项目。使用LVS技术要达到的目标是:通过LVS提供的负载均衡技术和Linux操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。

    LVS主要用来做四层负载均衡。

    LVS架构:

    LVS架设的服务器集群系统由三个部分组成:最前端的负载均衡层(Loader Balancer),中间的服务器群组层,用Server Array表示,最底层的数据共享存储层,用Shared Storage表示。在用户看来所有的应用都是透明的,用户只是在使用一个虚拟服务器提供的高性能服务。
    5.png

    LVS的各个层次的详细介绍:

    Load Balancer层:位于整个集群系统的最前端,有一台或者多台负载调度器(Director Server)组成,LVS模块就安装在Director Server上,而Director的主要作用类似于一个路由器,它含有完成LVS功能所设定的路由表,通过这些路由表把用户的请求分发给Server Array层的应用服务器(Real Server)上。同时,在Director Server上还要安装对Real Server服务的监控模块Ldirectord,此模块用于监测各个Real Server服务的健康状况。在Real Server不可用时把它从LVS路由表中剔除,恢复时重新加入。

    Server Array层:由一组实际运行应用服务的机器组成,Real Server可以是Web服务器、Mail服务器、FTP服务器、DNS服务器、视频服务器中的一个或者多个,每个Real Server之间通过高速的LAN或分布在各地的WAN相连接。在实际的应用中,Director Server也可以同时兼任Real Server的角色。

    Shared Storage层:是为所有Real Server提供共享存储空间和内容一致性的存储区域,在物理上一般由磁盘阵列设备组成,为了提供内容的一致性,一般可以通过NFS网络文件系统共享数 据,但NFS在繁忙的业务系统中,性能并不是很好,此时可以采用集群文件系统,例如Red hat的GFS文件系统、Oracle提供的OCFS2文件系统等。

    从整个LVS结构可以看出,Director Server是整个LVS的核心,目前用于Director Server的操作系统只能是Linux和FreeBSD,Linux2.6内核不用任何设置就可以支持LVS功能,而FreeBSD作为 Director Server的应用还不是很多,性能也不是很好。对于Real Server,几乎可以是所有的系统平台,Linux、windows、Solaris、AIX、BSD系列都能很好地支持。
    ##Nginx

    Nginx(发音同engine x)是一个网页服务器,它能反向代理HTTP、HTTPS,、SMTP、POP3、IMAP的协议链接,以及一个负载均衡器和一个HTTP缓存。

    Nginx主要用来做七层负载均衡。

    并发性能:官方支持每秒5万并发,实际国内一般到每秒2万并发,有优化到每秒10万并发的。具体性能看应用场景。

    特点:

    * 模块化设计:良好的扩展性,可以通过模块方式进行功能扩展。
    * 高可靠性:主控进程和worker是同步实现的,一个worker出现问题,会立刻启动另一个worker。
    * 内存消耗低:一万个长连接(keep-alive),仅消耗2.5MB内存。
    * 支持热部署:不用停止服务器,实现更新配置文件,更换日志文件、更新服务器程序版本。
    * 并发能力强:官方数据每秒支持5万并发。
    * 功能丰富:优秀的反向代理功能和灵活的负载均衡策略。

    Nginx的基本工作模式:
    6.png

    一个master进程,生成一个或者多个worker进程。但这里master是使用root身份启动的,因为nginx要工作在80端口。而只有管理员才有权限启动小于低于1023的端口。master主要是负责的作用只是启动worker,加载配置文件,负责系统的平滑升级。其它的工作是交给worker。那当worker被启动之后,也只是负责一些web最简单的工作,而其它的工作都是由worker中调用的模块来实现的。

    模块之间是以流水线的方式实现功能的。流水线,指的是一个用户请求,由多个模块组合各自的功能依次实现完成的。比如:第一个模块只负责分析请求首部,第二个模块只负责查找数据,第三个模块只负责压缩数据,依次完成各自工作。来实现整个工作的完成。

    它们是如何实现热部署的呢?是这样的,我们前面说master不负责具体的工作,而是调用worker工作,它只是负责读取配置文件,因此当一个模块修改或者配置文件发生变化,是由master进行读取,因此此时不会影响到worker工作。在master进行读取配置文件之后,不会立即把修改的配置文件告知worker。而是让被修改的worker继续使用老的配置文件工作,当worker工作完毕之后,直接当掉这个子进程,更换新的子进程,使用新的规则。
    ##HAProxy

    HAProxy也是使用较多的一款负载均衡软件。HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,是免费、快速并且可靠的一种解决方案。特别适用于那些负载特大的web站点。运行模式使得它可以很简单安全的整合到当前的架构中,同时可以保护你的web服务器不被暴露到网络上。

    HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。

    Haproxy主要用来做七层负载均衡。

    常见负载均衡算法:

    上面介绍负载均衡技术的时候提到过,负载均衡服务器在决定将请求转发到具体哪台真实服务器时,是通过负载均衡算法来实现的。负载均衡算法可以分为两类:静态负载均衡算法和动态负载均衡算法。

    * 静态负载均衡算法包括:轮询、比率、优先权。
    * 动态负载均衡算法包括:最少连接数、最快响应速度、观察方法、预测法、动态性能分配、动态服务器补充、服务质量、服务类型、规则模式。

    轮询(Round Robin):顺序循环将请求一次顺序循环地连接每个服务器。当其中某个服务器发生第二到第7 层的故障,BIG-IP 就把其从顺序循环队列中拿出,不参加下一次的轮询,直到其恢复正常。

    以轮询的方式依次请求调度不同的服务器; 实现时,一般为服务器带上权重;这样有两个好处:

    * 针对服务器的性能差异可分配不同的负载;
    * 当需要将某个结点剔除时,只需要将其权重设置为0即可;

    优点:实现简单、高效;易水平扩展

    缺点:请求到目的结点的不确定,造成其无法适用于有写的场景(缓存,数据库写)

    应用场景:数据库或应用服务层中只有读的场景

    随机方式:请求随机分布到各个结点;在数据足够大的场景能达到一个均衡分布;

    优点:实现简单、易水平扩展

    缺点:同Round Robin,无法用于有写的场景

    应用场景:数据库负载均衡,也是只有读的场景

    哈希方式:根据key来计算需要落在的结点上,可以保证一个同一个键一定落在相同的服务器上;

    优点:相同key一定落在同一个结点上,这样就可用于有写有读的缓存场景

    缺点:在某个结点故障后,会导致哈希键重新分布,造成命中率大幅度下降

    解决:一致性哈希 or 使用keepalived保证任何一个结点的高可用性,故障后会有其它结点顶上来

    应用场景:缓存,有读有写

    一致性哈希:在服务器一个结点出现故障时,受影响的只有这个结点上的key,最大程度的保证命中率; 如twemproxy中的ketama方案; 生产实现中还可以规划指定子key哈希,从而保证局部相似特征的键能分布在同一个服务器上;

    优点:结点故障后命中率下降有限

    应用场景:缓存

    根据键的范围来负载:根据键的范围来负载,前1亿个键都存放到第一个服务器,1~2亿在第二个结点。

    优点:水平扩展容易,存储不够用时,加服务器存放后续新增数据

    缺点:负载不均;数据库的分布不均衡;

    (数据有冷热区分,一般最近注册的用户更加活跃,这样造成后续的服务器非常繁忙,而前期的结点空闲很多)

    适用场景:数据库分片负载均衡

    根据键对服务器结点数取模来负载:根据键对服务器结点数取模来负载;比如有4台服务器,key取模为0的落在第一个结点,1落在第二个结点上。

    优点:数据冷热分布均衡,数据库结点负载均衡分布;

    缺点:水平扩展较难;

    适用场景:数据库分片负载均衡

    纯动态结点负载均衡:根据CPU、IO、网络的处理能力来决策接下来的请求如何调度。

    优点:充分利用服务器的资源,保证个结点上负载处理均衡

    缺点:实现起来复杂,真实使用较少

    不用主动负载均衡:使用消息队列转为异步模型,将负载均衡的问题消灭;负载均衡是一种推模型,一直向你发数据,那么将所有的用户请求发到消息队列中,所有的下游结点谁空闲,谁上来取数据处理;转为拉模型之后,消除了对下行结点负载的问题。

    优点:通过消息队列的缓冲,保护后端系统,请求剧增时不会冲垮后端服务器;水平扩展容易,加入新结点后,直接取queue即可;
    缺点:不具有实时性;

    应用场景:不需要实时返回的场景;

    比如,12036下订单后,立刻返回提示信息:您的订单进去排队了...等处理完毕后,再异步通知;

    比率(Ratio):给每个服务器分配一个加权值为比例,根椐这个比例,把用户的请求分配到每个服务器。当其中某个服务器发生第2到第7 层的故障,BIG-IP 就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

    优先权(Priority):给所有服务器分组,给每个组定义优先权,BIG-IP 用户的请求,分配给优先级最高的服务器组(在同一组内,采用轮询或比率算法,分配用户的请求);当最高优先级中所有服务器出现故障,BIG-IP 才将请求送给次优先级的服务器组。这种方式,实际为用户提供一种热备份的方式。

    最少的连接方式(Least Connection):传递新的连接给那些进行最少连接处理的服务器。当其中某个服务器发生第2到第7 层的故障,BIG-IP 就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

    最快模式(Fastest):传递连接给那些响应最快的服务器。当其中某个服务器发生第二到第7 层的故障,BIG-IP 就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

    观察模式(Observed):连接数目和响应时间以这两项的最佳平衡为依据为新的请求选择服务器。当其中某个服务器发生第二到第7 层的故障,BIG-IP就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

    预测模式(Predictive):BIG-IP利用收集到的服务器当前的性能指标,进行预测分析,选择一台服务器在下一个时间片内,其性能将达到最佳的服务器相应用户的请求。(被BIG-IP 进行检测)

    动态性能分配(Dynamic Ratio-APM):BIG-IP 收集到的应用程序和应用服务器的各项性能参数,动态调整流量分配。

    动态服务器补充(Dynamic Server Act.):当主服务器群中因故障导致数量减少时,动态地将备份服务器补充至主服务器群。

    服务质量(QoS):按不同的优先级对数据流进行分配。

    服务类型(ToS):按不同的服务类型(在Type of Field中标识)负载均衡对数据流进行分配。

    规则模式:针对不同的数据流设置导向规则,用户可自行。

    负载均衡的几种算法Java实现代码:

    1. 轮询
    7.png

    1. 加权随机负载均衡算法
    8.png

    1. 随机负载均衡算法
    9.png

    1. 负载均衡 ip_hash算法.
    10.png


    作者:Kingreatwill

    出处:https://www.cnblogs.com/kingreatwill/p/7991151.html

    如何为Kubernetes配置多功能终端?

    hokingyang 发表了文章 • 0 个评论 • 218 次浏览 • 2019-05-27 10:07 • 来自相关话题

    Kubernetes内置了非常不错的CLI包。对于基础操作足够用了,但是对于一些高阶用户,就显得不够用了。Kubernetes社区开发了kube ops view、Grafana等基于Web的监控工具,但是如果有一个基于终端的工具会大幅度提高错误定位效率,就跟 ...查看全部
    Kubernetes内置了非常不错的CLI包。对于基础操作足够用了,但是对于一些高阶用户,就显得不够用了。Kubernetes社区开发了kube ops viewGrafana等基于Web的监控工具,但是如果有一个基于终端的工具会大幅度提高错误定位效率,就跟瑞士军刀一样实用。

    以下列出了我的苹果终端中安装的开源工具,用起来得心应手。这些小工具我基本上每天都会用到。
    ## 准备工作
    建议配置这些工具之前先安装ZSH,对苹果系统来说非常棒的开源shell,功能非常丰富而且很炫酷。
    ## k9s
    1.png

    k9s是Kubernetes集权管理最棒的CLI工具,可以通过key直接SSH进入Pod,查阅日志,删除资源等。k9s提供大量日常操作,是Kubernetes必备工具。如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
    ## kubectx
    k9s不支持Kubernetes集群config上下文之间切换,对于经常管理多个Kubernetes集群用户来说不太方便。kubectx可以提供如下操作命令进行上下文切换:
    kubectl config use-context my-context

    当然有些前提条件:

    - 需要知道集群名
    - 有类似于```set-context```的命令行

    kubectx是替换命令,如果单独运行,会列出.kube/config中的所有上下文,需要从中选择一个继续运行:
    kubectx my-context

    不需要记住这些上下文,也不需要手工选择上下文,避免出现错误命令,简单又有效。跟k9s配合,提供强大的功能组合。
    ## kubens
    搞定上下文后,可以深入到特定的命名空间,因为集群内部有很多命名空间。ahmetb先生(kubectx的贡献者)再次提供了kubens,用于命名空间的操作。
    kubens kube-system

    随后的命令默认都是基于选择的命名空间进行的。单独运行kubens会列出所有命名空间名字。
    ## kube-ps1
    如何确认在哪个上下文和命名空间操作呢?需要用如下命令:
    kubens
    kubectx
    kubectl

    为了简化,ps1是zsh中自动显示上下文和命名空间的插件:
    2.png

    有了它就可以不用命令看出目前运行的上下文和命名空间。这个插件也是高度可配置的,可以同时看上下文和命名空间,或者只看一个,或者完全关闭。
    ## popeye
    popeye是自动扫描repo中资源并将问题高亮出来的工具,这是一个很新但很有用的功能。如果需要清理集群内问题,最好安装这个工具。
    3.png

    ## stern
    如果有需求用kubectl一次看多个Pod的日志,可以用stern这个工具将日志从多个Pod中拉出来,非常方便实用。

    原文链接:How to set up a serious Kubernetes terminal(翻译:杨峰)

    微服务架构中的GraphQL

    buxie 发表了文章 • 0 个评论 • 229 次浏览 • 2019-05-27 09:45 • 来自相关话题

    #背景 在最近一篇文章《 Exploring Tokens with Stellar》中我们提到了如何利用GraphQL拼接来打造解决方案。为了更好的理解,我们使用了一种简单优雅的方式进行了介绍,首先分享下我们解决方案的整体拓扑。 ...查看全部
    #背景
    在最近一篇文章《 Exploring Tokens with Stellar》中我们提到了如何利用GraphQL拼接来打造解决方案。为了更好的理解,我们使用了一种简单优雅的方式进行了介绍,首先分享下我们解决方案的整体拓扑。
    1.png

    #GraphQL环境下微服务日益增长的麻烦
    在利用GraphQL构建编程模型时,我们发现在每一项功能当中引入离散服务能够使我们的团队快速工作并实现编程模型迭代,同时实现基于微服务与应用十二要素的一系列典型优势。另一方面,分离这些服务使得团队无法充分利用更多的诸如服务器批处理和缓存等GraphQL高级功能。同时,我们在并行状态下也试图简化客户端编程模型,以及Apollo如何在定义完善的端点上来初始化客户端,这为开发团队带来了其它的痛点。
    #GraphQL拼接如何解决我们的问题
    为了解决我们的痛点,团队成员决定去看看其他人是如何使用GraphQL来处理微服务架构,然后很快就发现了模式拼接的方法。在我们的微服务架构里,每个微服务都有其独一无二的服务端点以及为入口控制器所配置的路由规则。这种方法要求前端开发团队定义多个Apollo客户机来支持各种服务端点,或者在入口处简单路由规则之外来配置复杂的路由规则以支持到各种微服务端点的路由。通过使用模式拼接,我们能够合并来自各种支持GraphQL接口的复合视图微服务的模式,从而可以简化我们的客户机编程模型。其结果将是一个可编程的单个GraphQL端点。另外,这使得我们的客户端编程模型能够真正使用跨越多个服务的GraphQL和批处理查询,而这在以前的体系结构中是不可能做到的。如果你想和更多微服务技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
    #GraphQL拼接的架构
    GraphQL拼接是一种部署在现有拓扑上的附加运行服务(参见上面的拓扑)。我们的解决方案中在入口控制器和GraphQL端点之间部署了一个GraphQL代理进行路由流量。其核心功能由一个名为GraphQL - tools的社区Node.js模块提供,该模块由一组定义良好且需要实现的API接口组成。拼接的作用是从一组已经定义好的GraphQL端点中来导入和合并模式。此运行时服务负责将入站请求负载映射到对应合适的端点上,同时处理错误和保证安全性。
    #我们服务所使用的GraphQL拼接方法
    在下面的例子中,包含了用于合并模式的整个资源,同时这些资源也使用各种GraphQL修改查询来初始化Apollo服务。请注意,拼接此时扮演了实际服务代理的角色,并且在模式合并完成后是静态不变的。因此,如果你正在管理的拼接的GraphQL模式是不稳定的,那么你将需要定期监控这些端点的变化。在我们的例子中,利用了Kubernetes的就绪性和活跃性探测来跟踪更改,并在发生更改时来触发服务的重新加载。
    const {
    makeRemoteExecutableSchema,
    introspectSchema,
    mergeSchemas
    } = require('graphql-tools');
    const { createHttpLink } = require('apollo-link-http');
    const { setContext } = require('apollo-link-context');
    const { ApolloServer } = require('apollo-server-express');
    const fetch = require('node-fetch');
    const log4js = require('log4js');
    const logger = log4js.getLogger('server.js');
    logger.level = process.env.LOG_LEVEL || 'debug';
    const express = require('express');

    const app = express();
    const _ = require('lodash');

    const ACCOUNT_URI =
    process.env.BASE_URI || 'http://token-factory-account-service:4001'; // override for not in K8
    const REGISTRATION_URI =
    process.env.BASE_URI || 'http://token-factory-registration-service:4000'; // override for not in K8
    const STELLAR_NODE_URI = 'https://core-test.gly.sh/graphql'
    let schema = false;

    // graphql API metadata
    const graphqlApis = [
    {
    uri: STELLAR_NODE_URI //Token Factory APIs will override this default set
    },
    {
    uri: ACCOUNT_URI + '/account'
    },
    {
    uri: REGISTRATION_URI + '/registration'
    }
    ];

    // authenticate for schema usage
    const context = ({ req }) => {
    return { req };
    };

    // create executable schemas from remote GraphQL APIs
    const createRemoteExecutableSchemas = async () => {
    let schemas = [];
    for (const api of graphqlApis) {
    const http = new createHttpLink({ uri: api.uri, fetch });

    const link = setContext((request, previousContext) => {
    return {
    headers: {
    authorization: previousContext.graphqlContext
    ? previousContext.graphqlContext.req.headers.authorization
    : ''
    }
    };
    }).concat(http);

    const remoteSchema = await introspectSchema(link);
    const remoteExecutableSchema = makeRemoteExecutableSchema({
    schema: remoteSchema,
    link
    });
    schemas.push(remoteExecutableSchema);
    }
    return schemas;
    };

    const createNewSchema = async () => {
    const schemas = await createRemoteExecutableSchemas();
    if (!schemas) {
    return false;
    } else {
    return mergeSchemas({
    schemas
    });
    }
    };

    const port = 3001;
    const path = '/token-factory';
    app.path = path;

    //Kub8 health check
    app.get('/readiness', async function(req, res) {
    try {
    schema = await createNewSchema();
    if (schema) {
    const server = await new ApolloServer({ schema });
    server.applyMiddleware({ app, path });
    res.status(200).json({
    message: 'Graphql service is ready. All services are connected'
    });
    } else {
    res
    .status(500)
    .json({ err: 'Graphql service not ready. Waiting on services' });
    }
    } catch (error) {
    console.log('error', error);
    res.status(500).json({ err: 'Graphql service is unreachable' });
    }
    });

    app.get('/liveness', async function(req, res) {
    try {
    const tmpSchema = await createNewSchema();
    if (tmpSchema && _.differenceBy(tmpSchema, schema).length === 0) {
    res.status(200).json({
    message:
    'Graphql service is alive and no changes to schema have occurred'
    });
    } else {
    res.status(500).json({ err: 'Graphql schema has changed.' });
    }
    } catch (error) {
    console.log('error', error);
    res.status(500).json({ err: 'Graphql service is unreachable' });
    }
    });

    const startServer = async () => {
    app.listen({ port: port }, () => {
    logger.info(`App listening on :${port}${app.path}!`);
    });

    try {
    schema = await createNewSchema();
    if (schema) {
    const server = new ApolloServer({
    schema,
    context: context
    });
    logger.info('schema merged', schema);
    server.applyMiddleware({ app, path });
    }
    } catch (error) {
    logger.info(
    'Failed to create schema during startup. Defer to K8 probes',
    error
    );
    }
    };

    startServer();

    #远程第三方模式介绍
    在上述程序脚本的22行可以看到这样的代码:
    const STELLAR_NODE_URI = 'https://core-test.gly.sh/graphql'

    GraphQL拼接最强大的功能之一是能够使用第三方的API接口并把它们与已有的GraphQL API接口合并在一起。Stellar开发人员社区十分活跃,并为开发人员提供了许多有用的帮助。我们可以依赖的是一个位于Stellar testnet的Postgres数据库之上支持GraphQL的API层,关于这点以及关于开发者生态系统的强大功能的案例可以在《Building Stellar Apps》这篇文章中找到。这个端点增加了我们的API,并为每个Stellar核心数据库公开了一组丰富的GraphQL查询集。这真是太棒了。
    #结论
    站在以RESTAPI为中心的角度来看,GraphQL能够执行适合多个前端应用程序的细粒度查询,改变了游戏规则。通过使用GraphQL拼接,我们构建了健壮的API接口策略,既可用来消费使用,又具备了在未来添加额外微服务的扩展能力。

    原文链接:GraphQL in a Micro Services Architecture(翻译:韦峻峰)

    容器、微服务与服务网格

    cleverlzc 发表了文章 • 0 个评论 • 287 次浏览 • 2019-05-26 11:03 • 来自相关话题

    【编者的话】本文结合dotCloud的发展为例,阐述了一个基本的服务网格应该具备什么样的能力,对诸如Istio、Linkerd、Consul Connect等现代服务网格系统的基本模式进行了阐述,最后对于“自建还是购买(或者使用开源)”这个老生常谈的话题作者给 ...查看全部
    【编者的话】本文结合dotCloud的发展为例,阐述了一个基本的服务网格应该具备什么样的能力,对诸如Istio、Linkerd、Consul Connect等现代服务网格系统的基本模式进行了阐述,最后对于“自建还是购买(或者使用开源)”这个老生常谈的话题作者给出了自己的见解。

    如你所知,已经有很多关于服务网格的资料(1234),但这是另外一篇。是的!但是为什么会有这篇文章呢?因为我想给你们一些不同的视角,他们希望服务网格在10年前就已经存在,远早于Docker和Kubernetes这样的容器平台的兴起。我并不是说这个视角比其他视角更好或更差,但是由于服务网格是相当复杂的“野兽”,所以我相信多种视角有助于更好地理解它们。

    我将讨论dotCloud平台,这是一个建立在100多个微服务之上的平台,支持数千个运行在容器中的生产应用程序;我将解释在构建和运行它时所面临的挑战;以及服务网格会(或不会)提供帮助。
    # dotCloud的历史
    我已经写过关于dotCloud平台的历史和它的一些设计选择,但是我没有过多地讨论它的网络层。如果你不想深入了解我之前关于dotCloud的博客,你需要知道的是它是一个PaaS,允许客户运行各种应用程序(Java、PHP、Python等),支持广泛的数据服务(MongoDB、MySQL、Redis等)以及类似于Heroku的工作流程:你可以将代码推送到平台,平台将构建容器映像,并部署这些容器映像。

    我将告诉你流量是如何在dotCloud平台上路由的;不是因为它是特别棒或其他什么(我认为现在是比较合适的时间),但主要是因为,如果一个普通的团队需要一种在一个微服务群或一个应用程序群之间路由流量的方法,那么这种设计可以在短时间内用现在已有的工具轻松实现。因此,它将为我们提供一个很好的比较点,“如果我们破解它,我们会得到什么”和“如果我们使用现有的服务网格,我们会得到什么”,也就是老生常谈的“构建与购买”的困境。
    # 托管应用的流量路由
    部署在dotCloud上的应用程序会暴露HTTP和TCP端点。

    HTTP端点被动态地添加到Hipache负载平衡器集群的配置中。这与我们今天使用Kubernetes Ingress资源和Traefik这样的负载平衡器可以实现的功能类似。如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

    只要域名指向dotCloud的负载平衡器,客户端就可以使用它们的关联域名连接到HTTP端点。这里没有什么特别的。

    TCP端点与端口号相关联,然后端口号通过环境变量与该堆栈上的所有容器通信。

    客户端可以使用指定的主机名(类似于gateway-X.dotcloud.com)和端口号连接到TCP端点。

    该主机名将解析为一个“nats”服务器集群(与NATS没有任何关系),该集群将把传入的TCP连接路由到正确的容器(或者,在负载平衡服务的情况下,路由到正确的容器)。

    如果你熟悉Kubernetes,这可能会让你想起NodePort服务。

    dotCloud平台没有集群IP服务的等价物:为了简单起见,从内部和外部访问服务的方式是相同的。

    这非常简单,最初的HTTP和TCP路由网格的实现可能都是几百行Python代码,使用相当简单(我敢说,很天真)的算法,但是随着时间的推移,它们不断发展,以处理平台的增长和额外的需求。

    它不需要对现有应用程序代码进行大量重构。十二因素应用程序尤其可以直接使用通过环境变量提供的地址信息。
    # 它与现代服务网络有何不同?
    可观察性有限。对于TCP路由网格根本没有度量标准。至于HTTP路由网格,后来的版本提供了详细的HTTP度量,显示错误状态码和响应时间;但是现代服务网格的功能远远不止于此,它还提供了与度量收集系统(例如Prometheus)的集成。

    可观察性非常重要,不仅从操作角度(帮助我们解决问题),还可以提供安全的蓝/绿部署金丝雀部署等功能。

    路由效率也受到限制。在dotCloud路由网格中,所有流量都必须经过一组专用路由节点。这意味着可能跨越几个AZ(可用性区域)边界,并显著增加延迟。我记得对一些代码进行故障排除,这些代码发出100多个SQL请求来显示给定的页面,并为每个请求打开了到SQL服务器的新连接。在本地运行时,页面会立即加载,但在dotCloud上运行时,需要几秒钟,因为每个TCP连接(以及随后的SQL请求)都需要几十毫秒才能完成。在这种特定的情况下,使用持久连接起了作用。

    现代服务网络做得更好。首先,通过确保连接在源位置路由。逻辑流仍然是客户端-->网格-->服务,但是现在网格在本地运行,而不是在远程节点上运行,因此客户端-->网格连接是本地连接,因此速度非常快(微秒而不是毫秒)。

    现代服务网格还实现了更智能的负载平衡算法。通过监控后端的运行及健康状况,它们可以在更快的后端上发送更多的流量,从而提高整体性能。

    随着现代服务网络的出现,安全性也越来越强。dotCloud路由网格完全在EC2 Classic上运行,并且没有加密流量(假设如果有人设法嗅探EC2上的网络流量,那么无论如何都会遇到更大的问题)。现代服务网格可以透明地保护我们所有的通信,例如通过相互的TLS身份验证和随后的加密。
    # 平台服务的流量路由
    OK,我们已经讨论了应用程序是如何通信的,但是dotCloud平台本身呢?

    平台本身由大约100个微服务组成,负责各种功能。其中一些服务接受来自其他服务的请求,而其中一些服务是后台工作应用,它们将连接到其他服务,但不能自己接收连接。无论哪种方式,每个服务都需要知道它需要连接到的地址的端点。

    许多高级服务都可以使用上面描述的路由网格。事实上,dotCloud平台的100多个微服务中有很大一部分是作为常规应用程序部署在dotCloud平台上的。但是少数低级服务(特别是那些实现路由网格的服务)需要一些更简单的东西,需要更少的依赖关系(因为它们不能依靠自己来运行;这是一个老生常谈的“先有鸡还是先有蛋”的问题)。

    通过直接在几个关键节点上启动容器,而不是依赖于平台的构建器、调度程序和运行器服务,部署了这些底层的基本平台服务。如果你想要与现代容器平台进行比较,这就像直接在节点上运行Docker来启动我们的控制平面,而不是让Kubernetes为我们做这件事。这与kubeadmbootkube在引导自托管集群时使用的静态Pod的概念非常相似。

    这些服务以一种非常简单和粗糙的方式被公开:有一个YAML文件列出了这些服务,将它们的名称映射到它们的地址;作为其部署的一部分,这些服务的每个使用者都需要一份该YAML文件的副本。

    一方面,这是非常强大的,因为它不涉及像ZooKeeper那样维护外部键值存储(记住,etcd或Consul在那个时候不存在)。另一方面,这使得服务难以移动。每次移动服务时,它的所有消费者都需要接收更新的YAML文件(并且可能会重新启动)。不太方便!

    我们开始实现的解决方案是让每个消费者都连接到一个本地代理。使用者不需要知道服务的完整地址+端口,只需要知道它的端口号,并通过localhost进行连接。本地代理将处理该连接,并将其路由到实际后端。现在,当一个后端需要移动到另一台机器上,或按比例放大或缩小,而不是更新它的所有消费者,我们只需要更新所有这些本地代理;我们不再需要重新启动消费者。

    (还计划将流量封装在TLS连接中,并在接收端使用另一个代理来打开TLS并验证证书,而不涉及接收服务,该服务将被设置为仅在本地主机上接受连接。稍后会详细介绍。)

    这与AirBNB的SmartStack非常相似;与SmartStack实现并部署到生产环境的显著区别是,当dotCloud转向Docker时,它的新的内部路由网格被搁置了。

    我个人认为SmartStack是诸如Istio、Linkerd、Consul Connect等系统的先驱之一,因为所有这些系统都遵循这种模式:

    • 在每个节点上运行代理
    • 消费者连接到代理
    • 后端改变时,控制平面更新代理的配置
    # 今天实现一个服务网格如果我们今天必须实现类似的网格,我们可以使用类似的原则。例如,我们可以设置一个内部域名系统区域,将服务名映射到127.0.0.0/8空间中的地址。然后在集群的每个节点上运行HAProxy,接受每个服务地址(在127.0.0.0/8子网中)上的连接,并将它们转发/负载平衡到适当的后端。HAProxy配置可以由confd管理,允许在etcd或Consul中存储后端信息,并在需要时自动将更新的配置推送到HAProxy。这就是Istio的工作原理!但是有一些不同之处:
    • 它使用Envoy Proxy而不是HAProxy
    • 它使用Kubernetes API而不是etcd或Consul来存储后端配置
    • 服务在内部子网中分配地址(Kubernetes集群IP地址),而不是127.0.0.0/8
    • 它有一个额外的组件(Citadel),用于在客户机和服务器之间添加相互的TLS身份验证
    • 它增加了对诸如断路、分布式跟踪、金丝雀部署等新特性的支持

    让我们快速回顾一下这些差异。
    ## Envoy Proxy
    Envoy Proxy由Lyft撰写。它与其他代理(如HAProxy、NGINX、Traefik)有许多相似之处,但Lyft编写它是因为它们需要当时这些代理中不存在的功能,而且构建一个新的代理比扩展现有代理更有意义。

    Envoy可以单独使用。如果有一组给定的服务需要连接到其他服务,可以把它连接到Envoy,然后动态地配置和重新配置其他服务的Envoy的位置,而得到很多漂亮的额外的功能,比如域的可观测性。这里,没有使用定制的客户端库,也没有在代码中添加跟踪调用,而是将流量定向到Envoy,让它为我收集指标。

    但Envoy也可以用作服务网格的数据平面。这意味着现在将由该服务网格的控制平面配置Envoy。
    ## 控制平面
    说到控制平面,Istio依赖于Kubernetes API。这与使用confd没有太大的不同。confd依赖etcd或Consul来监视数据存储中的一组密钥。Istio依赖Kubernetes API来监视一组Kubernetes资源。

    Aparte:我个人认为阅读Kubernetes API描述非常有帮助。

    Kubernetes API服务器是一个“哑服务器”,它提供API资源上的存储、版本控制、验证、更新和监视语义。



    Istio是为与Kubernetes合作而设计的;如果你想在Kubernetes之外使用它,则需要运行Kubernetes API服务器的实例(以及支持的etcd服务)。
    ## 服务地址
    Istio依赖Kubernetes分配的集群IP地址,因此Istio得到一个内部地址(不在127.0.0.1/8范围)。

    在没有Istio的Kubernetes集群上,前往给定服务的ClusterIP地址的流量被kube-proxy拦截,并发送到该代理的后端。更具体地说,如果你想确定技术细节:kube-proxy设置iptables规则(或IPVS负载平衡器,取决于它是如何设置的)来重写连接到集群IP地址的目标IP地址。

    一旦Istio安装在Kubernetes集群上,就不会发生任何变化,直到通过将sidecar容器注入到使用者Pod中,显式地为给定的使用者甚至整个名称空间启用Istio。sidecar将运行一个Envoy实例,并设置一些iptables规则来拦截到其他服务的流量,并将这些流量重定向到Envoy。

    结合Kubernetes DNS集成,这意味着我们的代码可以连接到一个服务名,一切都可以正常工作。换句话说,比如我们的代码向`http://api/v1/users/4242`发起一个请求,`api`将解析到10.97.105.48,一条iptables规则将解释连接到10.97.105.48并重定向到本地Envoy代理,本地代理将这个请求路由到实际的API后端。
    ## 额外的铃声和哨声
    Istio还可以通过名为Citadel的组件通过mTLS(双向TLS)提供端到端加密和身份验证。

    它还包括混合器,Envoy组件可以查询每一个请求,对请求进行一个临时的决定取决于各种因素,例如请求头、后端负载(别担心,有丰富的规定以确保混合高度可用,即使它休息,Envoy可以继续代理流量)。

    当然,我提到了可观察性。Envoy在提供分布式跟踪的同时收集大量的度量指标。微服务架构,如果单个API请求必须经过微服务A、B、C和D,分布式跟踪将添加一个惟一的标识符请求进入系统,并保留标识符在子请求中,所有这些微服务允许收集所有相关的调用、延迟等。
    # 自建还是购买
    Istio以复杂著称。相比之下,使用我们今天拥有的工具,构建像我在本文开头描述的那样的路由网格相对比较简单。那么,构建我们自己的服务网格是否有意义呢?

    如果我们有适度的需求(如果我们不需要可观察性,断路器,和其他细节),我们可能想建立自己的。但是如果我们正在使用Kubernetes,我们甚至可能不需要这样做,因为Kubernetes已经提供了基本的服务发现和负载平衡。

    现在,如果我们有高级的需求,购买服务网格可能是一个更好的选择。(由于Istio是开源的,所以它并不总是真正的购买,但是我们仍然需要投入工程时间来理解它是如何工作、部署和运行的。)
    #如何选择Istio、Linkerd和Consul Connect
    到目前为止,我们只讨论了Istio,但它并不是唯一的服务网格。Linkerd是另一个流行的选择,还有Consul Connect

    我们应该选哪一个呢?

    实际上在这一点上我也不好说,我不认为我有足够的了解能够帮助任何人做决策。不过,已经有一些有趣的文章比较它们(12),甚至基准测试

    一种值得一提并且很有潜力的方法是使用像SuperGloo这样的工具。SuperGloo提供了一个抽象层来简化和统一服务网格公开的API。我们可以使用SuperGloo提供的更简单的构造,并无缝地从一个服务网格切换到另一个服务网格,而不是学习各种服务网格的特定API(在我看来,相对复杂)。有点像我们有一个描述HTTP前端和后端的中间配置格式,能够为NGINX、HAProxy、Traefik、Apache生成实际配置

    我已经使用SuperGloo稍微涉足Istio,在未来的博客文章中,我想说明如何使用SuperGloo将Isio或Linkerd添加到现有的集群中,以及后者是否能实现它的承诺,即允许我在不重写配置的情况下从一个路由网格切换到另一个。

    如果你喜欢这篇文章,并且想让我尝试一些具体的场景,我很乐意听到你的消息!

    原文链接:Containers, microservices, and service meshes

    译者:Mr.lzc,软件研发工程师、DevOpsDays深圳组织者&志愿者,目前供职于华为,从事云存储工作,以Cloud Native方式构建云文件系统服务,专注于K8s、微服务领域。

    使用Consul做服务发现的若干姿势

    阿娇 发表了文章 • 0 个评论 • 255 次浏览 • 2019-05-25 22:58 • 来自相关话题

    从2016年起就开始接触Consul,使用的主要目的就是做服务发现,后来逐步应用于生产环境,并总结了少许使用经验。这两年微服务越来越火,使用Consul的人也越来越多,经常有人问一些问题,比如: * 服务注册到节点后,其他节点为什 ...查看全部
    从2016年起就开始接触Consul,使用的主要目的就是做服务发现,后来逐步应用于生产环境,并总结了少许使用经验。这两年微服务越来越火,使用Consul的人也越来越多,经常有人问一些问题,比如:

    * 服务注册到节点后,其他节点为什么没有同步?
    * Client是干什么的?(Client有什么作用?)
    * 能不能直接注册到Server?(是否只有Server节点就够了?)
    * 服务信息是保存在哪里的?
    * 如果节点挂了健康检查能不能转移到别的节点?

    有些人可能对服务注册和发现还没有概念,有些人可能使用过其它服务发现的工具,比如ZooKeeper,etcd,会有一些先入为主的经验。这篇文章将结合Consul的官方文档和自己的实际经验,谈一下Consul做服务发现的方式,文中尽量不依赖具体的框架和开发语言,从原理上进行说明,希望能够讲清楚上边的几个问题。如果你想和更多 Consul 技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
    #为什么使用服务发现

    防止硬编码、容灾、水平扩缩容、提高运维效率等等,只要你想使用服务发现总能找到合适的理由。

    一般的说法是因为使用微服务架构。传统的单体架构不够灵活不能很好的适应变化,从而向微服务架构进行转换,而伴随着大量服务的出现,管理运维十分不便,于是开始搞一些自动化的策略,服务发现应运而生。所以如果需要使用服务发现,你应该有一些对服务治理的痛点。

    但是引入服务发现就可能引入一些技术栈,增加系统总体的复杂度,如果你只有很少的几个服务,比如10个以下,并且业务不怎么变化,吞吐量预计也很稳定,可能就没有必要使用服务发现。
    #Consul内部原理

    下面这张图来源于Consul官网,很好的解释了Consul的工作原理,先大致看一下。
    1.png

    首先Consul支持多数据中心,在上图中有两个DataCenter,他们通过Internet互联,同时请注意为了提高通信效率,只有Server节点才加入跨数据中心的通信。

    在单个数据中心中,Consul分为Client和Server两种节点(所有的节点也被称为Agent),Server节点保存数据,Client负责健康检查及转发数据请求到Server;Server节点有一个Leader和多个Follower,Leader节点会将数据同步到Follower,Server的数量推荐是3个或者5个,在Leader挂掉的时候会启动选举机制产生一个新的Leader。

    集群内的Consul节点通过gossip协议(流言协议)维护成员关系,也就是说某个节点了解集群内现在还有哪些节点,这些节点是Client还是Server。单个数据中心的流言协议同时使用TCP和UDP通信,并且都使用8301端口。跨数据中心的流言协议也同时使用TCP和UDP通信,端口使用8302。

    集群内数据的读写请求既可以直接发到Server,也可以通过Client使用RPC转发到Server,请求最终会到达Leader节点,在允许数据轻微陈旧的情况下,读请求也可以在普通的Server节点完成,集群内数据的读写和复制都是通过TCP的8300端口完成。
    #Consul服务发现原理

    下面这张图是自己画的,基本描述了服务发现的完整流程,先大致看一下。
    2.png

    首先需要有一个正常的Consul集群,有Server,有Leader。这里在服务器Server1、Server2、Server3上分别部署了Consul Server,假设他们选举了Server2上的Consul Server节点为Leader。这些服务器上最好只部署Consul程序,以尽量维护Consul Server的稳定。

    然后在服务器Server4和Server5上通过Consul Client分别注册Service A、B、C,这里每个Service分别部署在了两个服务器上,这样可以避免Service的单点问题。服务注册到Consul可以通过HTTP API(8500端口)的方式,也可以通过Consul配置文件的方式。Consul Client可以认为是无状态的,它将注册信息通过RPC转发到Consul Server,服务信息保存在Server的各个节点中,并且通过Raft实现了强一致性。

    最后在服务器Server6中Program D需要访问Service B,这时候Program D首先访问本机Consul Client提供的HTTP API,本机Client会将请求转发到Consul Server,Consul Server查询到Service B当前的信息返回,最终Program D拿到了Service B的所有部署的IP和端口,然后就可以选择Service B的其中一个部署并向其发起请求了。如果服务发现采用的是DNS方式,则Program D中直接使用Service B的服务发现域名,域名解析请求首先到达本机DNS代理,然后转发到本机Consul Client,本机Client会将请求转发到Consul Server,Consul Server查询到Service B当前的信息返回,最终Program D拿到了Service B的某个部署的IP和端口。

    图中描述的部署架构笔者认为是最普适最简单的方案,从某些默认配置或设计上看也是官方希望使用者采用的方案,比如8500端口默认监听127.0.0.1,当然有些同学不赞同,后边会提到其他方案。
    #Consul实际使用

    为了更快的熟悉Consul的原理及其使用方式,最好还是自己实际测试下。

    Consul安装十分简单,但是在一台机器上不方便搭建集群进行测试,使用虚拟机比较重,所以这里选择了docker。这里用了Windows 10,需要是专业版,因为Windows上的Docker依赖Hyper-V,而这个需要专业版才能支持。这里对于Docker的使用不会做过多的描述,如果遇到相关问题请搜索一下。
    #安装Docker

    通过这个地址下载安装:

    https://store.docker.com/editions/community/docker-ce-desktop-windows

    安装完成后打开 Windows PowerShell,输入docker –version,如果正常输出Docker版本就可以了。
    #启动Consul集群

    在 Windows PowerShell中执行命令拉取最新版本的Consul镜像:
    docker pull consul

    然后就可以启动集群了,这里启动4个Consul Agent,3个Server(会选举出一个leader),1个Client。
    #启动第1个Server节点,集群要求要有3个Server,将容器8500端口映射到主机8900端口,同时开启管理界面
    docker run -d --name=consul1 -p 8900:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui

    #启动第2个Server节点,并加入集群
    docker run -d --name=consul2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2

    #启动第3个Server节点,并加入集群
    docker run -d --name=consul3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2

    #启动第4个Client节点,并加入集群
    docker run -d --name=consul4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.2

    第1个启动容器的IP一般是172.17.0.2,后边启动的几个容器IP会排着来:172.17.0.3、172.17.0.4、172.17.0.5。

    这些Consul节点在Docker的容器内是互通的,他们通过桥接的模式通信。但是如果主机要访问容器内的网络,需要做端口映射。在启动第一个容器时,将Consul的8500端口映射到了主机的8900端口,这样就可以方便的通过主机的浏览器查看集群信息。
    3.png

    进入容器consul1:
    docker exec -it consul1 /bin/sh

    #执行ls后可以看到consul就在根目录
    ls

    输入exit可以跳出容器。
    #服务注册

    自己写一个web服务,用最熟悉的开发语言就好了,不过需要在容器中能够跑起来,可能需要安装运行环境,比如Python、Java、.Net Core等的SDK及Web服务器,需要注意的是Consul的Docker镜像基于alpine系统,具体运行环境的安装请搜索一下。

    这里写了一个hello服务,通过配置文件的方式注册到Consul,服务的相关信息:

    * name:hello,服务名称,需要能够区分不同的业务服务,可以部署多份并使用相同的name注册。
    * id:hello1,服务id,在每个节点上需要唯一,如果有重复会被覆盖。
    * address:172.17.0.5,服务所在机器的地址。
    * port:5000,服务的端口。
    * 健康检查地址:http://localhost:5000/,如果返回HTTP状态码为200就代表服务健康,每10秒Consul请求一次,请求超时时间为1秒。

    请将下面的内容保存成文件services.json,并上传到容器的/consul/config目录中。
     {
    "services": [
    {
    "id": "hello1",
    "name": "hello",
    "tags": [
    "primary"
    ],
    "address": "172.17.0.5",
    "port": 5000,
    "checks": [
    {
    "http": "http://localhost:5000/",
    "tls_skip_verify": false,
    "method": "Get",
    "interval": "10s",
    "timeout": "1s"
    }
    ]
    }
    ]
    }

    复制到consul config目录:
    docker cp {这里请替换成services.json的本地路径} consul4:/consul/config

    重新加载Consul配置:
    consul reload

    然后这个服务就注册成功了。可以将这个服务部署到多个节点,比如部署到consul1和consul4,并同时运行。
    4.png

    #服务发现

    服务注册成功以后,调用方获取相应服务地址的过程就是服务发现。Consul提供了多种方式。
    ##HTTP API方式:

    curl http://127.0.0.1:8500/v1/health/service/hello?passing=true

    返回的信息包括注册的Consul节点信息、服务信息及服务的健康检查信息。这里用了一个参数passing=true,会自动过滤掉不健康的服务,包括本身不健康的服务和不健康的Consul节点上的服务,从这个设计上可以看出Consul将服务的状态绑定到了节点的状态。

    如果服务有多个部署,会返回服务的多条信息,调用方需要决定使用哪个部署,常见的可以随机或者轮询。为了提高服务吞吐量,以及减轻Consul的压力,还可以缓存获取到的服务节点信息,不过要做好容错的方案,因为缓存服务部署可能会变得不可用。具体是否缓存需要结合自己的访问量及容错规则来确定。

    上边的参数passing默认为false,也就是说不健康的节点也会返回,结合获取节点全部服务的方法,这里可以做到获取全部服务的实时健康状态,并对不健康的服务进行报警处理。
    ##DNS方式:

    hello服务的域名是:hello.service.dc1.consul,后边的service代表服务,固定;dc1是数据中心的名字,可以配置;最后的consul也可以配置。

    官方在介绍DNS方式时经常使用dig命令进行测试,但是alpine系统中没有dig命令,也没有相关的包可以安装,但是有人实现了,下载下来解压到bin目录就可以了。
    curl -L https://github.com/sequenceiq/docker-alpine-dig/releases/download/v9.10.2/dig.tgz|tar -xzv -C /usr/local/bin

    然后执行dig命令:

    dig @127.0.0.1 -p 8600 hello.service.dc1.consul. ANY

    如果报错:parse of /etc/resolv.conf failed ,请将resolv.conf中的search那行删掉。

    正常的话可以看到返回了服务部署的IP信息,如果有多个部署会看到多个,如果某个部署不健康了会自动剔除(包括部署所在节点不健康的情况)。需要注意这种方式不会返回服务的端口信息。

    使用DNS的方式可以在程序中集成一个DNS解析库,也可以自定义本地的DNS Server。自定义本地DNS Server是指将.consul域的请求全部转发到Consul Agent,Windows上有DNS Agent,Linux上有Dnsmasq;对于非Consul提供的服务则继续请求原DNS;使用DNS Server时Consul会随机返回具体服务的多个部署中的一个,仅能提供简单的负载均衡。

    DNS缓存问题:DNS缓存一般存在于应用程序的网络库、本地DNS客户端或者代理,Consul Sever本身可以认为是没有缓存的(为了提高集群DNS吞吐量,可以设置使用普通Server上的陈旧数据,但影响一般不大),DNS缓存可以减轻Consul Server的访问压力,但是也会导致访问到不可用的服务。使用时需要根据实际访问量和容错能力确定DNS缓存方案。
    ##Consul Template

    Consul Template是Consul官方提供的一个工具,严格的来说不是标准的服务发现方式。这个工具会通过Consul监听数据变化然后替换模板中使用的标签,并发布替换后的文件到指定的目录。在Nginx等Web服务器做反向代理和负载均衡时特别有用。

    Consul的docker镜像中没有集成这个工具,需要自己安装,比较简单:
    curl -L https://releases.hashicorp.com/consul-template/0.19.5/consul-template_0.19.5_linux_amd64.tgz|tar -xzv -C /usr/local/bin

    然后创建一个文件:in.tpl,内容为:
     {{ range service "hello" }}
    server {{ .Name }}{{ .Address }}:{{ .Port }}{{ end }}

    这个标签会遍历hello服务的所有部署,并按照指定的格式输出。在此文件目录下执行:
    nohup consul-template -template "in.tpl:out.txt" &

    现在你可以cat out.txt查看根据模板生产的内容,新增或者关闭服务,文件内容会自动更新。

    此工具我没有用在生产环境,详细使用请访问:https://github.com/hashicorp/consul-template
    #节点和服务注销

    节点和服务的注销可以使用HTTP API:

    * 注销任意节点和服务:/catalog/deregister
    * 注销当前节点的服务:/agent/service/deregister/:service_id

    注意:

    如果注销的服务还在运行,则会再次同步到catalog中,因此应该只在agent不可用时才使用catalog的注销API。

    节点在宕机时状态会变为failed,默认情况下72小时后会被从集群移除。

    如果某个节点不继续使用了,也可以在本机使用consul leave命令,或者在其它节点使用consul force-leave 节点Id,则节点上的服务和健康检查全部注销。
    #Consul的健康检查

    Consul做服务发现是专业的,健康检查是其中一项必不可少的功能,其提供Script/TCP/HTTP+Interval,以及TTL等多种方式。服务的健康检查由服务注册到的Agent来处理,这个Agent既可以是Client也可以是Server。

    很多同学都使用ZooKeeper或者etcd做服务发现,使用Consul时发现节点挂掉后服务的状态变为不可用了,所以有同学问服务为什么不在各个节点之间同步?这个根本原因是服务发现的实现原理不同。
    ##Consul与ZooKeeper、etcd的区别

    后边这两个工具是通过键值存储来实现服务的注册与发现。

    * ZooKeeper利用临时节点的机制,业务服务启动时创建临时节点,节点在服务就在,节点不存在服务就不存在。
    * etcd利用TTL机制,业务服务启动时创建键值对,定时更新ttl,ttl过期则服务不可用。

    ZooKeeper和etcd的键值存储都是强一致性的,也就是说键值对会自动同步到多个节点,只要在某个节点上存在就可以认为对应的业务服务是可用的。

    Consul的数据同步也是强一致性的,服务的注册信息会在Server节点之间同步,相比ZooKeeper、etcd,服务的信息还是持久化保存的,即使服务部署不可用了,仍旧可以查询到这个服务部署。但是业务服务的可用状态是由注册到的Agent来维护的,Agent如果不能正常工作了,则无法确定服务的真实状态,并且Consul是相当稳定了,Agent挂掉的情况下大概率服务器的状态也可能是不好的,此时屏蔽掉此节点上的服务是合理的。Consul也确实是这样设计的,DNS接口会自动屏蔽挂掉节点上的服务,HTTP API也认为挂掉节点上的服务不是passing的。

    鉴于Consul健康检查的这种机制,同时避免单点故障,所有的业务服务应该部署多份,并注册到不同的Consul节点。部署多份可能会给你的设计带来一些挑战,因为调用方同时访问多个服务实例可能会由于会话不共享导致状态不一致,这个有许多成熟的解决方案,可以去查询,这里不做说明。
    ##健康检查能不能支持故障转移?

    上边提到健康检查是由服务注册到的Agent来处理的,那么如果这个Agent挂掉了,会不会有别的Agent来接管健康检查呢?答案是否定的。

    从问题产生的原因来看,在应用于生产环境之前,肯定需要对各种场景进行测试,没有问题才会上线,所以显而易见的问题可以屏蔽掉;如果是新版本Consul的BUG导致的,此时需要降级;如果这个BUG是偶发的,那么只需要将Consul重新拉起来就可以了,这样比较简单;如果是硬件、网络或者操作系统故障,那么节点上服务的可用性也很难保障,不需要别的Agent接管健康检查。

    从实现上看,选择哪个节点是个问题,这需要实时或准实时同步各个节点的负载状态,而且由于业务服务运行状态多变,即使当时选择出了负载比较轻松的节点,无法保证某个时段任务又变得繁重,可能造成新的更大范围的崩溃。如果原来的节点还要启动起来,那么接管的健康检查是否还要撤销,如果要,需要记录服务们最初注册的节点,然后有一个监听机制来触发,如果不要,通过服务发现就会获取到很多冗余的信息,并且随着时间推移,这种数据会越来越多,系统变的无序。

    从实际应用看,节点上的服务可能既要被发现,又要发现别的服务,如果节点挂掉了,仅提供被发现的功能实际上服务还是不可用的。当然发现别的服务也可以不使用本机节点,可以通过访问一个Nginx实现的若干Consul节点的负载均衡来实现,这无疑又引入了新的技术栈。

    如果不是上边提到的问题,或者你可以通过一些方式解决这些问题,健康检查接管的实现也必然是比较复杂的,因为分布式系统的状态同步是比较复杂的。同时不要忘了服务部署了多份,挂掉一个不应该影响系统的快速恢复,所以没必要去做这个接管。
    #Consul的其它部署架构

    如果你实在不想在每个主机部署Consul Client,还有一个多路注册的方案可供选择,这是交流群中获得的思路。
    5.png

    如图所示,在专门的服务器上部署Consul Client,然后每个服务都注册到多个Client,这里为了避免服务单点问题还是每个服务部署多份,需要服务发现时,程序向一个提供负载均衡的程序发起请求,该程序将请求转发到某个Consul Client。这种方案需要注意将Consul的8500端口绑定到私网IP上,默认只有127.0.0.1。

    这个架构的优势:

    * Consul节点服务器与应用服务器隔离,互相干扰少;
    * 不用每台主机都部署Consul,方便Consul的集中管理;
    * 某个Consul Client挂掉的情况下,注册到其上的服务仍有机会被访问到;

    但也需要注意其缺点:

    * 引入更多技术栈:负载均衡的实现,不仅要考虑Consul Client的负载均衡,还要考虑负载均衡本身的单点问题。
    * Client的节点数量:单个Client如果注册的服务太多,负载较重,需要有个算法(比如hash一致)合理分配每个Client上的服务数量,以及确定Client的总体数量。
    * 服务发现要过滤掉重复的注册,因为注册到了多个节点会认为是多个部署(DNS接口不会有这个问题)。

    这个方案其实还可以优化,服务发现使用的负载均衡可以直接代理Server节点,因为相关请求还是会转发到Server节点,不如直接就发到Server。
    ##是否可以只有Server?

    这个问题的答案还是有关服务数量的问题,首先Server的节点数量不是越多越好,3个或者5个是推荐的数量,数量越多数据同步的处理越慢(强一致性);然后每个节点可以注册的服务数量是有上限的,这个受限于软硬件的处理能力。所以如果你的服务只有10个左右,只有Server问题是不大的,但是这时候有没有必要使用Consul呢?因此正常使用Consul的时候还是要有Client才好,这也符合Consul的反熵设计。

    大家可以将这个部署架构与前文提到的普适架构对比下,看看哪个更适合自己,或者你有更好的方案欢迎分享出来。
    #后记

    在编写这篇文章的时候,发现很多地方还不了解,很多框架也没有使用过,增长了不少见识,同时确认了一些之前似是而非的细节,但是文中仍可能有些理解错误,或者说的不是很清楚的地方。

    原文链接:使用Consul做服务发现的若干姿势