项目发布
微服务
单体架构
单体架构,是指将开发好的项目打成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
准备数据库
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