SpringCloud微服务实例(K8S、Eureka、Zuul、Skywalking))

1、说明

在K8s Paas平台搭建SpringCloud微服务框架,进行微服务开发。网关采用Zuul1、服务注册与发现采用Eureka。链路跟踪与日志采集采用Skywalking。Skywalking日志采集是Skywalking8.5.0版本之后的功能,Skywalking日志采集采用服务工程主动推送的方式,与logback集成,可以满足中小型系统的日志采集和分析,数据库可选用elasticsearch,能保证良好的搜索性能。


新建一个k8s命名空间进行实验:

Yaml:

apiVersion: v1

kind: Namespace

metadata:

    name: sclouds

    labels:

       name: sclouds


设置默认命名空间:

kubectl config set-context $(kubectl config current-context) --namespace=sclouds


2、Eureka容器集群

2.1.StatefulSet、Headless Service

Eureka搭建容器集群,需要依赖k8s的statefulset组件。Eureka-server的每个实例需要相互同步状态。

StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括

稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。

稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现。

有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),有序收缩,有序删除(即从N-1到0)。

使用StatefulSet,StatefulSet中每个Pod的DNS就是固定的,格式为

    statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local

serviceName为Headless Service的名字0..N-1为Pod所在的序号,从0开始到N-1statefulSetName为StatefulSet的名字namespace为服务所在的namespace,Headless Service和StatefulSet必须在相同的namespacecluster.local为Cluster Domain


2.2.Ecureka Springboot镜像

集群由两个ecureka服务组成,服务工程基于Springboot开发,打包成jar包,最后打包成docker镜像在k8s上部署。

Sprinboot版本:2.6.2

SpringCloud版本:2021.0.1

pom.xml设置,引入spring-cloud-starter-netflix-eureka-server:

引入spring-boot-starter-web、spring-cloud-starter-netflix-eureka-server

    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <dependencyManagement>

        <dependencies>

            <dependency>

                <groupId>org.springframework.cloud</groupId>

                <artifactId>spring-cloud-dependencies</artifactId>

                <version>${spring-cloud.version}</version>

                <type>pom</type>

                <scope>import</scope>

            </dependency>

        </dependencies>

</dependencyManagement>

application.properties属性设置:

spring.application.name=register-server

server.port=8000

management.server.port=8001

eureka.instance.leaseRenewalIntervalInSeconds=10

eureka.instance.leaseExpirationDurationInSeconds=30

eureka.instance.hostname=${MY_POD_NAME}.register-server

eureka.instance.prefer-ip-address=true

eureka.client.fetch-registry=true

eureka.client.register-with-eureka=true

eureka.client.service-url.defaultZone=http://register-server-0.register-server:8000/eureka/,http://register-server-1.register-server:8000/eureka/

eureka.client.service-url.registryFetchIntervalSeconds=10

eureka.client.service-url.disable-delta=true

eureka.server.evictionIntervalTimerInMs=4000

eureka.server.enable-self-preservation=false

Dockfile:

FROM java:8

VOLUME /tmp

ADD eurekaclu-0.0.1-SNAPSHOT.jar /eurekaclu-0.0.1-SNAPSHOT.jar

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/eurekaclu-0.0.1-SNAPSHOT.jar"]

2.3.k8s service服务暴露

使用2.2的镜像部署statefulset。Service关联暴露服务。为了方便访问,设置成nodePort类型,暴露外网端口。

statefulset:

apiVersion: apps/v1

kind: StatefulSet

metadata:

  name: register-server

  labels:

    service: register-server

spec:

  replicas: 2

  serviceName: register-server

  selector:

    matchLabels:

      service: register-server

  template:

    metadata:

      labels:

        service: register-server

      annotations:

        service: register-server

    spec:

      containers:

        - name: register-server

          image: dw/eurekaclu-2

          imagePullPolicy: IfNotPresent

          env:

          - name: MY_POD_NAME

            valueFrom:

              fieldRef:

                fieldPath: metadata.name

          ports:

            - name: http

              containerPort: 8000

              protocol: TCP

          readinessProbe:

            httpGet:

              path: /actuator/health

              port: 8001

              scheme: HTTP

            failureThreshold: 3

            initialDelaySeconds: 60

            periodSeconds: 10

            successThreshold: 1

            timeoutSeconds: 10

          resources:

            limits:

              # cpu: 100m

              memory: 1Gi

            requests:

                # cpu: 100m

              memory: 1Gi

          volumeMounts:

          - mountPath: /Charts

            name: data

      volumes:

      - name: data

  podManagementPolicy: "Parallel"

Service:

apiVersion: v1

kind: Service

metadata:

  name: register-server

  labels:

    service: register-server

spec:

  type: NodePort

  ports:

    - port: 8000

      targetPort: 8000

      protocol: TCP

      name: http

      nodePort: 30111

  selector:

    service: register-server

依次应用statefulset、service,部署两个statefulset:


ecureka satefulset

这样可以得到两个ecurka-server的集群内url,和2.2节的属性设置对应:

register-server-0.register-server:8000

register-server-1.register-server:8000

导出nodePort,浏览器登录验证:


注册中心


3.Zuul1容器集群

Zuul1是springcloud早期的服务网关,这里使用旧一点的稳定版本。

3.1.zuul1 springboot

Zuul也要注册到eureka,需要引入eureka-client和netflix-zuul。服务注册ecureka使用上一章搭建的集群,根据k8s服务url规则,ecureka服务的url为http://register-server.sclouds.svc.cluster.local:8000/eureka/,k8s服务进行负载分发到两个stateful实例

Springboot版本:2.1.8

SpringCloud版本:Greenwich.SR2

Pom.xml:

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>

</dependency>

application.properties:

server.port=7005

spring.application.name=springboot-zuul-server

eureka.client.serviceUrl.defaultZone=http://register-server.sclouds.svc.cluster.local:8000/eureka/

zuul.stripPrefix=false

zuul.ignored-services="*"

zuul.routes.api-a.path=/ribbon/**

zuul.routes.api-a.serviceId=springboot-eureka-client

zuul.routes.api-a.strip-prefix=false

ribbon.eureka.enabled=true

eureka.instance.prefer-ip-address=true

注:这里设置一个路由规则,路由到springboot-eureka-client微服务(下文有例子)

Dockerfile:

FROM java:8

VOLUME /tmp

ADD ecurkazuul-0.0.1-SNAPSHOT.jar /ecurkazuul-0.0.1-SNAPSHOT.jar

ADD skagent /skagent

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/ecurkazuul-0.0.1-SNAPSHOT.jar"]

3.2.k8s service

Zuul集群实例不需要互相同步状态,部署Deployment即可。Service进行服务暴露负载

Yaml:

apiVersion: v1

kind: Service

metadata:

  name: ecurka-zuul

  namespace: sclouds

  labels:

    verison: "1.0.0"

    env: "test"

spec:

  type: NodePort

  selector:

    app: ecurka-zuul

    release: master

  ports:

      - name: http

        port: 7005

        targetPort: 7005

        nodePort: 30112

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: ecurka-zuul

  namespace: sclouds

  labels:

    verison: "1.0.0"

    env: "test"

spec:

  replicas: 2

  selector:

    matchLabels:

      app: ecurka-zuul

      release: master

  template:

    metadata:

      labels:

        app: ecurka-zuul

        release: master

    spec:

      containers:

        - name: ecurka-zuul

          image: dw/ecurka-zuul

          imagePullPolicy: IfNotPresent

          ports:

            - name: http

              containerPort: 7005

应用service,部署两个pod实例:

pods

登录ecureka,看到有两个zuul服务实例在运行:


ecureka

4、SkyWalking

这里简单介绍一下Windows单机部署

4.1.软件版本

Skywalking 8.7.0

下载地址:https://skywalking.apache.org/downloads/

Elasticsearch 6.8.23

下载地址:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-8-23

本文选择Elasticsearch 作为skywalking的数据库,skywalking与el的版本需要对应,如果使用Elasticsearch7,需要下载es后缀的skywalking版本。

4.2.elasticsearch

elasticsearch.yml修改:

4.3.Skywalking

分为两个服务,后台信息收集服务oap,前端门户ui(skywalking-webapp)

OAP后台服务

config:application.yml

选择数据库类型

UI门户工程

webapp.yml,如果端口被占用,可修改默认端口

webapp.yml


4.4.服务启动

启动Elasticsearch

执行elasticsearch.bat,默认占用9200端口

启动skywalking

执行startup.bat,或者分别执行oapService.bat、webappService.bat,默认占用11800,12800,8080端口。

4.5.Springboot工程接入

Skywalking对于Java工程是非侵入的,通过探针进行接口探测,数据上报。只需要在启动后台服务时,加入启动参数,指定Skywalking agent依赖包以及oap服务Url,idea中可在工程启动配置中配置,有两个属性需要注意,skywalking.agent.service_name是skywalking中显示的服务名称,不同服务需要区分。skywalking.collector.backend_service,是skywalking服务端的地址,要根据实际情况修改。本文中,skywalking没有部署到k8s中,写的是skywalking部署主机的地址。

参考:

-javaagent:J:\tmppro\demo\skagent\skywalking-agent.jar -Dskywalking.agent.service_name=DemoHelloService -Dskywalking.collector.backend_service=192.168.76.54:11800


idea java vm参数

HTTP调用,Skywalking前端观测


skywalking


4.6.springboot服务docker镜像打包修改

拷贝skywalking agent依赖到docker镜像打包目录


docker打包目录

修改Dockerfile,加入加粗字体部分:

FROM java:8

VOLUME /tmp

ADD ecurkaclient-0.0.1-SNAPSHOT.jar /ecurkaclient-0.0.1-SNAPSHOT.jar

ADD skagent /skagent

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-javaagent:/skagent/skywalking-agent.jar","-Dskywalking.agent.service_name=EurekaClient","-Dskywalking.collector.backend_service=192.168.76.54:11800","-jar","/ecurkaclient-0.0.1-SNAPSHOT.jar"]

5、服务实例


5.1.springboot镜像

Java代码,设置两个url作为服务实验:

package com.example.ecurkaclient;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class TestController {

    private static final Logger log = LoggerFactory.getLogger(TestController.class);

    @RequestMapping(value = "/hello", method = RequestMethod.GET)

    public ResponseX testHello() {

        ResponseX x = new ResponseX();

        x.setMsg("hello-x");

        log.info("######################################\n" + "hello");

        return x;

    }

    @RequestMapping(value = "/helloworld", method = RequestMethod.GET)

    public ResponseX testHellox() {

        ResponseX x = new ResponseX();

        x.setMsg("hello-world-x");

        log.info("######################################\n" + "hello-world");

        return x;

    }

}

application.properties:

server.port=7004

spring.application.name=springboot-eureka-client

eureka.client.serviceUrl.defaultZone=http://register-server.sclouds.svc.cluster.local:8000/eureka/

eureka.instance.prefer-ip-address=true

注:spring.application.name和前面zuul网关设置的zuul.routes.api-a.serviceId要对应。Zuul网关根据服务名称进行路由。

Dockerfile打包镜像:

FROM java:8

VOLUME /tmp

ADD ecurkaclient-0.0.1-SNAPSHOT.jar /ecurkaclient-0.0.1-SNAPSHOT.jar

ADD skagent /skagent

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-javaagent:/skagent/skywalking-agent.jar","-Dskywalking.agent.service_name=EurekaClient","-Dskywalking.collector.backend_service=192.168.76.54:11800","-jar","/ecurkaclient-0.0.1-SNAPSHOT.jar"]

5.2.k8s service

Yaml:

apiVersion: v1

kind: Service

metadata:

  name: ecurka-client

  namespace: sclouds

  labels:

    verison: "1.0.0"

    env: "test"

spec:

  selector:

    app: ecurka-client

    release: master

  ports:

      - name: http

        port: 7004

        targetPort: 7004

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: ecurka-client

  namespace: sclouds

  labels:

    verison: "1.0.0"

    env: "test"

spec:

  replicas: 2

  selector:

    matchLabels:

      app: ecurka-client

      release: master

  template:

    metadata:

      labels:

        app: ecurka-client

        release: master

    spec:

      containers:

        - name: ecurka-client

          image: dw/ecurka-client

          imagePullPolicy: IfNotPresent

          ports:

            - name: http

              containerPort: 7004

6、日志采集(SkyWalking)

logback设置GRPCLogClientAppender,设置日志级别:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appender name="msystem-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">

        <!-- 日志输出编码 -->

        <encoder>

            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

        </encoder>

    </appender>

    <root level="info">

        <appender-ref ref="msystem-log"/>

    </root>

</configuration>

完成上述配置,日志就会上传到skywalking

log.info("######################################\n" + "hello-world");


skywalking日志界面
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容