Loading

第26章: 微服务容器化迁移

1 环境说明

说明: 本文主要关注微服务在k8s平台的实现过程,有些步骤不会在本文中体现,需要自行搭建。

1.1 服务器环境

实验服务器配置: 40核/64GB/2TB

主机名 系统版本 IP地址 cpu/内存/磁盘 用途 软件版本
k8s_nfs CentOS7.5 172.16.1.60 4核/8GB/60GB nfs存储/SkyWalking服务器端/jdk nfs-utils-1.3.0-0.68/es7-8.3.0/openjdk-1.8
k8s_harbor CentOS7.5 172.16.1.61 4核/4GB/60GB harbor镜像仓库 v1.9.1
k8s_gitlab CentOS7.5 172.16.1.62 4核/4GB/60GB gitlab代码仓库 GitLab Community Edition 13.12.2
k8s-master1 CentOS7.5 172.16.1.81 4核/4GB/60GB kubernetes master1节点 jdk、maven用于编译代码 k8s v1.20.0 jdk-8u45 maven-3.5.0
k8s-master2 CentOS7.5 172.16.1.82 4核/4GB/60GB kubernetes master2节点 k8s v1.20.0
k8s-node1 CentOS7.5 172.16.1.83 8核/16GB/60GB kubernetes node1节点 k8s v1.20.0
k8s-node2 CentOS7.5 172.16.1.84 8核/16GB/60GB kubernetes node2节点 k8s v1.20.0

补充: kubernetes集群的控制节点我打了污点不能被pod调度使用。

1.2 微服务项目说明
1 项目地址
https://github.com/HyjyLc/simple-microservice/

2 项目配置说明
(1) 这是一个基于SpringCloud的微服务架构项目
(2) 部署须知
1) 导入db目录下数据库文件到自己的MySQL服务器
2) 修改配置环境(xxx-service/src/main/resources/application.yml,active值决定启用环境配置文件)
3) 修改连接数据库配置(xxx-service/src/main/resources/application-fat.yml)
4) 修改前端页面连接网关地址(portal-service/src/main/resources/static/js/productList.js和orderList.js)
5) 服务启动顺序:mysql -> eureka -> product,stock,order -> gateway -> portal
6) 增加Skywalking Agent

3 项目服务说明

项目截图: image-20220112134943400

服务 服务名 端口号 连接信息
portal-service 前端服务 8080 连接eureka
gateway-service 网关服务 9999 连接eureka
order-service 订单服务 8020 连接eureka、mysql
product-service 产品服务 8010 连接eureka、mysql
stock-service 库存服务 8030 连接eureka、mysql
eureka-service 微服务注册中心服务 8888 eureka之间相互连接
mysql 数据库服务 3306 /
1.3 应用环境准备
1 nfs服务部署
节点: k8s_nfs
用途: k8s pod 数据持久化存储
说明: nfs服务的搭建过程不再赘述
验证:
[root@k8s_nfs ~]# showmount -e 172.16.1.60
Export list for 172.16.1.60:
/ifs/kubernetes *

2 harbor镜像仓库部署
节点: k8s_harbor
用途: 微服务镜像仓库,需要建立名为"microservice"的私有项目
说明: harbor镜像仓库的搭建过程不再赘述
登录:
URL: http://172.16.1.61/
USER: admin
PASS: Harbor12345

3 gitlab代码仓库部署
节点: k8s_gitlab
用途: 微服务代码仓库
说明: gitlab代码仓库的搭建过程不再赘述,需要建立名为"microservice"的私有项目
登录:
URL: http://172.16.1.62:9999/
USER: root
PASS: 12345678

4 Ingress-Controller插件部署
节点: kubernetes集群
用途: 用于代理微服务项目中的"portal-service"服务和"gateway-service"服务。
说明: ingress的部署过程不再赘述。控制器使用"kind: DaemonSet",添加"hostNetwork: true"参数;添加svc为"type: ClusterIP";完成
部署后k8s-node1、k8s-node2节点都有80,443端口对外暴露。

查看:
[root@k8s-master1 ms]# kubectl get daemonset,pod,svc -n ingress-nginx
[root@k8s-node1 ~]# netstat -tunlp | egrep "80|443"
[root@k8s-node2 ~]# netstat -tunlp | egrep "80|443"

图示: image-20220115232847521

5 nfs-subdir-external-provisioner插件部署
节点: kubernetes集群
用途: 为mysql的pod提供pvc自动供给
说明: nfs pvc自动供给插件的部署过程不再赘述。修改"deployment.yaml"文件中连接nfs服务的地址和nfs共享目录参数;修改"class.yaml"
文件中"archiveOnDelete"(删除时是否存档)参数为 archiveOnDelete: "true",删除pod时保留pod数据,默认为false时为不保留数据。
注意: 在部署前需要在k8s各个节点上部署nfs的客户端(yum install nfs-utils -y),否则无法部署成功。

查看:
[root@k8s-master1 ms]# kubectl get deployment,pod,svc,sc -n default

图示: image-20220115233203924

6 kubernetes集群节点上配置docker信任harbor仓库
节点: 172.16.1.81-84
用途: 使docker信任harbor仓库,否则会报如下错误
Error response from daemon: Get https://172.16.1.61/v2/: dial tcp 172.16.1.61:443: connect: connection refused

配置: 添加 "insecure-registries": ["172.16.1.61"] 参数,记得不要忘记添加 "," 分割上下的配置项。
# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://b1cx9cn7.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"insecure-registries": ["172.16.1.61"]
}

生效:
# systemctl daemon-reload
# systemctl restart docker
注: 重启 docker 会导致 k8s 集群的 pod 重启

验证:
# docker login 172.16.1.61
Username: admin
Password: Harbor12345
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

2 微服务架构

2.1 单体应用 vs 微服务

1 单体架构

(1) 特点
1) 易于部署
2) 易于测试

(2) 不足
1) 代码膨胀,难以维护
2) 构建、部署成本大
3) 新人上手难

单体架构图: image-20220112202921772

2 微服务架构

(1) 特点
1) 服务组件化
每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。
2) 技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。
3) 独立部署
每个微服务独立部署,加快部署速度,方便扩展。
4) 扩展性强
每个微服务可以部署多个,并且有负载均衡能力。
5) 独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。

(2) 不足
1) 沟通成本
2) 数据一致性
3) 运维成本(部署、监控)
4) 内部架构复杂性
5) 大量服务治理

微服务架构图: image-20220112203014316

3 JAVA微服务框架

(1) Spring Boot:  快速开发微服务的框架
(2) Spring Cloud: 基于SpringBoot实现的一个完整的微服务解决方案
(3) Dubbo:       阿里巴巴开源的微服务治理框架
2.2 在K8S平台部署微服务考虑的问题

1 常见微服务架构图 image-20220113115807277

2 对微服务项目架构理解

(1) 微服务间如何通信?REST API,RPC,MQ
(2) 微服务如何发现彼此?注册中心
(3) 组件之间怎么个调用关系?
(4) 哪个服务作为整个网站入口?前后端分离
(5) 哪些微服务需要对外访问?前端和微服务网关
(6) 微服务怎么部署?更新?扩容?
(7) 区分有状态应用与无状态应用

3 为什么用注册中心系统

(1) 微服务太多面临的问题
1) 怎么记录一个微服务多个副本接口地址?
2) 怎么实现一个微服务多个副本负载均衡?
3) 怎么判断一个微服务副本是否可用?

(2) 主流注册中心
Eureka,Nacos,Consul

微服务服务间调用图示: image-20220113121054224

4 在k8s部署项目流程

dockerfile 》》》Deployment、StatefulSet、DaemonSet 》》》Service Ingress 》》》Prometheus+Grafana、ELK Stack

image-20220113121804036

3 在K8S平台部署Spring Cloud微服务项目

说明: Spring Cloud 微服务项目在 k8s 集群的 ms 命名空间下进行,需要在 k8s 集群中先创建 ms 命名空间。
[root@k8s-master1 ms]# kubectl create namespace ms
[root@k8s-master1 ms]# kubectl get ns | grep ms
ms Active 23s
3.1 熟悉Spring Cloud微服务项目
1 gitlab代码仓库
https://github.com/HyjyLc/simple-microservice/

2 代码分支说明
(1) dev1 交付代码
(2) dev2 增加Dockerfile
(3) dev3 增加K8s资源编排
(4) dev4 增加APM监控系统(SkyWalking)
(5) master 最终上线

注: 我这里根据 dev4 分支进行部署操作

架构图1: image-20220113150235432

架构图2:

image-20220114114447804

前端访问: image-20220116200729807

3.2 源代码编译构建
Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。
[root@k8s-master1 ms]# pwd
/root/ms

1 配置jdk、maven环境变量
# tar -xzf jdk-8u45-linux-x64.tar.gz
# tar -xzf apache-maven-3.5.0-bin.tar.gz
# mv jdk1.8.0_45/ /usr/local/jdk
# mv apache-maven-3.5.0/ /usr/local/maven
# cat >> /etc/profile << EOF
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=\$JAVA_HOME/lib/tools.jar:\$JAVA_HOME/jre/lib/rt.jar
export PATH=\$JAVA_HOME/bin:/usr/local/maven/bin:\$PATH
EOF

# source /etc/profile
[root@k8s-master1 ms]# java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
[root@k8s-master1 ms]#
[root@k8s-master1 ms]# mvn -v
Apache Maven 3.5.0 (ff8f5e7444045639af65f6095c62210b5713f426; 2017-04-04T03:39:06+08:00)
Maven home: /usr/local/maven
Java version: 1.8.0_45, vendor: Oracle Corporation
Java home: /usr/local/jdk/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-862.el7.x86_64", arch: "amd64", family: "unix"
[root@k8s-master1 ms]#

2 修改maven仓库地址
参考网址: https://maven.aliyun.com/mvn/guide
打开maven的配置文件,一般在maven安装目录的conf/settings.xml,在<mirrors></mirrors>标签中添加如下mirror子节点。
# vim /usr/local/maven/conf/settings.xml
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>

3 解压微服务项目包
# unzip simple-microservice.zip
# cd simple-microservice/

4 修改微服务应用连接mysql、eureka的连接地址配置
[root@k8s-master1 simple-microservice]# pwd
/root/ms/simple-microservice

mysql的连接地址为: mysql:3306
MySQL Service DNS名称:mysql.ms.svc.cluster.local

eureka的连接地址为:
http://eureka-0.eureka.ms:8888/eureka,http://eureka-1.eureka.ms:8888/eureka,http://eureka-2.eureka.ms:8888/eureka
Eureka集群节点Pod DNS名称:
http://eureka-0.eureka.ms.svc.cluster.local
http://eureka-1.eureka.ms.svc.cluster.local
http://eureka-2.eureka.ms.svc.cluster.local

(1) portal-service
# vim portal-service/src/main/resources/application-fat.yml
修改连接eureka地址配置

(2) gateway-service
# vim gateway-service/src/main/resources/application-fat.yml
修改连接eureka地址配置

(3) order-service
# vim order-service/order-service-biz/src/main/resources/application-fat.yml
修改连接eureka、mysql地址配置

(4) product-service
# vim product-service/product-service-biz/src/main/resources/application-fat.yml
修改连接eureka、mysql地址配置

(5) stock-service
# vim stock-service/stock-service-biz/src/main/resources/application-fat.yml
修改连接eureka、mysql地址配置

(6) eureka-service
# vim eureka-service/src/main/resources/application-fat.yml
修改连接eureka地址配置

5 编译代码
[root@k8s-master1 simple-microservice]# pwd
/root/ms/simple-microservice

# mvn clean package -Dmaven.test.skip=true

代码编译构建成功: image-20220113154311779

6 编译后的jar文件所在目录
[root@k8s-master1 simple-microservice]# pwd
/root/ms/simple-microservice

(1) portal-service
# ls -l portal-service/target/portal-service.jar

(2) gateway-service
# ls -l gateway-service/target/gateway-service.jar

(3) order-service
# ls -l order-service/order-service-biz/target/order-service-biz.jar

(4) product-service
# ls -l product-service/product-service-biz/target/product-service-biz.jar

(5) stock-service
# ls -l stock-service/stock-service-biz/target/stock-service-biz.jar

(6) eureka-service
# ls -l eureka-service/target/eureka-service.jar
3.3 增加dockerfile容器编排文件

这里以order-service为例,其它服务类似

[root@k8s-master1 simple-microservice]# pwd
/root/ms/simple-microservice

# cat order-service/order-service-biz/Dockerfile
FROM  java:8-jdk-alpine
LABEL maintainer lc
ENV JAVA_ARGS="-Dfile.encoding=UTF8 -Duser.timezone=GMT+08"
RUN  sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
     apk add -U tzdata && \
     ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./target/order-service-biz.jar ./
COPY skywalking /skywalking
EXPOSE 8020
CMD java -javaagent:/skywalking/skywalking-agent.jar=agent.service_name=ms-order,agent.instance_name=$(echo $HOSTNAME | awk -F- '{print $1"-"$NF}'),collector.backend_service=172.16.1.60:11800 $JAVA_ARGS $JAVA_OPTS -jar /order-service-biz.jar

说明:
agent.service_name=ms-order: 在skywalking中表示服务的名字,通常一个服务下有多个实例。

$(echo $HOSTNAME | awk -F- '{print $1"-"$NF}'): 表示以"-"为分割,截取pod容器主机名第一位和最后一位,然后以"-"连接,在
skywalking中表示pod实例。
示例:
# echo $(echo calico-node-pmf4q | awk -F- '{print $1"-"$NF}')
calico-pmf4q

collector.backend_service=172.16.1.60:11800: 指定SkyWalking服务器所在的地址及端口。

$JAVA_OPTS: 该变量在k8s yaml文件中定义,在pod容器中被引用。
3.4 增加K8s服务编排文件

这里以order-service为例,其它服务类似

[root@k8s-master1 simple-microservice]# pwd
/root/ms/simple-microservice

# cat k8s/order.yaml
apiVersion: apps/v1
kind: Deployment 
metadata:
  name: order
  namespace: ms 
spec:
  replicas: 1
  selector:
    matchLabels:
      project: ms
      app: order
  template:
    metadata:
      labels:
        project: ms 
        app: order
    spec:
      imagePullSecrets:
      - name: registry-pull-secret
      containers:
      - name: order
        image: 172.16.1.61/microservice/order:2022-01-15-22-38-07
        imagePullPolicy: Always
        ports:
          - protocol: TCP
            containerPort: 8020 
        env:
          - name: JAVA_OPTS
            value: "-Xmx1g"
        resources:
          requests:
            cpu: 0.5
            memory: 256Mi
          limits:
            cpu: 1
            memory: 1Gi
        readinessProbe:
          tcpSocket:
            port: 8020
          initialDelaySeconds: 60
          periodSeconds: 10
        livenessProbe:
          tcpSocket:
            port: 8020
          initialDelaySeconds: 60
          periodSeconds: 10
3.5 在K8s中部署MySQL
[root@k8s-master1 simple-microservice]# pwd
/root/ms/simple-microservice

1 应用yaml文件
# kubectl apply -f db/mysql.yaml
secret/mysql created
deployment.apps/mysql created
persistentvolumeclaim/mysql created
service/mysql created

2 查看pod、svc信息
# kubectl get pod,svc,ep -o wide -n ms
NAME READY STATUS RESTARTS AGE IP NODE
pod/mysql-59cdc7bd8-mrtl4 1/1 Running 0 13m 172.27.169.159 k8s-node2

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/mysql ClusterIP 172.28.181.225 <none> 3306/TCP 13m app=mysql,project=www

NAME ENDPOINTS AGE
endpoints/mysql 172.27.169.159:3306 13m

3 查看pvc,pv信息
# kubectl get pvc,pv -n ms

image-20220116010808691

4 查看存储
[root@k8s_nfs ~]# ls -l /ifs/kubernetes/
total 4
drwxrwxrwx 6 polkitd root 4096 Jan 16 00:51 ms-mysql-pvc-0b238551-7655-4564-8edc-8c6b42d2ecaa
[root@k8s_nfs ~]#

5 创建数据库并导入数据
# yum install mysql -y
# mysql -h 172.28.181.225 -u root -p'123456'
MySQL [(none)]> show grants for lc@'%';
+---------------------------------------------+
| Grants for lc@% |
+---------------------------------------------+
| GRANT USAGE ON *.* TO 'lc'@'%' |
| GRANT ALL PRIVILEGES ON `k8s`.* TO 'lc'@'%' |
+---------------------------------------------+
2 rows in set (0.00 sec)

MySQL [(none)]> show grants for root@'%';
+-------------------------------------------------------------+
| Grants for root@% |
+-------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION |
+-------------------------------------------------------------+
1 row in set (0.00 sec)

MySQL [(none)]> create database tb_order;
MySQL [(none)]> create database tb_product;
MySQL [(none)]> create database tb_stock;
MySQL [(none)]> use tb_order;
MySQL [tb_order]> source /root/ms/simple-microservice/db/order.sql
MySQL [tb_order]> use tb_product;
MySQL [tb_product]> source /root/ms/simple-microservice/db/product.sql
MySQL [tb_product]> use tb_stock;
MySQL [tb_stock]> source /root/ms/simple-microservice/db/stock.sql
MySQL [tb_stock]> exit
3.6 微服务部署脚本
[root@k8s-master1 k8s]# pwd
/root/ms/simple-microservice/k8s

1 创建 secret 用于 pod 从 harbor 仓库拉取镜像时进行账号密码验证
# docker_registry="172.16.1.61"
# 存储登录Harbor认证信息
# kubectl create secret docker-registry registry-pull-secret \
--docker-server=$docker_registry --docker-username=admin \
--docker-password=Harbor12345 --docker-email=admin@lc.com \
-n ms

# kubectl get secret -n ms | grep registry-pull-secret
registry-pull-secret   kubernetes.io/dockerconfigjson        1      31s

2 登录habor仓库,方便脚本推送镜像到harbor仓库
# docker login 172.16.1.61
Username: admin
Password: Harbor12345
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

3 脚本
[root@k8s-master1 k8s]# cat docker_build.sh
#!/bin/bash

# 说明: 执行脚本时所在的目录必须为 ../simple-microservice/k8s/

# Harbor仓库IP地址
docker_registry="172.16.1.61"

# 微服务应用部署列表
service_list="eureka-service order-service product-service stock-service gateway-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
   # 进入应用中Dockerfile所在的目录
   cd ${work_dir}/$service
   # 业务程序需进入biz目录里构建
   if ls |grep biz &>/dev/null; then
      cd ${service}-biz
   fi
   # 拿掉最后一个 "-" 及其右边的字符串,比如"eureka-service"变为"eureka"
   service="${service%-*}"
   # 镜像名称=Harbor仓库IP/Harbor仓库项目名/微服务应用名作为镜像仓库名:以镜像构建时间作为镜像版本
   image_name="${docker_registry}/microservice/${service}:$(date +%F-%H-%M-%S)"
   # 构建微服务应用镜像
   docker build -t ${image_name} .
   # 将微服务镜像上传到Harbor镜像仓库
   docker push ${image_name}
   # 修改微服务应用k8s编排yaml文件中镜像地址为新推送的镜像地址并apply
   sed -i -r "s#(image: )(.*)#\1${image_name}#" ${current_dir}/${service}.yaml
   kubectl apply -f ${current_dir}/${service}.yaml
done
[root@k8s-master1 k8s]# 

4 微服务应用部署顺序
(1) 注册中心
eureka-service

(2) 业务应用
1) order-service
2) product-service
3) stock-service

(3) 网关服务
gateway-service

(4) 前端服务
portal-service
3.7 在K8s中部署Eureka集群

Eureka高可用集群: image-20220116150559614

[root@k8s-master1 k8s]# pwd
/root/ms/simple-microservice/k8s

1 部署
# bash docker_build.sh eureka-service

2 查看 pod 的相关信息
# kubectl get pod -l app=eureka -n ms
NAME READY STATUS RESTARTS AGE
eureka-0 1/1 Running 0 71m
eureka-1 1/1 Running 0 70m
eureka-2 1/1 Running 0 69m

# kubectl get svc/eureka -n ms
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
eureka ClusterIP None <none> 8888/TCP 71m

# kubectl get ingress/eureka -n ms
NAME CLASS HOSTS ADDRESS PORTS AGE
eureka <none> eureka.lc.cn 172.28.127.25 80 72m

3 访问 Eureka 集群 UI
(1) 修改windows的hosts解析
在"C:\Windows\System32\drivers\etc\hosts"文件中添加如下内容
172.16.1.83 eureka.lc.cn

(2) 在浏览器中访问UI界面
http://eureka.lc.cn/

访问Eureka的UI界面: image-20220116163346704

3.8 部署微服务业务程序
[root@k8s-master1 k8s]# pwd
/root/ms/simple-microservice/k8s

1 部署 order-service 应用
# bash docker_build.sh order-service

2 部署 product-service 应用
# bash docker_build.sh product-service

3 部署 stock-service 应用
# bash docker_build.sh stock-service

4 部署网关服务
# bash docker_build.sh gateway-service

5 部署前端服务
# bash docker_build.sh portal-service
3.9 访问微服务
[root@k8s-master1 k8s]# pwd
/root/ms/simple-microservice/k8s

1 在 Eureka UI 界面查看注册上来的应用
http://eureka.lc.cn/

Eureka UI界面: image-20220116184755731

2 查看Harbor中的镜像仓库
http://172.16.1.61/

Harbor UI界面: image-20220116185019283

3 查看pod的相关信息
[root@k8s-master1 k8s]# kubectl get pod,svc,ep,ingress,pvc,pv -o wide -n ms

输出结果: image-20220116185815251

4 访问portal
(1) 修改windows的hosts解析
在"C:\Windows\System32\drivers\etc\hosts"文件中添加如下内容
172.16.1.84 portal.ctnrs.com gateway.ctnrs.com

(2) http://portal.ctnrs.com/

主页面:

image-20220116193730307

添加商品:

image-20220116194303062

查询订单

image-20220116194411619

3.10 微服务升级与扩容
[root@k8s-master1 k8s]# pwd
/root/ms/simple-microservice/k8s

1 微服务应用升级
(1) 更新portal应用的首页
# vim ../portal-service/src/main/resources/templates/index.ftl
......(省略的内容)
<body>
<h1>hello lc 2022</h1>
......(省略的内容)

(2) 更新portal应用的pod
# bash docker_build.sh portal-service
注: 当portal应用的新的pod准备好后会将旧的pod给删除。

(3) 访问portal应用页面

pod更替: image-20220118003543848

UI页面: image-20220118003800015

2 扩容微服务应用
(1) 扩容order应用
# kubectl scale deployment order --replicas=2 -n ms

(2) 查看eureka注册的order应用

image-20220118010158169

4 微服务生产环境踩坑案例

4.1 限制了容器资源,还经常被杀死
1 问题描述
在JAVA1.9版本之前,是不能自动发现docker设置的内存限制,随着应用负载起伏就会造成内存使用过大,超过limits限制,从而触发K8s杀掉该容器。

2 解决办法
(1) 手动指定JVM堆内存大小

示例: image-20220118234321735

(2) 配置JVM自动识别(1.9版本+才支持)
- XX:+UnlockExperimentalVMOptions
- XX:+UseCGroupMemoryLimitForHeap
4.2 滚动更新之健康检查重要性
1 问题描述
滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据Probe状态来决定是否继续更新以及是否允许接入流量,这样在整个滚动更新过程中可
保证始终会有可用的Pod存在,达到平滑升级。

2 解决办法

示例: image-20220118235108221

4.3 滚动更新期间造成流量丢失
1 问题描述
滚动更新触发,Pod在删除过程中,有些节点kube-proxy还没来得及同步iptables规则,从而部分流量请求到Terminating的Pod上,导致请求出错。

2 解决办法
配置preStop回调,在容器终止前优雅暂停5秒,给kube-proxy多预留一点时间。

示例: image-20220119002936677

5 APM监控微服务项目

5.1 APM监控系统说明
1 微服务监控需求
随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。这些服务可能不同编程语言开发,不同团队开发,可能部
署很多副本。因此,就需要一些可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。"APM系统"就在
这样的问题背景下产生了。

APM系统从整体维度到局部维度展示各项指标,将跨应用的所有调用链性能信息集中展现,可方便度量整体和局部性能,并且方便找到故障产生的源头,
生产上可极大缩短故障排除时间。

2 APM监控系统是什么
APM(ApplicationPerformance Management)是一种应用程序性能管理监控工具,通过汇聚业务系统各处理环节的实时数据,分析业务系统各事
务处理的交易路径和处理时间,实现对应用的全链路性能监测。

相比接触的Prometheus、Zabbix这类监控系统,APM系统主要监控的是应用程序内部,例如:
(1) 请求链路追踪: 通过分析服务调用关系,绘制运行时拓扑信息,可视化展示
(2) 调用情况衡量: 各个调用环节的性能分析,例如吞吐量、响应时间、错误次数
(3) 运行情况反馈: 告警,通过调用链结合业务日志快速定位错误信息

3 APM监控系统选择依据
APM类监控系统有: Skywalking、Pinpoint、Zipkin

关于选型,可以从以下方面考虑:
(1) 探针的性能消耗
APM组件服务的影响应该做到足够小,数据分析要快,性能占用小。
(2) 代码的侵入性
即也作为业务组件,应当尽可能少入侵或者无入侵其它业务系统,对于使用方的透明,减少开发人员的负担。
(3) 监控维度
分析的维度尽可能多。
(4) 可扩展性
一个优秀的调用跟踪系统必须支持分布式部署,具备良好的可扩展性,能够支持的组件越多当然越好。

APM监控架构图: image-20220119090320430

5.2 Skywalking说明
1 Skywalking介绍
Skywalking 是一个分布式应用程序性能监控系统,针对微服务体系结构而设计,其主要功能有:
(1) 多种监控手段: 可以通过语言探针和 service mesh 获得监控数据。
(2) 多个语言自动探针: 包括 Java,.NET Core 和 Node.JS。
(3) 轻量高效: 无需大数据平台和大量的服务器资源。
(4) 模块化: UI、存储、集群管理都有多种机制可选。
(5) 支持告警。
(6) 优秀的可视化解决方案。

2 Skywalking架构

架构图: frame-v8

5.3 Skywalking部署

部署架构图: image-20220119094320610

在 k8s_nfs 172.16.1.60 节点上操作

1 部署ES数据库
# docker run --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" -d elasticsearch:7.7.0

2 部署Skywalking OAP
(1) 软件包下载地址并解压
https://archive.apache.org/dist/skywalking/8.3.0/apache-skywalking-apm-es7-8.3.0.tar.gz
# yum install java-11-openjdk –y
# tar zxvf apache-skywalking-apm-es7-8.3.0.tar.gz
# cd apache-skywalking-apm-bin-es7/

(2) 指定数据源
# vim config/application.yml
storage:
# 这里使用elasticsearch7
selector: ${SW_STORAGE:elasticsearch7}
...
elasticsearch7:
nameSpace: ${SW_NAMESPACE:""}
# 指定ES地址
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:172.16.1.60:9200}

(3) 启动OAP和UI
./bin/startup.sh

(4) 访问UI
http://172.16.1.60:8080

3 微服务接入Skywalking监控
(1) 内置Agent包路径
apache-skywalking-apm-bin-es7/agent/

(2) 启动Java程序以探针方式集成Agent
java -javaagent:/skywalking/skywalking-agent.jar=agent.service_name=<项目名称>,agent.instance_name=<实例名称>,collector.backend_service=<Skywalking服务器>:11800 -jar xxx.jar
5.4 Skywalking UI使用

1 导航栏

image-20220118020415711

第一栏: 不同内容主题的监控面板,应用/数据库/容器等
第二栏: 操作,包括编辑/导出当前数据/导入展示数据/不同服务端点筛选展示
第三栏: 不同纬度展示,服务/实例/端点

2 全局

image-20220118020751829

1 Service Load:            CPM 每分钟回调次数
2 Slow Services: 慢响应服务,单位ms
3 Un-Health Services: 不健康的服务,1为满分
4 Slow Endpoints: 慢端点,单位ms
5 Global Response Latency: 百分比响应延时,不同百分比的延时时间,单位ms
6 Global Heatmap: 服务响应时间热力分布图,根据时间段内不同响应时间的数量显示颜色深度
7 底部栏: 展示数据的时间区间,点击可以调整

3 Service

image-20220118021354578

1 Service Apdex(数字):                 当前服务的评分
2 Service Apdex(折线图): 当前服务评分趋势图
3 Service Avg Response Times: 服务平均响应时间,单位ms
4 Service Response Time Percentile: 服务响应时间百分比,单位ms
5 Successful Rate(数字): 请求成功率
6 Successful Rate(折线图): 请求成功率趋势图
7 Service Load(数字): 每分钟请求数
8 Service Load(折线图): 每分钟请求数趋势图
9 Service Instances Load: 服务实例的每分钟请求数
10 Slow Service Instance: 慢服务实例,单位ms
11 Service Instance Successful Rate: 服务实例成功率

4 Instance

image-20220118021757987

1 Service Instance Load:              当前实例的每分钟请求数
2 Service Instance Successful Rate: 当前实例的请求成功率
3 Service Instance Latency: 当前实例的响应延时
4 JVM CPU: jvm占用CPU的百分比
5 JVM Memory: JVM堆内存,单位MB
6 JVM GC Time: JVM垃圾回收时间,包含YGC和OGC
7 JVM GC Count: JVM垃圾回收次数,包含YGC和OGC
8 JVM Thread Count: JVM线程统计
9 CLR XX: .NET服务的指标,类似JVM虚拟机

5 Endpoint

image-20220118021901135

1 Endpoint Load in Current Service:     每个端点的每分钟请求数
2 Slow Endpoints in Current Service: 每个端点的最慢请求时间,单位ms
3 Successful Rate in Current Service: 每个端点的请求成功率
4 Endpoint Load: 端点请求数趋势图
5 Endpoint Avg Response Time: 端点平均响应时间趋势图
6 Endpoint Response Time Percentile: 端口响应时间的百分位数
7 Endpoint Successful Rate: 端点请求成功率

6 拓扑图

image-20220118022619074


posted @ 2022-01-20 11:34  云起时。  阅读(443)  评论(0编辑  收藏  举报