微服务容器化迁移——在K8s中部署Spring Cloud

作者:小树扎根儿

邮箱:zjg_num01@163.com

一、从运维角度看微服务:

1.1 微服务的特点:

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

1.2 微服务的不足:

  1. 沟通成本:微服务相比于传统单体应用开发团队沟通成本更大。
  2. 数据一致性:每个微服务都有自己独立的数据存储,可能会造成数据的不一致。
  3. 运维成本:微服务部署会涉及更多的组件,对运维的部署、监控、更新都带来更大的挑战。
  4. 内部架构复杂性:微服务本身就会带来架构的复杂性,如:服务之间的耦合性设计、分布式事务等。

1.3 单体架构 vs 微服务:

  1. 单体架构:

    • 单体架构的优势:

    易于部署;

    易于测试;

    • 单体架构的不足:

    代码臃肿,难以维护;

    构建、部署时间成本大;

    新人上手难;

  2. 微服务架构:

1.4 Java微服务框架:

  • Spring Boot
  • Spring Cloud / Spring Cloud Alibaba
  • Dubbo

二、在K8S平台部署微服务需要考虑的问题:

  1. 微服务架构图:

  2. 项目迁移到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

  3. 传统部署与K8S部署的区别:

    • 传统方式部署项目:

    • K8S方式部署项目:

三、在K8S平台部署Spring Cloud微服务项目:

1、熟悉Spring Cloud微服务项目:

  1. 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
  2. Spring Cloud微服务项目地址:https://github.com/xiaoshuzhagen/simple-microservice

  3. Spring Cloud微服务使用到的组件如下:

2、通过二进制包方式部署Consul:

  1. 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、构建项目镜像并推送到镜像仓库:

  1. 编写微服务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"]
    
  2. 通过maven命令构建微服务:

    mvn clean package -Dmaven.test.skip=true
    
  3. jar包构建成docker镜像并推送到镜像仓库中:

    docker build -t gateway-service .
    # -f : 可以指定要使用的Dockerfile路径.
    # -m : 可以设置内存最大值.
    # -t : 可以指定镜像名称及版本.
    # .  : 指定构建镜像的上下文路径,docker build 会将这个路径下所有的文件都打包上传给Docker引擎.
    
  4. 将微服务镜像推送到镜像仓库中:

    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、服务编排:

  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
    
  2. 部署微服务:

    kubectl apply -f product-service.yaml
    
  3. 资源限制问题:

    虽然微服务运行的Pod已经进行了资源限制,如:最大使用1G内存,但Pod中的jvm并不会感知到资源限制问题,jvm

    运行时如果资源不够会继续申请物理资源,此时,Pod检测到使用的物理资源已经超出自身限制的最大可用户资源,

    会将Java进程kill掉,从而Java程序会抛出OOM。

    • jdk 1.8之前的版本:

      ​ 服务编排的yaml中指定环境变量:

      Dockfile中引用服务编排yaml中定义的环境变量:

    • jdk 1.9以上的版本不存在这个问题。

原文地址:https://www.cnblogs.com/xiaoshuzhagen/p/14704912.html