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!!

推荐阅读更多精彩内容

  • 本博文主要向大家介绍如何使用Spring Cloud和Docker构建微服务平台。 什么是Spring Cloud...
    0dd5ba4532c8阅读 1,018评论 2 15
  • 1. 微服务架构介绍 1.1 什么是微服务架构? 形像一点来说,微服务架构就像搭积木,每个微服务都是一个零件,并使...
    静修佛缘阅读 5,514评论 0 39
  • 一、微服务将变得轻量级 架构需要由人去设计,这些人被称为架构师。或许很多人并未授予架构师的头衔,但自己却从事着架构...
    justmilkrain阅读 5,175评论 10 110
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 131,195评论 18 138
  • 前言 Docker微服务架构,已渐渐成为服务器架构的主流 。 但是对于Docker在生产环境的部署方案,目前没有一...
    luax阅读 1,129评论 0 4
  • 开心, 伦敦是我们英伦行的登陆地也是最后一站。 明信片上常见的地标 今天都浏览了下,真的只是浏览 等你再大一点,我...
    蔡敏_Michelle阅读 49评论 0 0
  • 俘获 就这样被你俘获 没有甜言蜜语 没有海誓山盟 亦没有英雄救美的唯美场景 你只需一个眼神 一个平常的动作 我就愿...
    瞎眼陈阅读 114评论 7 2
  • 什么是大数据,最早提出“大数据”时代到来的是全球知名咨询公司麦肯锡。简单定了大数据:大数据不是随机样本,而是全体数...
    更夫说阅读 491评论 0 0
  • 在游乐场里,经常会看到这样一个场景:爸爸妈妈或爷爷奶奶/外公外婆拉着孩子,嘴里说着:“回家了/天快黑了……”各种理...
    雨天有彩虹阅读 1,190评论 0 0
  • 孙路弘老师他从出生起就表现出优秀的数学能力,立志当数学老师。 后来他如愿考入北京师范大学数学系。四年后1985年,...
    微笑的流光飞舞阅读 979评论 0 2