微服务


单体架构

单体架构,是指将开发好的项目打成war包,然后发布到tomcat等容器中的应用。

假设你正准备开发一款与Uber和滴滴竞争的出租车调度软件,经过初步会议和需求分析,你可能会手动或者使用基于Spring Boot、Play或者Maven的生成器开始这个新项目,它的六边形架构是模块化的

应用核心是业务逻辑,由定义服务、领域对象和事件的模块完成。围绕着核心的是与外界打交道的适配器。适配器包括数据库访问组件、生产和处理消息的消息组件,以及提供API或者UI访问支持的web模块等。

最终它还是会打包并部署为单体式应用。具体的格式依赖于应用语言和框架。例如,许多Java应用会被打包为WAR格式,部署在Tomcat或者Jetty上,而另外一些Java应用会被打包成自包含的JAR格式,类似的,Rails和Node.js会被打包成层级目录

微服务

微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。

每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。

优点

  • 服务组件化

    每个服务独立开发, 部署, 有效避免一个服务的修改引起整个系统重新部署

  • 技术栈灵活

    约定通信方式, 使得服务本身功能实现对技术要求不再那么敏感,每个服务的请求会发到注册中心,注册中心交给API GATEWAY, 通过路由找到相应的服务给出响应

  • 独立部署

    每个微服务独立部署, 加快部署速度, 方便扩展

  • 扩展性强

    每个微服务可以部署多个, 并且有负载能力

  • 独立数据

    每个微服务有独立的基本组件,例如数据库, 缓存等

缺点

  • 沟通成本
  • 数据一致性
  • 运维成本
    • 大量服务如何治理
    • 如何部署
    • 如何监控
    • 数据和事务
  • 内部架构复杂性

微服务问题

  • 微服务间如何通信?

    REST API, RPC, MQ

  • 微服务如何发现彼此

    前端接收用户的http/https请求, 交给负载均衡器, 负载均衡器将请求发送给下面的某一个网关, 网关与注册中心 通信,注册中心是一个生产者消费者模型, 所有的服务的生产者消费者都存在这里, 网关中的请求是消费者, 通过注册中心寻找请求对应的生产者,生产者提供相应的响应, 如果配置比较多, 则所有服务的配置会交给配置中心统一管理配置

  • 组件之间如何调用关系

    根据用户的访问顺序确定调用关系(先看商品,下订单,支付)

  • 哪个服务作为整个网站的入口

    前端, 接收用户的请求, 发送给网关

    网关, 服务端的入口,接收前端的请求 和 发送响应给负载均衡器并交给前端

  • 哪些微服务需要对外访问

    前端和负载均衡器需要通信,所以前端的端口, 负载均衡器的端口需要暴露

  • 微服务怎么部署, 更新, 扩容

    以java为例, 通过jar包的形式进行部署, 更新, 扩容

  • 区分有状态应用和无状态应用

    一般k8s部署, 都是部署无状态应用,

  • 为什么要有注册中心(Eureka, Nacos)

    记录微服务多个副本的接口地址

    实现一个微服务多个副本的负载均衡

    判断微服务副本是否可用

项目迁移到k8s


流程

制作镜像 – 控制器管理pod – 暴露应用 – 对外发布应用 – Pod数据持久化 – 日志/监控

第一步: 制作镜像(3层结构)

基础镜像: centos, ubuntu

运行环境/中间件镜像: jdk, php (+基础镜像)

项目镜像: 基础镜像 + 运行环境 + 项目代码

第二步: 控制器管理pod

  • Deployment: 无状态部署
  • StatefulSet: 有状态部署
  • DaemonSet: 守护进程部署
  • Job & CronJob: 批处理

第三步: 暴露应用

通过Service

  • Service 定义了Pod的逻辑集合和访问这个集合的策略
  • Service 引入为了解决Pod的动态变化, 提供服务发现和负载均衡

第四步: 对外发布应用

通过 Ingress

  • 通过Service关联Pod
  • 基于域名访问
  • 通过Ingress Controller 实现Pod的负载均衡

第五步: Pod数据持久化(数据卷/PVC)

容器部署过程中一般有3类数据

  • 启动时需要的初始数据, 可以是配置文件
  • 启动过程中产生的临时数据, 该临时数据需要多个容器间共享
  • 启动过程中产生的持久化数据

第六步: 日志/监控

  • Filebeat + ELK
  • Prometheus + Grafana

传统部署和k8s部署的区别

传统部署是上传war/jar包, k8s部署是上传镜像

传统部署

k8s部署

部署spring Cloud微服务项目

示例代码: https://gitee.com/chen1219/simple-microservice.git

代码分支说明

  • dev1 交付代码
  • dev2 编写Dockerfile构建镜像
  • dev3 K8s资源编排
  • dev4 微服务链路监控
  • master 最终上线

第一步: 代码编译构建

  • 拉取镜像
git clone -b dev1 https://gitee.com/chen1219/simple-microservice.git dev1
git clone -b dev2 https://gitee.com/chen1219/simple-microservice.git dev2
git clone -b dev3 https://gitee.com/chen1219/simple-microservice.git dev3
git clone -b dev4 https://gitee.com/chen1219/simple-microservice.git dev4
git clone -b master https://gitee.com/chen1219/simple-microservice.git master

  • 安装maven 和 java
yum -y install java-1.8.0-openjdk maven

  • maven打包
cd /root/dev2
mvn clean package -Dmaven.test.skip=true

  • 打包完成, 每个服务的target目录下面会产生jar包
ll eureka-service/target/ gateway-service/target/ basic-common/ order-service/order-service-biz/target/ product-service/product-service-biz/target/ stock-service/stock-service-biz/target/ portal-service/target/

第二步: 将打包成的jar包构建项目镜像

打包单一服务示例

cd product-service/product-service-biz/
docker build -t product .

  • 查看构建的镜像
docker images

构建全部镜像

  • 设置镜像仓库
vim  /etc/docker/daemon.json 
{
       "registry-mirrors": [
        "https://1nj0zren.mirror.aliyuncs.com",
        "https://docker.mirrors.ustc.edu.cn",
        "http://f1361db2.m.daocloud.io",
        "https://registry.docker-cn.com"
    ],
     "insecure-registries" : [ "172.16.240.200:5000", "172.16.240.110:8999", "172.16.240.121" ], 
     "exec-opts": ["native.cgroupdriver=systemd"],
     "log-driver": "json-file",
    "log-opts": {"max-size": "100m"}
}
systemctl restart docker

  • 登录镜像仓库
docker login 172.16.240.121 

mkdir k8s && cd k8s
vim docker_build.sh 
#!/bin/bash

docker_registry=172.16.240.121

service_list="eureka-service gateway-service order-service product-service stock-service portal-service"
service_list=${1:-${service_list}}
work_dir=$(dirname $PWD)
current_dir=$PWD

cd $work_dir
mvn clean package -Dmaven.test.skip=true

for service in $service_list; do
   cd $work_dir/$service
   if ls |grep biz &>/dev/null; then
      cd ${service}-biz
   fi
   service=${service%-*}
   image_name=$docker_registry/microservice/${service}:$(date +%F-%H-%M-%S)
   docker build -t ${image_name} .
   docker push ${image_name} 
done

./docker_build.sh

  • 查看镜像仓库

第三步: 将项目部署到k8s环境

172.16.240.100 k8s-master
172.16.240.101 k8s-node01
172.16.240.102 k8s-node02
172.16.240.121 harbor, mysql

服务编排

https://gitee.com/chen1219/simple-microservice/tree/dev3/k8s

https://gitee.com/chen1219/simple-microservice/blob/dev3/eureka-service/src/main/resources/application-fat.yml

https://gitee.com/chen1219/simple-microservice/blob/dev3/gateway-service/src/main/resources/application-fat.yml

https://gitee.com/chen1219/simple-microservice/blob/dev3/portal-service/src/main/resources/application-fat.yml

https://gitee.com/chen1219/simple-microservice/blob/dev3/order-service/order-service-biz/src/main/resources/application-fat.yml

https://gitee.com/chen1219/simple-microservice/blob/dev3/product-service/product-service-biz/src/main/resources/application-fat.yml

https://gitee.com/chen1219/simple-microservice/blob/dev3/stock-service/stock-service-biz/src/main/resources/application-fat.yml

准备数据库

mysql> create database tb_order;
Query OK, 1 row affected (0.01 sec)

mysql> create database tb_product;
Query OK, 1 row affected (0.00 sec)

mysql> create database tb_stock;
Query OK, 1 row affected (0.01 sec)

mysql> use tb_order;
Database changed
mysql> source order.sql;

mysql> use tb_product;
Database changed
mysql> source product.sql;

mysql> use tb_stock;
Database changed
mysql> source stock.sql

  • 配置数据库
spring:
  datasource:
    url: jdbc:mysql://172.16.240.121:3306/tb_stock?characterEncoding=utf-8
    username: java
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

部署ingress controller

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
kubectl apply -f mandatory.yaml

部署nginx-ingress

http://m.py3study.com/Article/details/id/19809.html

wget https://kuboard.cn/install-script/v1.17.x/nginx-ingress.yaml
kubectl apply -f nginx-ingress.yaml

部署eureka集群

kubectl create ns ms
kubectl create secret docker-registry registry-pull-secret --docker-server=172.16.240.121 --docker-username=admin --docker-password=Harbor12345 --docker-email=admin@ctnrs.com -n ms
kubectl apply -f eureka.yaml
kubectl get pods,svc -n ms

  • 配置本地域名解析(/etc/hosts)

    随意一个部署有eureka的节点配置本地解析就能访问

172.16.240.101 eureka.ctnrs.com

浏览器输入 http://eureka.ctnrs.com/, 可以看到eureka页面

部署网关(gateway)

kubectl apply -f k8s/gateway.yaml 

部署前端(portal)

kubectl apply -f k8s/portal.yaml

部署product, stock, order

kubectl apply -f k8s/stock.yaml 
kubectl apply -f k8s/order.yaml 
kubectl apply -f k8s/product.yaml 

准备基础环境


172.16.240.111 gitlab
172.16.240.121 harbor

1、代码版本仓库 Gitlab

1.1 部署gitlab

docker run -d --name gitlab --hostname gitlab.hims-portal-stg1.paic.com.cn -p 443:443 -p 80:80 -p 8022:22 --restart always -v /srv/gitlab/config:/etc/gitlab -v /srv/gitlab/logs:/var/log/gitlab -v /srv/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce:12.8.8-ce.0

访问地址:

初次会先设置管理员密码 ,然后登陆,默认管理员用户名root,密码就是刚设置的。

1.2 创建项目,提交测试代码

https://github.com/lizhenliang/simple-microservice

代码分支说明:

  • dev1 交付代码
  • dev2 编写Dockerfile构建镜像
  • dev3 K8S资源编排
  • dev4 增加微服务链路监控
  • master 最终上线

拉取dev3分支,推送到私有代码仓库:

git clone -b dev3 https://github.com/lizhenliang/simple-microservice
git clone http://192.168.31.70:9999/root/microservice.git
cp -rf simple-microservice/* microservice
cd microservice
git add .
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git commit -m \'all\'
git push origin master

2、镜像仓库 Harbor

2.1 安装docker与docker-compose

wget http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum install docker-ce -y
systemctl start docker
systemctl enable docker
curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

2.2 解压离线包部署

# tar zxvf harbor-offline-installer-v1.9.1.tgz
# cd harbor
# vi harbor.yml
hostname: 192.168.31.70
# ./prepare
# ./install.sh --with-chartmuseum
# docker-compose ps 

–with-chartmuseum 参数表示启用Charts存储功能。

2.3 配置Docker可信任

由于habor未配置https,还需要在docker配置可信任。

# cat /etc/docker/daemon.json 
{"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
  "insecure-registries": ["192.168.31.70"]
}
# systemctl restart docker

3、应用包管理器 Helm

3.1 安装Helm工具

# wget https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
# tar zxvf helm-v3.0.0-linux-amd64.tar.gz 
# mv linux-amd64/helm /usr/bin/

3.2 配置国内Chart仓库

# helm repo add stable http://mirror.azure.cn/kubernetes/charts
# helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 
# helm repo list

3.3 安装push插件

# helm plugin install https://github.com/chartmuseum/helm-push

如果网络下载不了,也可以直接解压课件里包:

# tar zxvf helm-push_0.7.1_linux_amd64.tar.gz
# mkdir -p /root/.local/share/helm/plugins/helm-push
# chmod +x bin/*
# mv bin plugin.yaml /root/.local/share/helm/plugins/helm-push

3.4 添加repo

# helm repo add  --username admin --password Harbor12345 myrepo http://192.168.31.70/chartrepo/library

3.5 推送与安装Chart

# helm push mysql-1.4.0.tgz --username=admin --password=Harbor12345 http://192.168.31.70/chartrepo/library
# helm install web --version 1.4.0 myrepo/demo

4、微服务数据库 MySQL

# yum install mariadb-server -y
# mysqladmin -uroot password \'123456\'

或者docker创建

docker run -d --name db -p 3306:3306 -v /opt/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 --character-set-server=utf8

最后将微服务数据库导入。

5、K8S PV自动供给

先准备一台NFS服务器为K8S提供存储支持。

# yum install nfs-utils
# vi /etc/exports
/ifs/kubernetes *(rw,no_root_squash)
# mkdir -p /ifs/kubernetes
# systemctl start nfs
# systemctl enable nfs

并且要在每个Node上安装nfs-utils包,用于mount挂载时用。

由于K8S不支持NFS动态供给,还需要先安装上图中的nfs-client-provisioner插件:

# cd nfs-client
# vi deployment.yaml # 修改里面NFS地址和共享目录为你的
# kubectl apply -f .
# kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-df88f57df-bv8h7   1/1     Running   0          49m

6、持续集成 Jenkins

由于默认插件源在国外服务器,大多数网络无法顺利下载,需修改国内插件源地址:

cd jenkins_home/updates
sed -i \'s/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g\' default.json && \
sed -i \'s/http:\/\/www.google.com/https:\/\/www.baidu.com/g\' default.json

版权声明:本文为cjwnb原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/cjwnb/p/12706875.html