详情参考: https://blog.csdn.net/qinaye/article/details/82840625
服务组件化
每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。
技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。
独立部署
每个微服务独立部署,加快部署速度,方便扩展。
扩展性强
每个微服务可以部署多个,并且有负载均衡能力。
独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。
SpringBoot: 快速开发微服务的框架
SpringCloud: 基于springBoot实现的一套微服务解决方案
Dubbo: 阿里巴巴开源的微服务框架
微服务间如何通信?REST API,RPC,MQ 微服务如何发现彼此?注册中心 组件之间怎么个调用关系? • 哪个服务作为整个网站入口?前后端分离 哪些微服务需要对外访问?前端和微服务网关 微服务怎么部署?更新?扩容? 区分有状态应用与无状态应用
具体步骤: 第一步:熟悉Spring Cloud微服务项目 第二步:源代码编译构建 第三步:构建项目镜像并推送到镜像仓库 第四步:K8s服务编排 第五步:在K8s中部署Eureka集群(注册中心)和MySQL数据库 第六步:部署微服务网关服务 第七步:部署微服务业务程序 第八步:部署微服务前端 第九步:微服务对外发布 第十步:微服务升级与扩容
https://github.com/lizhenliang/simple-microservice
代码分支说明:
• dev1 交付代码
• dev2 增加Dockerfile
• dev3 增加K8S资源编排
• dev4 增加微服务链路监控
• master 最终上线
$ unzip simple-microservice-dev1.zip && cd simple-microservice-dev1
aliyun maven: https://maven.aliyun.com/mvn/guide
$ yum install java-1.8.0-openjdk maven
$ vim /etc/maven/settings.xml
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
$ mvn clean package -Dmaven.test.skip=true #编译
需要下载好
$ vim Dockerfile
FROM alpine:latest
LABEL maintainer="122725501@qq.com"
ADD jdk-8u261-linux-x64.tar.gz /usr/local/
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
apk update && apk upgrade && apk --no-cache add ca-certificates && \
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk && \
apk add glibc-2.30-r0.apk && \
rm -rf *.apk && \
rm -rf /var/cache/apk/*
# 设置JAVA变量环境
ENV JAVA_HOME=/usr/local/jdk1.8.0_261
ENV CLASSPATH=$JAVA_HOME/bin
ENV PATH=.:$JAVA_HOME/bin:$PATH
CMD ["java","-version"]
# 指定工作空间
WORKDIR /opt
$ docker build -t jdk-alpine:latest .
$ unzip simple-microservice-dev2.zip && cd simple-microservice-dev2
$ mvn clean package -Dmaven.test.skip=true #编译
$ cd simple-microservice-dev2/gateway-service/
$ vim Dockerfile
FROM java:8-jdk-alpine
LABEL maintainer 122725501@qq.com
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
apk add -U tzdata && \
rm -rf /var/cache/apk/* &&\
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./target/gateway-service.jar ./
EXPOSE 9999
CMD java -jar /gateway-service.jar
$ docker build -t gateway . #构建镜像
本人之前部署的harbor: 192.168.56.18 hub.cropy.cn
$ docker login hub.cropy.cn
$ docker tag gateway:latest hub.cropy.cn/demo/gateway:latest
StatefulSet+Headless DNS名称格式:
<statefulsetName-index>.<service-name> .<namespace
name>.svc.cluster.local
Eureka集群节点Pod名称:
http://eureka-0.eureka.ms.svc.cluster.local
http://eureka-1.eureka.ms.svc.cluster.local
http://eureka-2.eureka.ms.svc.cluster.loc
$ unzip simple-microservice-dev3.zip && cd simple-microservice-dev3
$ mvn clean package -Dmaven.test.skip=true
$ cd eureka-service && vim Dockerfile
FROM java:8-jdk-alpine
LABEL maintainer 122725501@qq.com
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 &&\
rm -rf /var/cache/apk/*
COPY ./target/eureka-service.jar ./
EXPOSE 8888
CMD java -jar -Deureka.instance.hostname=${MY_POD_NAME}.eureka.ms /eureka-service.jar
$ docker build -t eureka-service .
$ docker tag eureka-service hub.cropy.cn/demo/eureka-service
$ docker push hub.cropy.cn/demo/eureka-service
$ vim eurake-server.yaml
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: eureka
namespace: ms
spec:
rules:
- host: eureka.ctnrs.com
http:
paths:
- path: /
backend:
serviceName: eureka
servicePort: 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
containers:
- name: eureka
image: hub.cropy.cn/demo/eureka-service
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 namespace ms
$ kubectl create secret docker-registry registry-pull-secret --docker-server=hub.cropy.cn --docker-username=admin --docker-password=Harbor12345 -n ms
$ kubectl apply -f eureka.yaml
$ kubectl get pod -n ms
$ kubectl get svc -n ms
$ kubectl get statefulset -n ms
$ kubectl get ingress -n ms
$ kubectl get ep -n ms
$ kubectl get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ingress-controller-766fb9f77-dlf5j 1/1 Running 16 20d 192.168.56.13 k8s-node2 <none> <none>
$ kubectl get ingress -n ms
NAME CLASS HOSTS ADDRESS PORTS AGE
eureka <none> eureka.ctnrs.com 80 17m
绑定192.168.56.13 eureka.ctnrs.com 到宿主机hosts文件
6 . 基础mysql数据库创建
$ helm install java-demo-db --set persistence.storageClass="managed-nfs-storage" azure/mysql
$ kubectl get secret --namespace default java-demo-db-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo
RRGynGS53N
mysql -h java-demo-db-mysql -pRRGynGS53N # 获取访问方式
$ kubectl get svc
$ cd simple-microservice-dev3 && mvn clean package -Dmaven.test.skip=true && cd product-service/
vim Dockerfile
FROM java:8-jdk-alpine
LABEL maintainer 122725501@qq.com
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
apk add -U tzdata && \
rm -rf /var/cache/apk/* && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./target/product-service-biz.jar ./
EXPOSE 8010
CMD java -jar /product-service-biz.jar
主要在src/main/resources/application-fat.yml 配置文件中
1. msyql: order-service-biz,product-service-biz, stock-service-biz (**一定要配置上default ns 下的mysql svc**)
url: jdbc:mysql://java-demo-db-mysql.default:3306/tb_order?characterEncoding=utf-8
username: root
password: RRGynGS53N
2. eurake
defaultZone: http://eureka-0.eureka.ms:8888/eureka,http://eureka-1.eureka.ms:8888/eureka,http://eureka-2.eureka.ms:8888/eureka
$ cd simple-microservice-dev3/db
$ kubectl run mysql-client -it --image=mysql:5.7 -- bash
$ root@mysql-client:/# mysql -h java-demo-db-mysql -pRRGynGS53N # 测试登陆数据库(如不能登陆,请检查网络)
### 另起终端,准备导入数据
$ cd simple-microservice-dev3/db
$ kubectl cp order.sql mysql-client:/opt/
$ kubectl cp product.sql mysql-client:/opt/
$ kubectl cp stock.sql mysql-client:/opt/
### 回到登陆远程数据库的终端
mysql> source /opt/order.sql;
mysql> source /opt/stock.sql;
source /opt/product.sql;
$ cd microservic-code/simple-microservice-dev3
$ cd k8s && ls
docker_build.sh eureka.yaml gateway.yaml order.yaml portal.yaml product.yaml stock.yaml
$ vim docker_build.sh #自动构建脚本
#!/bin/bash
docker_registry=hub.cropy.cn
kubectl create secret docker-registry registry-pull-secret --docker-server=$docker_registry --docker-username=admin --docker-password=Harbor12345 --docker-email=admin@122725501.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
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 -i -r "s#(image: )(.*)#\1$image_name#" ${current_dir}/${service}.yaml
kubectl apply -f ${current_dir}/${service}.yaml
done
$ ./docker_build.sh # 自动构建并上传镜像,同时启动服务
$ kubectl get pod -n ms # 查看构建之后的pod是否正常
$ kubectl get ingress -n ms
NAME CLASS HOSTS ADDRESS PORTS AGE
eureka <none> eureka.ctnrs.com 80 21m
gateway <none> gateway.ctnrs.com 80 16m
portal <none> portal.ctnrs.com 80 15m
绑定上述域名到192.168.56.13 的hosts 解析文件,即可访问
微服务升级:对要升级的微服务进行上述步骤打包镜像:版本,替代运行的镜像
微服务扩容:对Pod扩容副本数
java不能自动发现docker设置的堆内存,这将会导致
JVM资源不稳定,超出limits限制,k8s会杀掉该容器!
解决办法:
• 手动指定JVM堆内存大小
• 配置JVM自动识别(1.9版本+才支持)-
XX:+UnlockExperimentalVMOptions -
XX:+UseCGroupMemoryLimitForHeap
滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据Probe状态来决定是否继续更新以及是否允许接入流量,这样在整个滚动更新过程中可抱歉始终会有可用的Pod存在,达到平滑升级。
滚动更新触发,Pod在删除过程中,有些节点kube-proxy还没来得及同步iptables规则,从而部分流量请求到Terminating的Pod上,导致请求出错。
解决办法:配置preStop回调,在容器终止前优雅暂停5秒,给kube-proxy多预留一点时间