从运维角度看微服务
单体应用:
特点:
- 易于部署
- 易于测试
不足:
- 代码膨胀,难以维护
- 构建、部署成本大
- 新人上手难
微服务特点
将大的电商服务分成多个小的服务,每个服务都有一个小组维护,商品服务,订单服务和库存服务,分别维护各自的数据库,通过API Gateway统一进行转发,主要有以下特点:
•服务组件化
每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。
•技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么敏感,可以用多种开发语言对同一个平台进行开发。
•独立部署
每个微服务独立部署,加快部署速度,方便扩展。
•扩展性强
传统的业务软件架构设计存在一定局限性(缓存,代码优化等,消息队列等设计),导致可能不会因为服务器扩展而可承受更高的并发量,每个微服务可以部署多个,并且有负载均衡能力。
•独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。
微服务不足
•不同小团队的沟通成本增大
•不同业务模块的数据一致性需要不同团队相互配合来达到
•对运维成本的考验:部署、监控
•内部架构复杂性,对运维要求变高
•大量服务治理
Java微服务框架
•Spring Boot:快速开发微服务的框架,较为单一
•Spring Cloud:基于SpringBoot实现的一个完整的微服务解决方案套件,可以实现服务发现,熔断,流量管理
•Dubbo:阿里巴巴开源的微服务治理框架
在K8S平台部署微服务考虑的问题
常见微服务架构图
- 前后端分离,前端注重调用api是否可通
- 网关是前端api统一的访问的入口,网关这里可以做熔断,限流,负责将请求分发到不同的后端微服务
- 微服务之前解耦,不同为服务之间访问通过注册中心进行
- 微服务一般都还有有数据库,分布式存储,消息队列,缓存等框架
对微服务项目架构理解
•微服务间如何通信?REST API,RPC,MQ(Kafka,rabbitMQ等)
•微服务如何发现彼此?注册中心
•组件之间怎么个调用关系?比如说一个网站购物商城,下单后会调用支付服务,然后生成订单服务,最后调用库存服务
•哪个服务作为整个网站入口?前(例如前端商品服务界面)后端(gateaway作为入口)进行分离
•哪些微服务需要对外访问?前端和微服务网关
•微服务怎么部署?更新?扩容?
•区分有状态应用与无状态应用
为什么用注册中心系统
微服务太多面临的问题:
- 怎么记录一个微服务多个副本接口地址(微服务之间的访问需要知道对方的地址)?
- 怎么实现一个微服务多个副本负载均衡?(多个微服务需要有健康检查)
- 怎么判断一个微服务副本是否可用?(如何实现健康检查)
主流注册中心:Eureka,Nacos,Consul
微服务在Eureka服务器注册,当Eureka客户端需要数据时,直接从后端微服务中返回给客户端进行消费
在K8s部署项目流程
在K8S平台部署Spring Cloud微服务项目
容器化微服务项目实施步骤
具体步骤:
第一步:熟悉Spring Cloud微服务项目
第二步:源代码编译构建
第三步:构建项目镜像并推送到镜像仓库
第四步:K8s服务编排
第五步:在K8s中部署Eureka集群(注册中心)和MySQL数据库
第六步:部署微服务网关服务
第七步:部署微服务业务程序
第八步:部署微服务前端
第九步:微服务对外发布
第十步:微服务升级与扩容
第一步:熟悉Spring Cloud微服务项目
https://github.com/lizhenliang/simple-microservice
代码分支说明:
•dev1交付代码
•dev2 增加Dockerfile
•dev3 增加K8s资源编排
•dev4 增加APM监控系统
•master 最终上线
服务器 | 端口 | 服务 | 用途 |
kubernetes集群 | 8888 | eureka | 注册中心 |
3306 | mysql | 数据库 | |
8010 | product | 商品服务 | |
8020 | order | 订单服务 | |
8030 | stock | 库存服务 | |
8080 | portal | 前端 | |
9999 | gateway | 网关 |
通过负载均衡暴露公网IP
portal通过API调用Gateway
Gateway负责将api请求转发到后端微服务
微服务在Eureka中注册,微服务之间通信通过Eureka获取到对方地址
所有微服务都有自己独立的数据表(一般大的项目需要有独立的数据库)
项目代码:
- 这个项目以“-service”结尾的都是微服务
- basic-common是一个公共库
- db是数据库目录
README.md查看:
这是一个基于SpringCloud的微服务架构项目
部署须知
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、服务启动顺序:eureka -> mysql -> product,stock,order -> gateway -> portal
第二步:源代码编译构建
Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。
# 获取项目
git clone https://github.com/lizhenliang/simple-microservice.git
cd simple-microservice/
# 和开发确定安装jdk的对应版本
yum install java-1.8.0-openjdk
# maven管理项目的编译构建,安装maven,mvn配置文件是pom.xml
yum install maven
# 使用mvn编译构建,每次构建清理之前的包,跳过单元测试(生产环境不要跳过)
mvn clean package -Dmaven.test.skip=true
确定版本可以兼容公司开发人员的项目
mvn clean package -Dmaven.test.skip=true
portal-service和gateway-service目录下会出现target
启动相关配置
vim gateway-service/src/main/resources/application.yml
# 9999端口开启
vim gateway-service/src/main/resources/application-fat.yml
第三步:构建项目镜像并推送到镜像仓库
普通项目在-service目录下就有Dockerfile,构建业务应用时(拥有$servicename-service-biz目录):product-service、order-service、stock-service,需要进入到以上业务项目目录,并在目录下创建Dockerfile
这里观察一下业务项目的Docker所在位置(例如order-service-biz)
为了多个业务应用的构建,在外面目录simple-microservice写了一个脚本
外部编译+Dockerfile脚本(需要有docker仓库,harbor私有仓库部署过程可见https://www.ljh.cool/4978.html,在仓库下创建一个microservice的私有项目,以匹配下面脚本中的橙色高亮项目名称):
#!/bin/bash
docker_registry=hub.ljh.com # harbor镜像仓库地址
service_list="eureka-service gateway-service order-service product-service stock-service portal-service"
service_list=${1:-${service_list}}
work_dir=$PWD
cd $work_dir
mvn clean package -Dmaven.test.skip=true
for service in $service_list; do
cd $work_dir/$service
# 业务程序需进入有biz目录的目录并进入目录里构建
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
普通项目目录(eureka、gateway、portal):
simple-microservice/eureka-service/Dockerfile:
FROM java:8-jdk-alpine
LABEL maintainer XXXXX
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/eureka-service.jar ./
EXPOSE 8888
simple-microservice/gateway-service/Dockerfile:
FROM java:8-jdk-alpine
LABEL maintainer XXXXX
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/gateway-service.jar ./
EXPOSE 9999
CMD java -jar /gateway-service.jar
simple-microservice/portal-service
FROM java:8-jdk-alpine
LABEL maintainer XXXXX
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/portal-service.jar ./
EXPOSE 8080
CMD java -jar /portal-service.jar
[root@k8s-master portal-service]# pwd
/root/micro/simple-microservice/portal-service
业务项目目录(product-service、order-service、stock-service):
simple-microservice/order-service/order-service-biz/Dockerfile
FROM java:8-jdk-alpine
LABEL maintainer XXXXX
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/product-service-biz.jar ./
EXPOSE 8010
CMD java -jar /product-service-biz.jar
simple-microservice/product-service/product-service-biz/Dockerfile
FROM java:8-jdk-alpine
LABEL maintainer XXXXX
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 ./
EXPOSE 8020
CMD java -jar /order-service-biz.jar
simple-microservice/stock-service/stock-service-biz/Dockerfile
FROM java:8-jdk-alpine
LABEL maintainer XXXXX
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/stock-service-biz.jar ./
EXPOSE 8030
CMD java -jar /stock-service-biz.jar
本地登陆dockerhub,这里就是用admin用户登录了,建议创建一个新的用户并授权项目进行登陆
docker login hub.ljh.com
执行脚本:bash docker_build.sh
推送成功:
第四步:K8s服务编排架构理解
前端和网关接口都要暴露在公网,所以需要配置Ingress、Service,微服务部分(product、stok、order)不需要对公网暴露服务,所以不需要创建,Eureka可以创建一个service暴露服务注册地址
第五步:在K8s中部署Erureka集群和MySQL数据库
Eureka集群内部也是互相注册的:
修改源代码中eureka配置文件:
eureka-service/src/main/resources/application-fat.yml
eureka:
server:
renewal-percent-threshold: 0.9
enable-self-preservation: false
eviction-interval-timer-in-ms: 40000
instance:
hostname: 127.0.0.1
prefer-ip-address: false
client:
register-with-eureka: true
serviceUrl:
defaultZone: http://eureka-0.eureka.ms:${server.port}/eureka/,http://eureka-1.eureka.ms:${server.port}/eureka/,http://eureka-2.eureka.ms:${server.port}/eureka/
fetch-registry: true
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
kubernetes集群创建ms名称空间:
kubectl create ns ms
修改docker_build.sh,并添加kubernetes yaml文件
simple-microservice/k8s/docker_build.sh
#!/bin/bash
docker_registry=hub.ljh.com
# 存储登录Harbor认证信息
kubectl create secret docker-registry registry-pull-secret \
--docker-server=$docker_registry \
--docker-username=admin \
--docker-password=Harbor12345 \
--docker-email=admin@gmail.com \
-n ms
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
# 业务程序需进入biz目录里构建
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}
# 这个sed命令的作用是在文件中查找以 "image: " 开头的行,并将其后的部分替换为 $image_name 中定义的内容。修改yaml中镜像地址为新推送的地址,并apply
sed -i -r "s#(image: )(.*)#\1$image_name#" ${current_dir}/${service}.yaml
# 下面这行可以选择检查完当前目录后统一部署,这里先不直接部署了
# kubectl apply -f ${current_dir}/${service}.yaml
done
添加的yaml,和脚本放在相同目录:
k8s/eureka.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: eureka
namespace: ms
annotations:
kubernetes.io/ingress.class: "nginx" #声名需要使用nginx方式解析ingress
spec:
rules:
- host: eureka.ctnrs.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: eureka
port:
number: 8888
---
apiVersion: v1
kind: Service
metadata:
name: eureka
namespace: ms
spec:
clusterIP: None
ports:
- port: 8888
name: eureka
selector:
project: ms
app: eureka
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eureka
namespace: ms
spec:
replicas: 3
selector:
matchLabels:
project: ms
app: eureka
serviceName: "eureka"
template:
metadata:
labels:
project: ms
app: eureka
spec:
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: eureka
image: hub.ljh.com/microservice/eureka:2024-02-13-16-53-16
ports:
- protocol: TCP
containerPort: 8888
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
cpu: 0.5
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
readinessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 60
periodSeconds: 10
kubectl create -f eureka.yaml
eureka注册页面:
k8s部署MySQL
simple-microservice/k8s/mysql.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql
namespace: ms
type: Opaque
data:
mysql-root-password: "MTIzNDU2"
mysql-password: "MTIzNDU2"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: ms
spec:
selector:
matchLabels:
project: www
app: mysql
template:
metadata:
labels:
project: www
app: mysql
spec:
containers:
- name: db
image: mysql:5.7.30
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 500m
memory: 512Mi
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: mysql-root-password
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: mysql-password
- name: MYSQL_USER
value: "mysqluser"
- name: MYSQL_DATABASE
value: "k8s"
ports:
- name: mysql
containerPort: 3306
livenessProbe:
exec:
command:
- sh
- -c
- "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}"
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- sh
- -c
- "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}"
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
emptyDir: {}
#persistentVolumeClaim:
# claimName: mysql
---
# 生产环境使用pv,这里使用临时目录了
#apiVersion: v1
#kind: PersistentVolumeClaim
#metadata:
# name: mysql
# namespace: ms
#spec:
# storageClassName: "managed-nfs-storage"
# accessModes:
# - "ReadWriteOnce"
# resources:
# requests:
# storage: "8Gi"
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: ms
spec:
type: ClusterIP
ports:
- name: mysql
port: 3306
targetPort: mysql
selector:
project: www
app: mysql
1、部署MySQL
kubectl apply -f mysql.yaml
2、导入sql文件
# 将源代码里db目录下sql文件拷贝到mysql容器并导入:
# 目前所在目录:simple-microservice
kubectl -n ms cp db mysql-xxxxxxxxxxxxx:/
kubectl -n ms exec -it mysql-xxxxxxxxxxxxx -- bash
mysql -uroot -p$MYSQL_ROOT_PASSWORD
mysql> create database tb_product;
mysql> create database tb_order;
mysql> create database tb_stock;
mysql> use tb_product;
mysql> source /db/product.sql;
mysql> use tb_order;
mysql> source /db/order.sql;
mysql> use tb_stock;
mysql> source /db/stock.sql;
3、修改product、stock、order连接数据库地址,MySQL Service DNS名称:mysql.ms.svc.cluster.local
product-service/product-service-biz/src/main/resources/application-fat.yml
修改:url: jdbc:mysql://mysql.ms:3306/tb_product?characterEncoding=utf-8
stock-service/stock-service-biz/src/main/resources/application-fat.yml
修改:url: jdbc:mysql://mysql.ms:3306/tb_stock?characterEncoding=utf-8
order-service/order-service-biz/src/main/resources/application-fat.yml
修改:url: jdbc:mysql://mysql.ms:3306/tb_order?characterEncoding=utf-8
第六步至第九步:在K8s中部署微服务
部署业务程序(product、stock、order)
simple-microservice/k8s/product.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: product
namespace: ms
spec:
replicas: 1
selector:
matchLabels:
project: ms
app: product
template:
metadata:
labels:
project: ms
app: product
spec:
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: product
image: hub.ljh.com/microservice/product:2024-02-14-01-13-17
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 8010
resources:
requests:
cpu: 0.5
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
readinessProbe:
tcpSocket:
port: 8010
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8010
initialDelaySeconds: 60
periodSeconds: 10
simple-microservice/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: hub.ljh.com/microservice/order:2024-02-14-01-21-10
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 8020
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
simple-microservice/k8s/stock.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: stock
namespace: ms
spec:
replicas: 1
selector:
matchLabels:
project: ms
app: stock
template:
metadata:
labels:
project: ms
app: stock
spec:
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: stock
image: hub.ljh.com/microservice/stock:2024-02-14-01-22-25
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 8030
resources:
requests:
cpu: 0.5
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
readinessProbe:
tcpSocket:
port: 8030
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8030
initialDelaySeconds: 60
periodSeconds: 10
cd k8s
./docker_build.sh product-service
./docker_build.sh order-service
./docker_build.sh stock-service
上述过程:
eureka注册检查:
部署网关(gateway):为内部微服务提供统一的访问入口,还提供一些功能,例如限流,智能路由、负载均衡,Springcloud使用了zuul进行网关部署
修改域名:
simple-microservice/gateway-service/src/main/resources/application-fat.yml
修改: defaultZone: http://eureka-0.eureka.ms:8888/eureka,http://eureka-1.eureka.ms:8888/eureka,http://eureka-2.eureka.ms:8888/eureka
simple-microservice/k8s/gateway.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateway
namespace: ms
annotations:
kubernetes.io/ingress.class: "nginx" #声名需要使用nginx方式解析ingress
spec:
ingressClassName: nginx
rules:
- host: gateway.ctnrs.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gateway
port:
number: 9999
---
apiVersion: v1
kind: Service
metadata:
name: gateway
namespace: ms
spec:
ports:
- port: 9999
name: gateway
selector:
project: ms
app: gateway
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
namespace: ms
spec:
replicas: 2
selector:
matchLabels:
project: ms
app: gateway
template:
metadata:
labels:
project: ms
app: gateway
spec:
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: gateway
image: hub.ljh.com/microservice/gateway:2024-02-13-16-53-42
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 9999
resources:
requests:
cpu: 0.5
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
readinessProbe:
tcpSocket:
port: 9999
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 9999
initialDelaySeconds: 60
periodSeconds: 10
./docker_build.sh gateway-service
部署前端(portal)
修改前端调用后端接口域名配置:
portal-service/src/main/resources/static/js/productList.js
portal-service/src/main/resources/static/js/orderList.js
simple-microservice/k8s/portal.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: portal
namespace: ms
annotations:
kubernetes.io/ingress.class: "nginx" #声名需要使用nginx方式解析ingress
spec:
# ingressClassName: nginx
rules:
- host: portal.ctnrs.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: portal
port:
number: 8080
---
apiVersion: v1
kind: Service
metadata:
name: portal
namespace: ms
spec:
ports:
- port: 8080
name: portal
selector:
project: ms
app: portal
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: portal
namespace: ms
spec:
replicas: 1
selector:
matchLabels:
project: ms
app: portal
template:
metadata:
labels:
project: ms
app: portal
spec:
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: portal
image: hub.ljh.com/microservice/portal:2024-02-13-16-55-33
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 8080
# resources:
# requests:
# cpu: 0.5
# memory: 256Mi
# limits:
# cpu: 1
# memory: 1Gi
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
cd k8s
./docker_build.sh portal-service
注册查看
域名访问:http://portal.ctnrs.com/
选择查询商品服务:
购买后会调用订单微服务,在查询订单服务中查看:
微服务升级:对要升级的微服务进行上述步骤打包镜像:版本,替代运行的镜像
模拟更新版本:
vim portal-service/src/main/resources/templates/index.ftl
重跑微服务
./docker_build.sh portal-service
微服务扩容:对Pod扩容副本数
对于无状态的服务直接scale即可
kubectl -n ms scale deployment portal --replicas=3
生产环境踩坑经验分享
限制了容器资源,还经常被杀死?
在JAVA1.9版本之前,是不能自动发现docker设置的内存限制,随着应用负载起伏就会造成内存使用过大,超过limits限制,从而触发K8s杀掉该容器。
解决办法:
- 手动指定JVM堆内存大小
- 配置JVM自动识别(1.9版本+才支持)-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
建议使用手动指定JVM堆内存大小:
Dockerfile需要指定环境变量:
例如product需要修改为:
FROM lizhenliang/java:8-jdk-alpine
LABEL maintainer www.ctnrs.com
ENV JAVA_ARGS="-Dfile.encoding=UTF8 -Duser.timezone=GMT+08"
COPY ./target/product-service-biz.jar ./
COPY pinpoint /pinpoint
EXPOSE 8010
CMD java -jar -javaagent:/pinpoint/pinpoint-bootstrap-1.8.3.jar -Dpinpoint.agentId=$(echo $HOSTNAME | awk -F- '{print "product-"$NF}') -Dpinpoint.applicationName=ms-product $JAVA_ARGS $JAVA_OPTS /product-service-biz.jar
滚动更新期间造成流量丢失
滚动更新触发,Pod在删除过程中,有些节点kube-proxy还没来得及同步iptables规则,从而部分流量请求到Terminating的Pod上,导致请求出错。
原理:kube-proxy通过watch-list方式获取到api-server滚动更新的相关消息后,才会修改iptables相关规则
解决办法:配置preStop回调,在容器终止前优雅暂停5秒,给kube-proxy多预留一点时间。等到新的pod起来后再等待几秒,再杀掉旧的pod
滚动更新之健康检查重要性
滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据Probe状态来决定是否继续更新以及是否允许接入流量,这样在整个滚动更新过程中可保证始终会有可用的Pod存在,达到平滑升级。
readinessProbe:
tcpSocket:
port: 9999
initialDelaySeconds: 60
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 9999
initialDelaySeconds: 60
periodSeconds: 10
发布者:LJH,转发请注明出处:https://www.ljh.cool/40743.html