01-微服务容器化迁移

从运维角度看微服务

单体应用:

01-微服务容器化迁移

特点:

  • 易于部署
  • 易于测试

不足:

  • 代码膨胀,难以维护
  • 构建、部署成本大
  • 新人上手难

微服务特点

01-微服务容器化迁移

将大的电商服务分成多个小的服务,每个服务都有一个小组维护,商品服务,订单服务和库存服务,分别维护各自的数据库,通过API Gateway统一进行转发,主要有以下特点:

•服务组件化
每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。
•技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么敏感,可以用多种开发语言对同一个平台进行开发。
•独立部署
每个微服务独立部署,加快部署速度,方便扩展。
•扩展性强
传统的业务软件架构设计存在一定局限性(缓存,代码优化等,消息队列等设计),导致可能不会因为服务器扩展而可承受更高的并发量,每个微服务可以部署多个,并且有负载均衡能力。
•独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。

微服务不足

•不同小团队的沟通成本增大
•不同业务模块的数据一致性需要不同团队相互配合来达到
•对运维成本的考验:部署、监控
•内部架构复杂性,对运维要求变高
•大量服务治理

Java微服务框架

•Spring Boot:快速开发微服务的框架,较为单一
•Spring Cloud:基于SpringBoot实现的一个完整的微服务解决方案套件,可以实现服务发现,熔断,流量管理
•Dubbo:阿里巴巴开源的微服务治理框架

在K8S平台部署微服务考虑的问题

常见微服务架构图

01-微服务容器化迁移
  • 前后端分离,前端注重调用api是否可通
  • 网关是前端api统一的访问的入口,网关这里可以做熔断,限流,负责将请求分发到不同的后端微服务
  • 微服务之前解耦,不同为服务之间访问通过注册中心进行
  • 微服务一般都还有有数据库,分布式存储,消息队列,缓存等框架

对微服务项目架构理解

•微服务间如何通信?REST API,RPC,MQ(Kafka,rabbitMQ等)

•微服务如何发现彼此?注册中心

•组件之间怎么个调用关系?比如说一个网站购物商城,下单后会调用支付服务,然后生成订单服务,最后调用库存服务

•哪个服务作为整个网站入口?前(例如前端商品服务界面)后端(gateaway作为入口)进行分离

•哪些微服务需要对外访问?前端和微服务网关

•微服务怎么部署?更新?扩容?

•区分有状态应用与无状态应用

为什么用注册中心系统

微服务太多面临的问题:

  • 怎么记录一个微服务多个副本接口地址(微服务之间的访问需要知道对方的地址)?
  • 怎么实现一个微服务多个副本负载均衡?(多个微服务需要有健康检查)
  • 怎么判断一个微服务副本是否可用?(如何实现健康检查)

主流注册中心:Eureka,Nacos,Consul

01-微服务容器化迁移

微服务在Eureka服务器注册,当Eureka客户端需要数据时,直接从后端微服务中返回给客户端进行消费

在K8s部署项目流程

01-微服务容器化迁移

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

容器化微服务项目实施步骤

具体步骤:
第一步:熟悉Spring Cloud微服务项目
第二步:源代码编译构建
第三步:构建项目镜像并推送到镜像仓库
第四步:K8s服务编排
第五步:在K8s中部署Eureka集群(注册中心)和MySQL数据库
第六步:部署微服务网关服务
第七步:部署微服务业务程序
第八步:部署微服务前端
第九步:微服务对外发布
第十步:微服务升级与扩容

第一步:熟悉Spring Cloud微服务项目

https://github.com/lizhenliang/simple-microservice

01-微服务容器化迁移
代码分支说明:
•dev1交付代码
•dev2 增加Dockerfile
•dev3 增加K8s资源编排
•dev4 增加APM监控系统
•master 最终上线
服务器端口服务用途
kubernetes集群8888eureka注册中心
3306mysql数据库
8010product商品服务
8020order订单服务
8030stock库存服务
8080portal前端
9999gateway网关
01-微服务容器化迁移

通过负载均衡暴露公网IP

portal通过API调用Gateway

Gateway负责将api请求转发到后端微服务

微服务在Eureka中注册,微服务之间通信通过Eureka获取到对方地址

所有微服务都有自己独立的数据表(一般大的项目需要有独立的数据库)

项目代码:

01-微服务容器化迁移
  • 这个项目以“-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

确定版本可以兼容公司开发人员的项目

01-微服务容器化迁移
mvn clean package -Dmaven.test.skip=true
01-微服务容器化迁移

portal-service和gateway-service目录下会出现target

01-微服务容器化迁移

启动相关配置

vim gateway-service/src/main/resources/application.yml 
# 9999端口开启
vim gateway-service/src/main/resources/application-fat.yml

第三步:构建项目镜像并推送到镜像仓库

01-微服务容器化迁移

普通项目在-service目录下就有Dockerfile,构建业务应用时(拥有$servicename-service-biz目录):product-service、order-service、stock-service,需要进入到以上业务项目目录,并在目录下创建Dockerfile

01-微服务容器化迁移

这里观察一下业务项目的Docker所在位置(例如order-service-biz)

01-微服务容器化迁移

为了多个业务应用的构建,在外面目录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
01-微服务容器化迁移

执行脚本:bash docker_build.sh

推送成功:

01-微服务容器化迁移

第四步:K8s服务编排架构理解

01-微服务容器化迁移

前端和网关接口都要暴露在公网,所以需要配置Ingress、Service,微服务部分(product、stok、order)不需要对公网暴露服务,所以不需要创建,Eureka可以创建一个service暴露服务注册地址

第五步:在K8s中部署Erureka集群和MySQL数据库

Eureka集群内部也是互相注册的:

01-微服务容器化迁移

修改源代码中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注册页面:

01-微服务容器化迁移
01-微服务容器化迁移

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

上述过程:

01-微服务容器化迁移
01-微服务容器化迁移

eureka注册检查:

01-微服务容器化迁移

部署网关(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

01-微服务容器化迁移

portal-service/src/main/resources/static/js/orderList.js

01-微服务容器化迁移

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
01-微服务容器化迁移
cd k8s
./docker_build.sh portal-service

注册查看

01-微服务容器化迁移

域名访问:http://portal.ctnrs.com/

01-微服务容器化迁移

选择查询商品服务:

01-微服务容器化迁移

购买后会调用订单微服务,在查询订单服务中查看:

01-微服务容器化迁移

微服务升级:对要升级的微服务进行上述步骤打包镜像:版本,替代运行的镜像

模拟更新版本:

vim portal-service/src/main/resources/templates/index.ftl

01-微服务容器化迁移

重跑微服务

./docker_build.sh portal-service
01-微服务容器化迁移

微服务扩容:对Pod扩容副本数

对于无状态的服务直接scale即可

kubectl -n ms scale deployment portal --replicas=3

生产环境踩坑经验分享

限制了容器资源,还经常被杀死?

在JAVA1.9版本之前,是不能自动发现docker设置的内存限制,随着应用负载起伏就会造成内存使用过大,超过limits限制,从而触发K8s杀掉该容器。

解决办法:

  • 手动指定JVM堆内存大小
  • 配置JVM自动识别(1.9版本+才支持)-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

建议使用手动指定JVM堆内存大小:

01-微服务容器化迁移

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

01-微服务容器化迁移

滚动更新之健康检查重要性

滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据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

(0)
上一篇 2024年2月6日 下午4:35
下一篇 2024年2月20日 下午6:50

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注