docker+jenkins+seneca构建去集中化微服务架构

前言

在微服务架构中,服务发现一直是一件比较复杂的事。而且服务发现式的架构处理不好,容易产生集中化。同时,微服务的提供,不可避免的需要一些负载均衡方案,实现服务的高可用和可扩展,这无疑增加了很多复杂度。

笔者认为,使用异步、基于消息的方式,可能更适合微服务架构。

基于消息的微服务架构,对于所有微服务的部署条件非常简单,只需要能访问到消息服务即可。同时微服务节点的移除和增加不会影响到服务的提供。相比服务发现的架构,简单太多了,简单即是美。

在这次实践中,使用到了seneca,一个nodejs 微服务框架。seneca,使用seneca-amqp-transport插件,可以轻松构建基于消息的微服务。

下面是架构图:


https://www.processon.com/view/link/59dc2491e4b0ef561379bc25

在这个架构中,我们使用的是标准的seneca定义的命令规范,这可能是所有微服务都需要遵守的一个规范,至于说使用其他语言,也很简单。封装一个seneca命令规范的库即可。不知道官方有没开发,开发起来难度也不会太大。

接口层比较灵活,可以根据上层应用特性,来决定如何封装传输协议,最后将转化成标准命令发送到消息服务。不建议直接访问消息服务,上层应用应保持灵活。

完整的实践代码:https://github.com/luaxlou/micro-service-practice.git

1 前期准备

使用docker-machine创建虚拟机。

关于docker的一些基本用法,可以读上一篇文章:docker+consul基于服务发现的极简web架构实践,这里就不再赘述。

依次创建3台虚拟机:

$ dm create -d "virtualbox” node1
$ dm create -d "virtualbox” node2
$ dm create -d "virtualbox" node3

2 开始构建

搭建Rabbitmq消息服务

消息队列服务,已经成为高并发应用的必备基础服务。我们选用Rabbitmq,你可以换成任意的,遵循amqp协议即可。

使用docker安装很方便,但是生产环境不建议使用docker安装。更推荐的是使用云服务,这样能保证足够高的高可用和扩展性。虽然价格贵点,但是这是唯一的单点,花点钱还是值得的。

直接安装在宿主机上:

$ docker search rabbitmq

NAME                                       DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
rabbitmq                                   RabbitMQ is an open source multi-protocol ...   1466      [OK]
tutum/rabbitmq                             Base docker image to run a RabbitMQ server      11
frodenas/rabbitmq                          A Docker Image for RabbitMQ                     11                   [OK]
sysrun/rpi-rabbitmq                        RabbitMQ Container for the Raspberry Pi 2 ...   6
aweber/rabbitmq-autocluster                RabbitMQ with the Autocluster Plugin            5
gonkulatorlabs/rabbitmq                    DEPRECATED: See maryville/rabbitmq              5                    [OK]
letsxo/rabbitmq                            RabbitMQ with Management and MQTT plugins.      4                    [OK]
bitnami/rabbitmq                           Bitnami Docker Image for RabbitMQ               3                    [OK]
$ docker run -d --name rabbit -p   5672:5672  rabbitmq

这样就启动了一个消息队里服务,并且开放5672端口

安装jenkins

jenkins用于自动集成,不然每次构建是个很麻烦的事。

下面的实践是笔者掉了不少坑之后完成的,jenkins在安装过程中会有不少麻烦,而且在mac下安装也会遇到麻烦。

将jenkins 安装到 node1

$ dm ssh node1
 
$ mkdir /mnt/sda1/var/jenkins_home
$ sudo chown 1000 /mnt/sda1/var/jenkins_home
$ sudo chown 1000 /var/run/docker.sock

$ docker run -d -v /var/run/docker.sock:/var/run/docker.sock \
                -v /mnt/sda1/var/jenkins_home:/var/jenkins_home \
                -v $(which docker):/usr/bin/docker -p 8080:8080 jenkins

查看初始密码:
$ cat /mnt/sda1/var/jenkins_home/secrets/initialAdminPassword

安装私有的Registry

在mac上安装即可

$ docker run -d -p 5000:5000 registry

文档参考:https://docs.docker.com/registry/spec/api/

准备代码

代码使用的是seneca官方的例子,完整的Dockerfile也已经写好。

FROM node:alpine

RUN npm install pm2 -g
WORKDIR /usr/src/app

COPY package.json ./
RUN npm install
COPY . .

CMD ["pm2-docker","process.yml"]

为了让nodejs能使用到多核cpu,Dockerfile 集成了pm2,使用pm2来管理node进程。

完整代码:
https://github.com/luaxlou/micro-service-practice.git

配置自动集成

这里使用了最新版的jenkins,新版的jenkins使用了pipline。一种新的构建方式,使用groovy语法。

写起来是挺优雅的,但是学习成本颇高。因为文档不全及有些文档失效,笔者不得已反编译了pipeline插件,才得以调通。

使用pipeline script

node {
    stage('Preparation') {
        def r = git('https://github.com/luaxlou/micro-service-practice.git')
   }
   stage('Build') {
       dir('seneca-listener') {
          withEnv(["DOCKER_REGISTRY_URL=http://192.168.99.1:5000"]) {

              docker.build("seneca-listener").push("latest")
            
          }
            
       }
               
   }
   
}

开始构建,顺利的话,会看到如下的结果:

image.png

这是pipeline的特性,可以可视化看到各个阶段的执行情况,算是不小的进步吧。

访问私有Registy的API,就可以看到生成的tag。

curl http://192.168.99.1:5000/v2/seneca-listener/tags/list

最后一步,试试我们的程序

在宿主机发布消息:

$ git clone https://github.com/luaxlou/micro-service-practice.git

seneca-clinet 代码是接口层代码的示意,可以根据自己的喜好封装。
同时直接发送了命令代码用于测试。

进入seneca-clinet 目录

$  AMQP_URL=192.168.99.1:5672 node index.js

这个程序会每隔两秒发送一个命令:

#!/usr/bin/env node
'use strict';

const client = require('seneca')()
    .use('seneca-amqp-transport')
    .client({
        type: 'amqp',
        pin: 'cmd:salute',
        url: process.env.AMQP_URL
    });

setInterval(function() {
    client.act('cmd:salute', {
        name: 'World',
        max: 100,
        min: 25
    }, (err, res) => {
        if (err) {
            throw err;
        }
        console.log(res);
});
}, 2000);

虽然一直在发命令,你很快就会发现命令全部超时了。这是因为还没有消费者,当然这些命令也没有丢失,只不过接口层没有得到及时返回。如果应用层支持异步的模式,每个command都有独立的id,可以保留id后,以后再过来取。这就很灵活了,一切看需求去封装接口层即可。

进入node2

$ docker run 192.168.99.1:5000/seneca-listener:latest
0|seneca-l | {"kind":"notice","notice":"hello seneca fwunhukrcmzn/1507605332382/16/3.4.2/-","level":"info","seneca":"fwunhukrcmzn/1507605332382/16/3.4.2/-","when":1507605332661}

启动后,回到seneca-clinet,发现之前超时的命令,全部接收到了。

{ id: 86,
  message: 'Hello World!',
  from: { pid: 16, file: 'index.js' },
  now: 1507605332699 }
{ id: 44,
  message: 'Hello World!',
  from: { pid: 16, file: 'index.js' },
  now: 1507605332701 }
{ id: 56,
  message: 'Hello World!',
  from: { pid: 16, file: 'index.js' },
  now: 1507605332703 }
{ id: 57,
  message: 'Hello World!',
  from: { pid: 16, file: 'index.js' },
  now: 1507605332706 }
{ id: 58,
  message: 'Hello World!',
  from: { pid: 16, file: 'index.js' },
  now: 1507605332707 }

至此,完整架构已经构建完毕。

一些未完的事项

1.自动集成,只需要配置webhook即可。
2.自动部署,因为docker运转的方式,当服务升级时需要重启docker进程。方式有很多,比较粗暴的是直接控制宿主机,或者类似salt这样的工具。
目前来说,没有找到太好的开源方案。个人倾向于自己开发agent,发布有限的API,用于常规的部署或者其他任务,以及可以定时收集服务器的信息,用于监控。这可能会是笔者的下一个开源项目。

总结

这篇文章算是一个新的里程碑,实践的成果将用于后期的架构。docker让我从传统的架构模式中脱离出来,同时也让我吃了不少苦头。但这一切都是值得的。

同时也是一个新的开始,终于从之前的公司出来。未来何去何从,有很多的未知,但我相信都是美好的。

这也许就是人生的魅力。

Hello World!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 本博文主要向大家介绍如何使用Spring Cloud和Docker构建微服务平台。 什么是Spring Cloud...
    0dd5ba4532c8阅读 1,135评论 2 15
  • 1. 微服务架构介绍 1.1 什么是微服务架构? 形像一点来说,微服务架构就像搭积木,每个微服务都是一个零件,并使...
    静修佛缘阅读 6,532评论 0 39
  • 一、微服务将变得轻量级 架构需要由人去设计,这些人被称为架构师。或许很多人并未授予架构师的头衔,但自己却从事着架构...
    justmilkrain阅读 5,336评论 10 109
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 前言 Docker微服务架构,已渐渐成为服务器架构的主流 。 但是对于Docker在生产环境的部署方案,目前没有一...
    luax阅读 1,245评论 0 4