项目有感

微服务

微服务的具体概念或者优缺点可以看这个:

微服务-解决复杂问题 | 千锋教育-李卫民

微服务架构,更好的进行分布式系统开发,拆分单体应用,将一个应用拆分成多个服务,每一个服务都是一个可以独立运行的项目。

微服务分布式开发会遇到这四个问题:

  1. 这么多服务,客户端如何访问
  2. 这么多服务,服务之间如何通信
  3. 这么多服务,如何治理
  4. 服务挂了,怎么办?

解决方案:

Spring Cloud,是一套生态,是为了解决微服务架构遇到的问题,想要使用Spring Cloud必须基于Spring Boot


后来去了解了下,现在Spring Cloud微服务方案有三套:

Spring Cloud Netflix

目前市场上主流的 第一套微服务架构解决方案:Spring Boot + Spring Cloud Netflix

  • Spring Cloud Netflix为了解决第一个问题,提出了API网关组件—->Zuul
  • 为了解决服务之间如何通信问题,提出了Feign,它是基于HTTP通信的,同步并阻塞的
  • 为了解决如何治理服务问题,提出了服务注册与发现组件—>Eureka
  • 为了解决服务挂了的问题,提出了熔断机制—>Hystrix组件

市面上面的教程很多都是这一套,不过这一套已经不维护了,所以不考虑这一个

Dubbo + Zookeeper

目前市场上主流的 第二套微服务架构解决方案:Spring Boot + Dubbo + Zookeeper

  • Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架。用于解决服务之间的通信问题
  • ZooKeeper 是一种分布式协调服务,用于管理大型主机。在分布式环境中协调和管理服务是一个复杂的过程。用于解决治理服务的问题,也就是服务注册与发现
  • API网关没有现成的,得找第三方组件或自己实现
  • 熔断机制组件也没有现成

所以该套方案不是很完善,但是新版在孵化,估计新版会解决这些问题

Spring Cloud Alibaba

目前市场上主流的 第三套微服务架构解决方案:Spring Boot + Spring Cloud Alibaba

Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

依托Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将Spring Cloud应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。

  • Spring Cloud Netflix阶段我们采用Eureka做作为我们的服务注册与发现服务器,现利用Spring Cloud Alibaba 提供的Nacos组件替代该方案。
  • 服务之间通信Feign
  • 熔断机制组件: 阿里巴巴开源了 Sentinel 组件,实现了熔断器模式
  • API网关: Spring Cloud GatewaySpring Cloud Gateway 作为 Spring Cloud 生态系中的网关,目标是替代 Netflix ZUUL,其不仅提供统一的路由方式,并且基于 Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

下一代微服务架构—服务网格(service mesh)

可以去了解下微服务管理框架service mesh——Istio

SpringBoot转SringCloudAlibaba

为什么要转?一方面是因为项目使用了shiro,很多时候其他接口都要依赖shiro的检查之后才能用,也就是说流量得经过shiro检查,没有问题才放行给接口处理逻辑,这样的话接口就和shiro耦合在一起了,如果我们把shiro拆出来,当一个服务,流量经过这个服务检查,没问题才放行给其他服务使用,这里我们讲的其实就是微服务里面的网关。另一方面就是之前没有用过,想用用。当然,微服务也有很多缺点,比如增加开发成本,服务器开销等等。

SpringCloud自动部署问题

当我们使用SpringCloud的时候,意味着我们一个项目会有很多个服务,每个项目都是打包部署的,而我们可能会有几百个服务,所以要是像我们之前使用SpringBoot手动打包项目成Jar,然后再手动上传到服务器那样的话,那么肯定会累si。所以当我们这个很简单版的SpringCloud项目完成后,我就考虑如何去部署它。

既然这么多项目需要打包了,那么直觉就可以告诉我们要上自动部署了,所以这几天一直都在写那个自动部署的脚本。回归正题,其实这东西现在看来是一个CI/CD的过程,CI/CD又关系到devops,之前对这个词有点模糊,现在可以趁机补习一下。

CI/CD与devops

其实,CI的全称是continuous integrationCD的全称是continuous delivery

翻译过来分别是持续集成持续交付

那么devops

DevOps is a set of practices that combines software development (Dev) and information-technology operations (Ops) which aims to shorten the systems development life cycle and provide continuous delivery with high software quality.

DevOps - Wikipedia

DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

devops_百度百科

baba什么的,其实我感觉它的作用应该就是让软件更快更好地交付给客户使用,所以它们的关系应该是

CICDdevops的最佳实践之一,可以更频繁更可靠得交付

更多可点下面链接了解

What is CI/CD? Continuous integration and continuous delivery explained | InfoWorld

如何从零开始搭建 CI/CD 流水线-InfoQ

总结

DevOps 是一种软件开发方法。它将持续开发、持续测试、持续集成、持续部署和持续监控贯穿于软件开发的整个生命周期

CI/CD可以将它们看作是类似于软件开发生命周期的过程

搭建CI/CD流水线

搭建CI/CD流水线的方法用很多,比如用JenkinsGitLabTravis,或者是最近刚出的Github Actions等等。之前我们团队尝试过使用Jenkins,优点就是自定义任务很多并且可以自己把控,缺点就是得有服务器部署它,(或许是本地虚拟机+内网穿透也行)。

权衡了下,决定使用Travis


第一步是在项目的根目录添加.travis.yml

这个文件会被travis发现,并且执行里面设置的逻辑达到自动部署的目的,其实这个本质上就是travis给你开一台机器,你写脚本去控制它,让这个机器帮你做一些事情,这个脚本的内容其实就是Linux上的一些命令。travis脚本的一些基础的命令可以在网上很容易的找到。

.travis.yml

下面是我当时写的.travis.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
language: java

jdk:
- openjdk8

services:
- docker

addons:
apt:
packages:
- sshpass

cache:
directories:
- $HOME/.m2

install:
- ssh-keyscan ${gatewayip} >> ~/.ssh/known_hosts

script:
- bash start.sh acm-dependencies acm-commons-controller acm-commons-utils

branches:
only:
- master

notifications:
email: false

env:
global:
- GH_REF=https://github.com/GreenHatHG/ACMRecentContests_SpringCloudAlibaba.git

有几点说明一下:

  1. 因为Java项目,所以language里面是Javatravis支持多语言,详情可看:How to set up Travis CI with multiple languages - Stack Overflow,大概是这样的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    matrix:
    include:
    - language: python
    python: 2.7
    script: ...
    ...
    - language: objective-c
    os: osx
    script: ...
    ...
  2. 当前SpringCloud项目使用了maven构建工具,因为maven在构建的时候需要下载很多依赖,所以为了加快构建的速度,我们缓存了maven所下载的依赖,当travis构建完成时清空其他东西而保存了依赖,下次再次构建的时候就可以直接使用。

    1
    2
    3
    cache:
    directories:
    - $HOME/.m2
  1. 因为要用sshpass远程控制服务器,所以得install那里把ip地址填到~/.ssh/known_hosts文件,以免出现不能访问的情况

start.sh

因为要执行的逻辑比较多,所以把脚本写到了一个文件里面。start.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/bin/bash

# -----------------install父类依赖---------------------
for arg;
do
mvn clean install -f $arg/pom.xml
done

# -----------------创建dockerfile---------------------
# $1:项目名,$2:jar的相对路径
createDokcerfiler(){
rm $1/dockerfile || true
touch $1/dockerfile
echo 'FROM openjdk:8-alpine' >> $1/dockerfile
echo 'RUN mkdir /app' >> $1/dockerfile
echo 'COPY' $2 ' /app/' >> $1/dockerfile
echo 'CMD java -jar /app/'$2 >> $1/dockerfile
}

# -----------------打包---------------------
baseFolder='/root/spring-cloud-alibaba/'
# 创建文件夹用来存放jar
# sshpass -p $pwd ssh -o StrictHostKeyChecking=no root@$ip 'mkdir -p '${baseFolder} || true

for path in `ls`
do
flag=1
# 判断是否是父类依赖,是的话则直接跳过
for arg;
do
if [ $path == $arg ]; then
flag=0
break
fi
done
# 判断是不是文件夹
if [ $flag == 1 ]&&[ -d $path ]; then
mvn clean package -f $path/pom.xml
# sshpass -p $pwd scp $path/target/*.jar root@$ip:${baseFolder}
jarPath=`ls $path/target | grep '.jar$'`
createDokcerfiler $path $jarPath
mv "$path/target/$jarPath" $path
fi
done

# -----------------上传到阿里云docker仓库---------------------
time=$(date "+%Y%m%d%H")

docker login --username=$registryu registry.cn-hongkong.aliyuncs.com --password=$registryp

for path in `ls`
do
if [ -f $path/dockerfile ]; then
docker build -t $path:$time $path
docker tag $path:$time registry.cn-hongkong.aliyuncs.com/acm-recentcontests/$path:$time
docker push registry.cn-hongkong.aliyuncs.com/acm-recentcontests/$path:$time
fi
done

里面执行的逻辑其实很简单,首先就是对maven所要依赖的公共项目进行编译安装,然后再去编译其他独立的一个个项目,最后制作dockerfile文件,编译打包上传到阿里云的docker仓库

这里面有几个坑点,一个是多模块的maven项目怎么打包,这里面也花了我挺长时间,因为每个项目都是独立的,不像单体应用那么简单。除了我这个方法,还有一个方法就是构建一个maven私服,把自己的jar包上传上去,当构建别的项目的时候,它依赖了某个项目,这时候所要依赖的jar包可以从私服上面找到。

第二点就是dockerfile要和jar文件夹处在同一级目录才好打包,不然会报错,所以脚本有一处是将jar包移动到dockerfile的目录

第三点就是一些零零碎碎的Linux Shell知识了,比如赋值等号不能有空格,双引号与单引号的区别等等,需要注意。

debug模式

不过这里有个好方法可以去解决脚本问题,就是开启debug模式,这样我们可以sshtravis的机器上面,然后我们可以在travis里面不断修改我们的脚本。

Running Build in Debug Mode - Travis CI

跟着官网的脚本走就行了,不过需要注意几点就是

  1. 需要给官方发邮件叫工作人员对你的某个配置开启debug模式后你才能用这个模式,注意时区2333,那时候工作人员可能还在睡觉

  1. 因为travis服务器处于外国,直接连接会比较慢,所以可以考虑给ssh套代理,在linux使用ssh命令并没有找到什么的好的让ssh走代理的方法,我是用putty解决的
  2. ssh上去后如果执行exit的话会直接导致这次的debug直接结束,如果需要退出,直接关闭窗口就行,下次连接的时候还是处于上次操作的位置,需要注意的是,一次debug模式只有三十分钟,超时了只能再发一次请求,并且数据会清空。

travis网页的设置

脚本配置好了后,就可以去travis官网设置要关联的仓库,好像现在travis只能关联Github仓库,并且得是公开的,私有仓库得要钱。

然后在右上角头像那里打开setting,进去之后就有个repositories

记得之前官网是travis.org的时候有关联的设置,新版官方好像是没有,我们直接在我们要自动部署的仓库里面点一次构建,之后就可以一直构建了。

然后查看每次的构建日志就行啦。

总结

总结来说,一共2步:

  1. 编写.travis.yml文件放到项目根目录并且推上仓库
  2. travis官网设置要关联的仓库

个人总结

个人踩过的坑在maven的构建和travis脚本的编写上面,因为那时候在整一个项目下新建一个子项目都是手动的,有时候会打错某个文件夹名字,但是idea可以运行,命令行打包会报错,这时候可能是某个文件夹的名字错了,或者是某个文件的名字错了,所以手残党新建一个SpringBoot子项目的时候可以新建一个mavenmodule,然后删除多余的东西就行啦。

还有一个就是pom.xml找不到父模块的问题,或者托管这个maven子项目到idea的时候会报错,这时候只需要把idea2019版本换回idea2018.2就行啦。

这2个前期最烦的问题,解决就顺畅很多了。