Saturday, October 31, 2015

OpenStack Summit 2015 Tokyo 有感

本次峰会是 10.27 ~ 10.30,四天在东京的品川站附近召开,6000 多人参会,几百个主会 speak 和各个项目的 design summit。
因为要做一个有关容器和网络的 speak,所以,虽经波折,最终还是按时参加了峰会。业余玩社区确实挑战比较大。
整体感受是,时间很紧,内容很多,身体压力很大。虽然只挑了最核心最热门的话题去听,也是从早到晚急匆匆地从一个会场赶到另一个(好几个 building)。一天下来,疲劳的很。

社区,不只是技术

开源项目的成功,除了技术外,往往还有很多很重要的因素。
比如怎么运营社区,怎么跟商业公司合作,怎么处理各个团队的关系……
毫无疑问,OpenStack 到今天能这么火,在各个方面做得都是非常优秀的。
本届大会,基本上越大的主题演讲 topic 都越浅显一些,但是人满为患;design summit 则集中到具体项目进行设计的讨论,反而人气没那么旺。
参加的人员,技术人员仍然是主体,但是非技术人员也不少见。
云,其实本质上不是个技术的事情。呵呵呵~

容器和网络是热点

OpenStack 社区对容器还是很积极的一个主动拥抱态度,各个项目都在考虑虚拟化对象是容器的新场景。
实际上,无论是 Docker 系列,K8s、Mesos,都有一些相对完整的 solution,无需 IaaS 的支持,自己就可以玩得很好。
但 OpenStack 社区还是希望底下用自己,所以努力提供新的 API 来支持这些 solution。
两边的定位有 overlap,肯定会冲突。底层平台必须要主动考虑上层 workload,考虑应用特性。这个是生产关系决定的。
网络话题这次被广泛关注,大会报告中有好几个都在谈网络(包括 SDN 和 NFV)。这次来参会的公司也有不少是网络公司,不过技术上新的东西不多。
比较搞笑的是,这次峰会的超级用户奖颁给了 NTT(sponser 了现场的网络接入),然而 wifi 接入体验比较一般(本来多好的宣传机会!)。
两个值得关注的项目,kuryr 还有 ovs 自己搞的 ovn 等开始亮相社区,都挺有意思,定位思路很清晰,不像 Magnum,做起来的问题不大。
围绕 neutron,问题不少,但是老框架在这里,能周旋的余地很少。怎么能跟别的项目更好的集成,怎么提供更好的性能,都是很现实的问题。
强调下,云计算的技术基础是计算虚拟化,然而成功能否,根本取决于网络。
到现在还没意识到这点的,基本可以歇了。
比较遗憾的是,有一些传统网络厂商,没能很好的抓住云计算这波机会。亡羊补牢,为时未晚,还可以考虑抓紧时间布局物联网。

技术周期趋向成熟

基本上,新的项目 focus 的 scope 都圈得比较小。
很多人开始关注实际的部署和运维方面的一些问题(再次强调下我的观点,云环境中,ops 将变得比 dev 更重要!)。
这很正常,最多的 80% 的需求也是最基本的,剩下 20% 不好做,不是通用需求,但往往是差异化和体现技术实力的点。
很多人会松了口气,趋向成熟,意味着再也不用跟着后面折腾太多升级了。
成熟后怎么能再健康的发展下去,是每一个成功社区都会碰到的问题,现在已经有点由盛转衰的意味,虽然不明显。

国内力量不可小觑

market place,国内公司(特别创业公司)见到不少。除了传统方案和硬件厂商,就是日本本地企业和国内企业,甚至国内企业感觉比日本企业还多一些。
而且来的人好多,一下子就是好几十号人,庞大的队伍!
做应用的企业没见到……,不过有一些很有特色的小企业,比如 cumulix 啊、puppet、solinea 啊,哈哈哈~
这次本地报告也不少,竟然还出现了用日语讲报告的情况。
各种基于 OpenStack 的方案,各种特点。
乐观看,大家都尽量兼容 OpenStack,又努力做出自己的特色;悲观看,差异化和成长空间可能有限。

日本的文化和生活

日本是一个很有意思的地方,学习了东方和西方的文化,糅合在一起,难免有不少纠结的地方。
也许是意识到这种文化的缺位,对于传下来的和服啊、武士道啊、艺伎表演啊,就都十分重视。
但日本文化上其实是封闭的,现在年青一代很少愿意去接触外面的世界。整个日本社会就像是一个精密的大机器,每个人按照职责努力的工作。七八点上班,十一二点下班,很少有跳槽,很少有变化,压力太大,森严的规矩,老龄化……日本的年轻人,不容易!
生活成本低、贫富差距不大,这些西方社会普遍的特色,也造成了日本现在已经进入了高度稳定甚至停滞期。

Sunday, October 18, 2015

云计算的第二个十年 -- IT 行业的新变化

如果从概念的提出(2006 年由 IBM、Google 联合提出)算起,云计算即将步入第二个十年。
在第一个十年里,云计算从被质疑到成为新一代 IT 标准,从单纯技术上的概念到影响到整个业务模式。
虽然到目前为止,还有很多不成熟的地方值得探索,但云计算在第一个十年里已经正式确立了它的地位,已经被广泛接受并实践。
在云时代的下一个十年里,IT 行业又会发生哪些变化呢?

ops 将变得比 dev 更重要

在过去,无论是企业还是个人市场,新产品的研发能力是最核心的,运营团队一贯被视为“第二梯队”。
造成这种局面的原因很复杂,根子上是基础设施的缺乏。大量的重复性、非标准化、非核心的研发任务,造成 dev 在整个生产链中的核心地位,造成运营团队话语权的缺失。
在云时代,随着基础设施服务的成熟和标准化,新产品研发的效率和复杂度将大大下降。反而是产品上线后,怎么应对不同时间、不同场景的需求变得更为重要。运营能力将直接决定云的质量。
所以,即使是研发团队,也一定要具备一定的运维能力。devops 的紧密结合,才能具备在云时代的快速应变能力。

PaaS 将变得比 IaaS 更重要

如果说 IaaS 是云计算一切服务的基础,那么 PaaS 将变成未来云计算服务的核心。
IaaS 的定位是提供基础架构能力,从整个云计算栈上看,无论是提供裸机、虚机还是容器,这只是对物理计算资源进行单纯的抽象和管理,并不具备任何面向业务属性。而 PaaS 则在基础架构的基础上进一步抽象计算资源为软件业务能力。
如果以盖房子为例子,IaaS 相当于提供了砖头和水泥。而 PaaS 则进一步的整合这些基础材料为墙板、横梁。显然,施工团队更喜欢直接用后者。
同时,由于 PaaS 更贴近应用,也具有更多话语权。
那么,比 PaaS 再上一层的 SaaS 是否更有优势呢?理论上是没错的,但是实际上在下一个十年里,公有 SaaS 成为主流的可能性不大。一方面是大量的企业的应用并不具有太强的通用性,需要定制化开发;另一方面是过度耦合到第三方服务的隐患。
私有 SaaS 会有,但是一定种类不会太多。办公类、娱乐类将成主体。

通用平台将越来越少

由于搭建和运维云成本的进一步降低,云将成为家家户户都可以创建的资源,面向公共服务的通用云平台将进一步集中,成为两三家的业务。
另外一方面,面向通用计算的云平台将很难获利。反而是某些具有特色服务的专有云将大量出现。
这些特色应该至少包括安全性、高性能、跟托管业务紧耦合的一些辅助服务,例如域名、CDN 等等。

Tuesday, September 22, 2015

用 Docker 搭建 Spark 集群

简介

Spark 是 Berkeley 开发的分布式计算的框架,相对于 Hadoop 来说,Spark 可以缓存中间结果到内存而提高某些需要迭代的计算场景的效率,目前收到广泛关注。
熟悉 Hadoop 的同学也不必担心,Spark 很多设计理念和用法都跟 Hadoop 保持一致和相似,并且在使用上完全兼容 HDFS。但是 Spark 的安装并不容易,依赖包括 Java、Scala、HDFS 等。
通过使用 Docker,可以快速的在本地搭建一套 Spark 环境,方便大家开发 Spark 应用,或者扩展到生产环境。
Spark 的设计理念很简单master 节点负责接收要执行的应用和指令worker 节点负责具体处理
除了自带的集群机制,还兼容集成到其他的集群框架,包括 mesos、yarn 等。

安装

其实官方的源码中已经提供了支持 mesos 的 Dockerfile 文件,在 docker\spark-mesos 下面,可以据此生成 Docker 镜像。
这里,我们采用比较热门的 sequenceiq/docker-spark 镜像,这个镜像已经安装了对 Spark 的完整依赖。
无论官方还是 sequenceiq/docker-spark 镜像,都是基于提前打包的二进制文件来制作的,都可以放心使用。
由于镜像比较大(2+ GB),首先下载该镜像到本地。
$ docker pull sequenceiq/spark:1.4.0
下载完毕后,从 https://github.com/yeasy/docker-compose-files/tree/master/spark_cluster 下载编写好的支持 Spark 集群的 docker-compose.yml 文件,并启动它
$ sudo pip install docker-compose==1.4.0
$ docker-compose up
可以看到类似如下的输出:
Creating sparkcompose_master_1...
Creating sparkcompose_slave_1...
Attaching to sparkcompose_master_1, sparkcompose_slave_1
master_1 | /
master_1 | Starting sshd: [  OK  ]
slave_1  | /
slave_1  | Starting sshd: [  OK  ]
master_1 | Starting namenodes on [master]
slave_1  | Starting namenodes on [5d0ea02da185]
master_1 | master: starting namenode, logging to /usr/local/hadoop/logs/hadoop-root-namenode-master.out
slave_1  | 5d0ea02da185: starting namenode, logging to /usr/local/hadoop/logs/hadoop-root-namenode-5d0ea02da185.out
master_1 | localhost: starting datanode, logging to /usr/local/hadoop/logs/hadoop-root-datanode-master.out
slave_1  | localhost: starting datanode, logging to /usr/local/hadoop/logs/hadoop-root-datanode-5d0ea02da185.out
master_1 | Starting secondary namenodes [0.0.0.0]
slave_1  | Starting secondary namenodes [0.0.0.0]
master_1 | 0.0.0.0: starting secondarynamenode, logging to /usr/local/hadoop/logs/hadoop-root-secondarynamenode-master.out
master_1 | starting yarn daemons
master_1 | starting resourcemanager, logging to /usr/local/hadoop/logs/yarn--resourcemanager-master.out
master_1 | localhost: starting nodemanager, logging to /usr/local/hadoop/logs/yarn-root-nodemanager-master.out
master_1 | starting org.apache.spark.deploy.master.Master, logging to /usr/local/spark-1.4.0-bin-hadoop2.6/sbin/../logs/spark--org.apache.spark.deploy.master.Master-1-master.out
slave_1  | 0.0.0.0: starting secondarynamenode, logging to /usr/local/hadoop/logs/hadoop-root-secondarynamenode-5d0ea02da185.out
slave_1  | starting yarn daemons
slave_1  | starting resourcemanager, logging to /usr/local/hadoop/logs/yarn--resourcemanager-5d0ea02da185.out
slave_1  | localhost: starting nodemanager, logging to /usr/local/hadoop/logs/yarn-root-nodemanager-5d0ea02da185.out
slave_1  | starting org.apache.spark.deploy.worker.Worker, logging to /usr/local/spark-1.4.0-bin-hadoop2.6/sbin/../logs/spark--org.apache.spark.deploy.worker.Worker-1-5d0ea02da185.out
docker-compose 服务起来后我们还可以用 scale 命令来动态扩展 Spark 的 worker 节点数例如
$ docker-compose scale worker=2
Creating and starting 2... done
注意,需要先用 pip 安装 docker-compose,1.4.1 版本有 bug,推荐使用 1.4.0 版本。

docker-compose 文件

我们来解析下 docker-compose 文件,核心内容很简单,包括 master 服务和 worker 服务。
master:
  image: sequenceiq/spark:1.4.0
  hostname: master
  ports:
  - "4040:4040"
  - "8042:8042"
  - "7077:7077"
  - "8080:8080"
  - "8088:8088"
  restart: always
  command: bash /usr/local/spark/sbin/start-master.sh && ping localhost > /dev/null

worker:
  image: sequenceiq/spark:1.4.0
  links:
  - master:master
  expose
  - "8081"
  restart: always
  command: bash /usr/local/spark/sbin/start-slave.sh spark://master:7077 && ping localhost >/dev/null

master 服务

首先,master 服务映射了好几组端口到本地,分别功能为: 4040:Spark 运行任务时候提供 web 界面观测任务的具体执行状况,包括执行到哪个阶段、在哪个 executor 上执行; 8042:Hadoop 的节点管理界面; 7077:Spark 主节点的监听端口,用户可以提交应用到这个端口,worker 节点也可以通过这个端口连接到主节点构成集群; 8080:Spark 的监控界面,可以看到所有的 worker、应用整体信息; * 8088:Hadoop 集群的整体监控界面。
master 服务启动后执行了 bash /usr/local/spark/sbin/start-master.sh 命令来配置自己为 master 节点然后通过 ping 来避免容器退出

worker 服务

类似 master 节点,启动后,执行了 /usr/local/spark/sbin/start-slave.sh spark://master:7077 命令来配置自己为 worker 节点,然后通过 ping 来避免容器退出。
注意,启动脚本后面需要提供 spark://master:7077 参数来指定 master 节点地址。
8081 端口提供的 web 界面,可以看到该 worker 节点上任务的具体执行情况。

执行应用

Spark 推荐用 spark-submit 命令来提交执行的命令基本语法为
spark-submit \
  --class your-class-name \
  --master master_url \
  your-jar-file
  app_params
例如,我们可以使用 spark 自带样例中的计算 Pi 的应用。
在 master 节点上执行命令
/urs/local/spark/bin/spark-submit --master spark://master:7077 --class org.apache.spark.examples.SparkPi /usr/local/spark/lib/spark-examples-1.4.0-hadoop2.6.0.jar 1000
最后的参数 1000 表示要计算的迭代次数为 1000 次。
任务运行中,可以用浏览器访问 4040 端口,看到任务被分配到了两个 worker 节点上执行。 
计算过程中也会输出结果,如下:
...
15/09/22 03:07:54 INFO scheduler.TaskSetManager: Finished task 998.0 in stage 0.0 (TID 998) in 201 ms on 172.17.0.49 (998/1000)
15/09/22 03:07:54 INFO scheduler.TaskSetManager: Finished task 999.0 in stage 0.0 (TID 999) in 142 ms on 172.17.0.49 (999/1000)
15/09/22 03:07:54 INFO scheduler.TaskSetManager: Finished task 997.0 in stage 0.0 (TID 997) in 220 ms on 172.17.0.49 (1000/1000)
15/09/22 03:07:54 INFO scheduler.TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool
15/09/22 03:07:54 INFO scheduler.DAGScheduler: ResultStage 0 (reduce at SparkPi.scala:35) finished in 23.149 s
15/09/22 03:07:54 INFO scheduler.DAGScheduler: Job 0 finished: reduce at SparkPi.scala:35, took 23.544018 s
Pi is roughly 3.1417124
15/09/22 03:07:54 INFO handler.ContextHandler: stopped o.s.j.s.ServletContextHandler{/metrics/json,null}
15/09/22 03:07:54 INFO handler.ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/stage/kill,null}
15/09/22 03:07:54 INFO handler.ContextHandler: stopped o.s.j.s.ServletContextHandler{/api,null}
...

总结

集群系统作为现代 IT 基础架构的重要组成部分,一直是运维部门的“硬骨头”。上线、部署、扩容……规模大了后各方面都可能出问题。而结合 Docker 这样的容器技术,可以很大程度上解耦对周边环境的依赖。如果再配合 mesos 等资源管理系统,可以大大降低人工运维的风险和复杂性。
当然,优秀的系统一定要配合正确的流程。生产环境中如果缺乏一套成熟的 devops 流程,是不可能有高效的生产力的。加班,也就成了常态。
转载请注明。

Monday, August 17, 2015

用 consul + consul-template + registrator + nginx 打造真正可动态扩展的服务架构

在互联网应用领域,服务的动态性需求十分常见,这就对服务的自动发现和可动态扩展提出了很高的要求。
Docker 的出现,以及微服务架构的兴起,让众多开源项目开始关注在松耦合的架构前提下,如何基于 Docker 实现一套真正可动态扩展的服务架构。

基本需求

基本的需求包括:
  • 服务启动后要能自动被发现(vs 传统需要手动进行注册);
  • 负载要能动态在可用的服务实例上进行均衡(vs 传统需要静态写入配置);
  • 服务规模要方便进行快速调整(vs 传统需要较长时间的手动调整)。

相关项目

服务发现

服务发现的项目已经有不少,包括之前介绍的 consul,以及 skydnsserf、以及主要关注一致性的强大的 zookeeper 等。
这些项目各有优缺点,功能上大同小异,都是要通过某种机制来获取服务信息,然后通过维护一套(分布式)数据库来存储服务的信息。这也是为什么 etcd 受到大家关注和集成。
在这里,选用 HashiCorp 公司的 consul 作为服务发现的管理端,它的简介可以参考 这里

服务注册

服务注册的手段有很多,当然,从发起方是谁可以分为两大类,主动注册还是被动探测。
主动注册,顾名思义,服务启动后,向指定的服务发现管理端的 API 发送请求,给出自身的相关信息。这样做,对管理端的要求简单了很多,但意味着服务自身要完成注册工作,并且极端情况下,管理端比较难探测出真正存活的服务。
被动探测,则是服务发现管理端通过某种机制来探测存活的服务。这样可以获取真实的服务情况,但如何探测是个很难设计的点,特别当服务类型比较复杂的时候。
以上两种,都对网络连通性要求较高。从短期看,主动注册方式会比较容易实现一些,应用情形更广泛;但长期维护上,被动探测方式应该是更高效的设计。
这里,我们选用 gliderlabs 的 registrator,它可以通过跟本地的 docker 引擎通信,来获取本地启动的容器信息,并且注册到指定的服务发现管理端。

配置更新

服务被调整后,负载均衡器要想动态重新分配负载,就需要通过配置来获取更新。这样的方案也有不少,基本上都是要安装一些本地 agent 来监听服务发现管理端的信息,生成新的配置,并执行更新命令。
HashiCorp 公司 的consul-template,可以通过监听 consul 的注册信息,来完成本地应用的配置更新。

负载均衡

负载均衡对性能要求很高,其实并不是软件所擅长的领域,但软件方案胜在成本低、维护方便。包括 lvshaproxy 都是很优秀的设计方案。
这里,我们选用 nginx。nginx 不仅是个强大的 web 代理服务器,同时在负载均衡方面表现也不俗。更关键的,新版本的 nginx 对在线升级支持做到了极致。实时配置更新更是不在话下,可以保证服务的连续性。

实验过程

准备工作

首先,从 这里 下载模板文件。
主要内容如下:
#backend web application, scale this with docker-compose scale web=3
web:
  image: yeasy/simple-web:latest
  environment:
    SERVICE_80_NAME: http
    SERVICE_NAME: web
    SERVICE_TAGS: backend
  ports:
  - "80"

#load balancer will automatically update the config using consul-template
lb:
  image: yeasy/nginx-consul-template:latest
  hostname: lb
  links:
  - consulserver:consul
  ports:
  - "80:80"

consulserver:
  image: gliderlabs/consul-server:latest
  hostname: consulserver
  ports:
  - "8300"
  - "8400"
  - "8500:8500"
  - "53"
  command: -data-dir /tmp/consul -bootstrap -client 0.0.0.0

# listen on local docker sock to register the container with public ports to the consul service
registrator:
  image: gliderlabs/registrator:master
  hostname: registrator
  links:
  - consulserver:consul
  volumes:
  - "/var/run/docker.sock:/tmp/docker.sock"
  command: -internal consul://consul:8500
如果没有安装 docker 和 docker-compose,需要先进行安装,以 ubuntu 系统为例。
$ curl -sSL https://get.docker.com/ | sh
$ sudo pip install docker-compose

执行

docker-compose 模板所在目录,执行
$ sudo docker-compose up
相关镜像即可自动被下载,下载完毕后,容器就启动起来了。
访问 http://localhost 可以看到一个 web 页面,提示实际访问的目标地址。
多次刷新,可以看到目标地址没有变化,这是因为,目前我们只有一个 web 后端服务器。
2015-08-18 03:37:58: 6 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.148>
调整后端为 3 个服务器。
$ sudo docker-compose scale web=3
然后,再次访问 http://localhost,多次刷新,可以看到访问的实际目标地址发生了变化,新启动的 web 服务器被自动注册,并且 nginx 自动对它们进行了负载均衡。
2015-08-18 03:37:58: 6 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.148>
2015-08-18 03:38:17: 5 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.152>
2015-08-18 03:38:20: 5 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.153>

Tuesday, August 04, 2015

Consul 简介

概述

Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。
它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows

安装

从 www.consul.io/downloads.html 下载二进制文件到本地即可。
consul 在每个节点上都只需要相同的单一二进制文件,部署十分简单。

基本概念

agent

组成 consul 集群的每个成员上都要运行一个 agent,可以通过 consul agent 命令来启动。agent 可以运行在 server 状态或者 client 状态。自然的,运行在 server 状态的节点被称为 server 节点;运行在 client 状态的节点被称为 client 节点。

client 节点

负责转发所有的 RPC 到 server 节点。本身无状态,且轻量级,因此,可以部署大量的 client 节点。

server 节点

负责组成 cluster 的复杂工作(选举、状态维护、转发请求到 lead),以及 consul 提供的服务(响应 RCP 请求)。考虑到容错和收敛,一般部署 3 ~ 5 个比较合适。
第一个节点:
$ consul agent -data-dir=/tmp/consul -server -bootstrap-expect 1 -bind $IP
其他节点:
$ consul agent -data-dir=/tmp/consul -server -join $IP
通过 $IP:8500/v1/catalog/nodes 可以访问到注册上的节点。

Gossip

基于 Serf 实现的 gossip 协议,负责成员、失败探测、事件广播等。通过 UDP 实现各个节点之间的消息。分为 LAN 上的和 WAN 上的两种情形。

架构

consul architecture

相关项目

registrator

可以监听主机上的容器信息,并把有暴露端口的容器注册到给定的 consul/etcd 等服务上。

consul-template

可以监听 consul 服务的内容变化,并根据变化实时更新应用的配置文件。