第26章: 微服务容器化迁移
说明: 本文主要关注微服务在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 项目服务说明
服务 | 服务名 | 端口号 | 连接信息 |
---|---|---|---|
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"
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
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) 新人上手难
2 微服务架构
(1) 特点
1) 服务组件化
每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。
2) 技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。
3) 独立部署
每个微服务独立部署,加快部署速度,方便扩展。
4) 扩展性强
每个微服务可以部署多个,并且有负载均衡能力。
5) 独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。
(2) 不足
1) 沟通成本
2) 数据一致性
3) 运维成本(部署、监控)
4) 内部架构复杂性
5) 大量服务治理
3 JAVA微服务框架
(1) Spring Boot: 快速开发微服务的框架
(2) Spring Cloud: 基于SpringBoot实现的一个完整的微服务解决方案
(3) Dubbo: 阿里巴巴开源的微服务治理框架
2.2 在K8S平台部署微服务考虑的问题
2 对微服务项目架构理解
(1) 微服务间如何通信?REST API,RPC,MQ
(2) 微服务如何发现彼此?注册中心
(3) 组件之间怎么个调用关系?
(4) 哪个服务作为整个网站入口?前后端分离
(5) 哪些微服务需要对外访问?前端和微服务网关
(6) 微服务怎么部署?更新?扩容?
(7) 区分有状态应用与无状态应用
3 为什么用注册中心系统
(1) 微服务太多面临的问题
1) 怎么记录一个微服务多个副本接口地址?
2) 怎么实现一个微服务多个副本负载均衡?
3) 怎么判断一个微服务副本是否可用?
(2) 主流注册中心
Eureka,Nacos,Consul
4 在k8s部署项目流程
dockerfile 》》》Deployment、StatefulSet、DaemonSet 》》》Service Ingress 》》》Prometheus+Grafana、ELK Stack
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 分支进行部署操作
架构图2:
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
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
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集群
[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/
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/
2 查看Harbor中的镜像仓库
http://172.16.1.61/
3 查看pod的相关信息
[root@k8s-master1 k8s]# kubectl get pod,svc,ep,ingress,pvc,pv -o wide -n ms
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/
主页面:
添加商品:
查询订单
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应用页面
2 扩容微服务应用
(1) 扩容order应用
# kubectl scale deployment order --replicas=2 -n ms
(2) 查看eureka注册的order应用
4 微服务生产环境踩坑案例
4.1 限制了容器资源,还经常被杀死
1 问题描述
在JAVA1.9版本之前,是不能自动发现docker设置的内存限制,随着应用负载起伏就会造成内存使用过大,超过limits限制,从而触发K8s杀掉该容器。
2 解决办法
(1) 手动指定JVM堆内存大小
(2) 配置JVM自动识别(1.9版本+才支持)
- XX:+UnlockExperimentalVMOptions
- XX:+UseCGroupMemoryLimitForHeap
4.2 滚动更新之健康检查重要性
1 问题描述
滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据Probe状态来决定是否继续更新以及是否允许接入流量,这样在整个滚动更新过程中可
保证始终会有可用的Pod存在,达到平滑升级。
2 解决办法
4.3 滚动更新期间造成流量丢失
1 问题描述
滚动更新触发,Pod在删除过程中,有些节点kube-proxy还没来得及同步iptables规则,从而部分流量请求到Terminating的Pod上,导致请求出错。
2 解决办法
配置preStop回调,在容器终止前优雅暂停5秒,给kube-proxy多预留一点时间。
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) 可扩展性
一个优秀的调用跟踪系统必须支持分布式部署,具备良好的可扩展性,能够支持的组件越多当然越好。
5.2 Skywalking说明
1 Skywalking介绍
Skywalking 是一个分布式应用程序性能监控系统,针对微服务体系结构而设计,其主要功能有:
(1) 多种监控手段: 可以通过语言探针和 service mesh 获得监控数据。
(2) 多个语言自动探针: 包括 Java,.NET Core 和 Node.JS。
(3) 轻量高效: 无需大数据平台和大量的服务器资源。
(4) 模块化: UI、存储、集群管理都有多种机制可选。
(5) 支持告警。
(6) 优秀的可视化解决方案。
2 Skywalking架构
5.3 Skywalking部署
在 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 导航栏
第一栏: 不同内容主题的监控面板,应用/数据库/容器等
第二栏: 操作,包括编辑/导出当前数据/导入展示数据/不同服务端点筛选展示
第三栏: 不同纬度展示,服务/实例/端点
2 全局
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
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
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
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 拓扑图