
作者:小树扎根儿
邮箱:zjg_num01@163.com
一、从运维角度看微服务:
1.1 微服务的特点:
- 服务组件化:每个微服务独立开发、部署,可以有效避免因单个微服务的变更引起整个系统重新部署的情况。
- 技术栈灵活:约定通信方式,使得服务本身功能实现对技术栈要求不再敏感。
- 独立部署:每个微服务独立部署,加速部署速度,方便扩展。
- 扩展性强:每个微服务可以部署多个,并且有负载均衡能力。
- 独立数据:每个微服务有独立的基本组件,例如:数据库、缓存等。
1.2 微服务的不足:
- 沟通成本:微服务相比于传统单体应用开发团队沟通成本更大。
- 数据一致性:每个微服务都有自己独立的数据存储,可能会造成数据的不一致。
- 运维成本:微服务部署会涉及更多的组件,对运维的部署、监控、更新都带来更大的挑战。
- 内部架构复杂性:微服务本身就会带来架构的复杂性,如:服务之间的耦合性设计、分布式事务等。
1.3 单体架构 vs 微服务:
-
单体架构:
- 单体架构的优势:
易于部署;
易于测试;
- 单体架构的不足:
代码臃肿,难以维护;
构建、部署时间成本大;
新人上手难;
-
微服务架构:
1.4 Java微服务框架:
- Spring Boot
- Spring Cloud / Spring Cloud Alibaba
- Dubbo
二、在K8S平台部署微服务需要考虑的问题:
-
微服务架构图:
-
项目迁移到K8S平台的流程:
-
制作镜像:
镜像分为三层:
基础镜像:centos、ubuntu ... 纯净系统;
运行环境:基础镜像 + 运行环境(如:jdk、php ....);
项目镜像:基础镜像 + 运行环境 + 应用程序代码;
-
控制器管理Pod:
K8S包括以下几种控制器:
Deployment:无状态部署;
StatefulSet:有状态部署;
DaemonSet:守护进程部署;
Job & CronJob:批处理;
-
通过Service暴露应用:
Service定义了Pod的逻辑集合和访问这个集合的策略;
Service的引入是为了解决Pod的动态变化,提供服务发现和负载均衡。
-
通过Ingress对外发布应用:
Ingress:
通过Service关联Pod;
基于域名访问;
通过Ingress Controller实现Pod的负载均衡;
-
日志/监控:
主流方案:
FileBeat + ELK
Prometheus + Grafana
-
-
传统部署与K8S部署的区别:
-
传统方式部署项目:
-
K8S方式部署项目:
-
三、在K8S平台部署Spring Cloud微服务项目:
1、熟悉Spring Cloud微服务项目:
-
K8S服务器部署清单:
角色 IP 组件 k8s-master 192.168.1.90 kube-apiserver、kube-controller、kube-scheduler、docker、etcd K8s-node1 192.168.1.91 kubelet、kube-proxy、docker、etcd K8s-node2 192.168.1.92 kubelet、kube-proxy、docker、etcd -
Spring Cloud微服务项目地址:https://github.com/xiaoshuzhagen/simple-microservice
-
Spring Cloud微服务使用到的组件如下:
2、通过二进制包方式部署Consul:
-
Consul服务器部署清单:
角色 IP 组件 Consul Node 192.168.1.90 consul server(master)、 consul client Consul Node 192.168.1.91 consul server(follower)、consul client Consul Node 192.168.1.92 consul server(follower)、consul client
3、构建项目镜像并推送到镜像仓库:
-
编写微服务
Dockerfile
:# 基础镜像,如果本地没有,会从远程仓库拉取 FROM openjdk:11 # 镜像的制作人 MAINTAINER zjg_num01@163.com # 定义环境变量 ENV JAVA_OPTS="$JAVA_OPTS" # 声明容器应该打开的端口并没有实际将端口启用 EXPOSE 6010 # 拷贝本地文件到镜像中 COPY ./target/gateway-service.jar ./ # 指定容器启动时要执行的命令,但如果存在CMD命令,CMD命令中的参数会被附加到ENTRYPOIN指令的后面 ENTRYPOINT ["java","-jar","./gateway-service.jar","$JAVA_OPTS"]
-
通过
maven
命令构建微服务:mvn clean package -Dmaven.test.skip=true
-
将
jar
包构建成docker
镜像并推送到镜像仓库中:docker build -t gateway-service . # -f : 可以指定要使用的Dockerfile路径. # -m : 可以设置内存最大值. # -t : 可以指定镜像名称及版本. # . : 指定构建镜像的上下文路径,docker build 会将这个路径下所有的文件都打包上传给Docker引擎.
-
将微服务镜像推送到镜像仓库中:
docker login http://192.168.1.90:6666 docker push http://192.168.1.90:6666/simple-microservice/gateway-service:v1.0 # simple-microservice:表示镜像仓库中的项目名称,把镜像打到指定的项目下. # gateway-service: 表示镜像名称. # v1.0:表示镜像版本.
4、K8S部署Spring Cloud项目:
1、服务编排:
-
编写微服务需要k8s编排的
yaml
文件:apiVersion: apps/v1 kind: Deployment metadata: name: product-service namespace: simple-microservice spec: replicas: 2 selector: matchLabels: project: simple-microservice app: product-service template: metadata: labels: project: simple-microservice app: product-service spec: imagePullSecrets: - name: registry-pull-secert containers: - name: product-service image: 192.168.1.90:7777/simple-microservice/product-service:v1.0 imagePullPolicy: Always ports: - protocol: tcp containerPort: 8888 resources: requests: cpu: 0.5 memory: 256Mi readinessProbe: tcpSocket: port: 8888 initialDelaySeconds: 60 periodSeconds: 10 livenessProbe: tcpSocket: port: 8888 initialDelaySeconds: 60 periodSeconds: 10
-
部署微服务:
kubectl apply -f product-service.yaml
-
资源限制问题:
虽然微服务运行的Pod已经进行了资源限制,如:最大使用1G内存,但Pod中的jvm并不会感知到资源限制问题,jvm
运行时如果资源不够会继续申请物理资源,此时,Pod检测到使用的物理资源已经超出自身限制的最大可用户资源,
会将Java进程kill掉,从而Java程序会抛出OOM。
-
jdk 1.8之前的版本:
服务编排的
yaml
中指定环境变量:
Dockfile
中引用服务编排yaml
中定义的环境变量:
-
jdk 1.9以上的版本不存在这个问题。
-