前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >kubernetes(二十)SpringCloud微服务容器化迁移

kubernetes(二十)SpringCloud微服务容器化迁移

作者头像
alexhuiwang
发布2020-09-23 10:00:26
1.4K0
发布2020-09-23 10:00:26
举报
文章被收录于专栏:运维博客

SpringCloud微服务容器化迁移

从运维角度看微服务

单体应用VS 微服务

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

详情参考: https://blog.csdn.net/qinaye/article/details/82840625

单体应用的优缺点
  • 优点 便于共享:单个归档文件包含所有功能,便于在团队之间以及不同的部署阶段之间共享。 易于测试:单体应用一旦部署,所有的服务或特性就都可以使用了,这简化了测试过程,因为没有额外的依赖,每项测试都可以在部署完成后立刻开始。 易于部署:只需将单个归档文件复制到单个目录下。
  • 缺点 复杂性高:由于是单个归档文件,所以整个项目文件包含的模块非常多,导致模块的边界模糊、依赖关系不清晰、代码的质量参差不齐,混乱的堆在一起,使得整个项目非常复杂。以致每次修改代码,都非常小心,可能添加一个简单的功能,或者修改一个Bug都会带来隐藏的缺陷。 技术债务:随着时间的推移、需求的变更和技术人员的更替,会逐渐形成应用程序的技术债务,并且越积越多。 扩展能力受限:单体应用只能作为一个整体进行扩展,无法根据业务模块的需要进行伸缩。 阻碍技术创新:对于单体应用来说,技术是在开发之前经过慎重评估后选定的,每个团队成员都必须使用相同的开发语言、持久化存储及消息系统。
微服务架构的优缺点
  • 优点 易于开发和维护:一个微服务只会关注一个特定的业务功能,所以业务清晰、代码量较少。开发和维护单个微服务相对简单。 单个微服务启动较快 局部修改容易部署:单体应用只要有修改,就得重新部署整个应用。微服务解决了这样的问题。一般来说,对某个微服务进行修改,只需要重新部署这个服务即可。 技术栈不受限制:在微服务架构中,可以结合项目业务及团队的特点,合理的选择技术栈。 按需伸缩:可根据需求,实现细粒度的扩展。
  • 缺点 运维要求高:更多的服务意味着要投入更多的运维。 分布式固有的复杂性:使用微服务构建的是分布式系统。对于一个分布式系统,系统容错、网络延迟、分布式事务等都会带来巨大的问题。 接口调整成本高:微服务之间通过接口进行通信。如果修改某一个微服务的API,可能所有用到这个接口的微服务都需要进行调整。

微服务的特点

服务组件化

每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。

技术栈灵活

约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。

独立部署

每个微服务独立部署,加快部署速度,方便扩展。

扩展性强

每个微服务可以部署多个,并且有负载均衡能力。

独立数据

每个微服务有独立的基本组件,例如数据库、缓存等。

java微服务框架

SpringBoot: 快速开发微服务的框架

SpringCloud: 基于springBoot实现的一套微服务解决方案

Dubbo: 阿里巴巴开源的微服务框架

在k8s平台部署微服务需要考虑的问题

微服务架构图

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

对微服务架构的理解

微服务间如何通信?REST API,RPC,MQ 微服务如何发现彼此?注册中心 组件之间怎么个调用关系? • 哪个服务作为整个网站入口?前后端分离 哪些微服务需要对外访问?前端和微服务网关 微服务怎么部署?更新?扩容? 区分有状态应用与无状态应用

为什么要用注册中心

  • 微服务太多面临的问题:
    • 怎么记录一个微服务多个副本接口地址?
    • 怎么实现一个微服务多个副本负载均衡?
    • 怎么判断一个微服务副本是否可用?
    • 主流注册中心:Eureka,Nacos,Consul
kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

容器交付流程

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

在K8s部署项目流程

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

容器化微服务项目

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

熟悉Spring Cloud微服务项目

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

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

代码分支说明:

• dev1 交付代码

• dev2 增加Dockerfile

• dev3 增加K8S资源编排

• dev4 增加微服务链路监控

• master 最终上线

源代码编译构建

  • 下载 microservic-code.zip 这个代码包,并解压出dev1分支
代码语言:javascript
复制
$ unzip simple-microservice-dev1.zip && cd simple-microservice-dev1 
  • 安装java和maven环境

aliyun maven: https://maven.aliyun.com/mvn/guide

代码语言:javascript
复制
$ 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    #编译
  • 构建jdk基础环境(选用)

需要下载好

代码语言:javascript
复制
$ 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 . 

构建项目镜像并推送到镜像仓库

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移
  • 下载 microservic-code.zip 这个代码包,并解压出dev2分支
代码语言:javascript
复制
$ unzip simple-microservice-dev2.zip && cd simple-microservice-dev2
$ mvn clean package -Dmaven.test.skip=true         #编译
  • 对gateway 制作镜像
代码语言:javascript
复制
$ 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仓库

本人之前部署的harbor: 192.168.56.18 hub.cropy.cn

代码语言:javascript
复制
$ docker login hub.cropy.cn
$ docker tag gateway:latest hub.cropy.cn/demo/gateway:latest

K8s服务编排

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

在K8s中部署Eureka集群(注册中心)和MySQL数据库

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

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

  1. 制作镜像并推送到harbor
代码语言:javascript
复制
$ 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
  1. 制作k8s yaml文件
代码语言:javascript
复制
$ 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
  1. 准备namespace和harbor secret
代码语言:javascript
复制
$ 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
  1. 构建eurake-service
代码语言:javascript
复制
$ 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  
  1. 测试eurake
代码语言:javascript
复制
$ 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文件

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

6 . 基础mysql数据库创建

代码语言:javascript
复制
$ 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

部署微服务业务程序

  1. 构建镜像(部署业务程序(product、stock、order)
代码语言:javascript
复制
$ 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
  1. 修改数据库和注册中心的连接配置(一定要配置上default ns 下的mysql svc)
代码语言:javascript
复制
主要在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
  1. 数据库数据导入
代码语言:javascript
复制
 $ 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;
  1. 重新构建镜像(脚本类的内容请联系QQ: 122725501 获取)
代码语言:javascript
复制
$ 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是否正常

微服务对外发布

代码语言:javascript
复制
$ 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

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

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

滚动更新是默认发布策略,当配置健康检查时,滚动更新会根据Probe状态来决定是否继续更新以及是否允许接入流量,这样在整个滚动更新过程中可抱歉始终会有可用的Pod存在,达到平滑升级。

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

滚动更新之流量丢失

kubernetes(二十)SpringCloud微服务容器化迁移
kubernetes(二十)SpringCloud微服务容器化迁移

滚动更新触发,Pod在删除过程中,有些节点kube-proxy还没来得及同步iptables规则,从而部分流量请求到Terminating的Pod上,导致请求出错。

解决办法:配置preStop回调,在容器终止前优雅暂停5秒,给kube-proxy多预留一点时间

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringCloud微服务容器化迁移
    • 从运维角度看微服务
      • 单体应用VS 微服务
      • 微服务的特点
      • java微服务框架
    • 在k8s平台部署微服务需要考虑的问题
      • 微服务架构图
      • 对微服务架构的理解
      • 为什么要用注册中心
      • 容器交付流程
      • 在K8s部署项目流程
    • 容器化微服务项目
      • 熟悉Spring Cloud微服务项目
      • 源代码编译构建
      • 构建项目镜像并推送到镜像仓库
      • K8s服务编排
      • 在K8s中部署Eureka集群(注册中心)和MySQL数据库
      • 部署微服务业务程序
      • 微服务对外发布
      • 微服务升级与扩容
    • 生产环境踩坑经验分享
      • 限制了容器资源,还经常被杀死
      • 滚动更新之健康检查的重要性
      • 滚动更新之流量丢失
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档