前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Eureka 在 K8S 的上高可用部署

Eureka 在 K8S 的上高可用部署

原创
作者头像
鲍远林
修改2021-06-07 10:11:26
6.2K1
修改2021-06-07 10:11:26
举报
文章被收录于专栏:TPlus

本文采用 StatefulSet 在 kubernetes 环境下部署 Eureka 高可用集群的方式,并在腾讯云 TKE 上成功部署。

Kubernetes 下 Eureka 的高可用部署,包含以下两点:

  • Eureka Server 集群部署
  • Pod 健康检查

Kubelets 通过调用以下三种类型的 Pod中的 Handler 进行健康检查:

  • ExecAction: 在容器中执行特定的命令,命令退出返回0表示成功
  • TCPSocketAction: 根据容器IP地址及特定的端口进行TCP检查,端口开放表示成功
  • HTTPGetAction: 根据容器IP、端口及访问路径发起一次HTTP请求,如果返回码在200到400之间表示成功

每种检查动作都可能有三种返回状态:

  • Success: 表示通过了健康检查
  • Failure: 表示没有通过健康检查
  • Unknown: 表示检查动作失败

liveness可以用来检查容器内应用的存活的情况来,如果检查失败会杀掉容器进程,是否重启容器则取决于Pod的重启策略。

1. Spring 工程

1.1 Maven 配置

完整的 maven pom 见附录 qcbm-registry maven pom。

1.2 健康检查 Controller

如下,新建个专门用于健康检查的 Controller。

代码语言:txt
复制
@RestController
@RequestMapping(path = "/")
public class HealthCheck {

    @GetMapping(path = "/healthcheck", produces = MediaType.TEXT_PLAIN_VALUE)
    public String healthz(){
        return "success";
    }
}

1.3 spring 配置

springboot 配置 yaml 如下:

代码语言:txt
复制
spring:
  application:
    name: EUREKA-SERVER

server:
  port: 8761

eureka:
  instance:
    prefer-ip-address: false
    hostname: ${EUREKA_INSTANCE_HOST_NAME}
  client:
    registerWithEureka: true
    fetchRegistry: true
    service-url:
      defaultZone: ${EUREKA_INSTANCE_LIST}
  server:
    enable-self-preservation: true
    response-cache-auto-expiration-in-seconds: 180
    response-cache-update-interval-ms: 10000
    eviction-interval-timer-in-ms: 10000

上面配置中的两个环境变量:EUREKA_INSTANCE_HOST_NAME 和 EUREKA_INSTANCE_LIST 可在下一节的 K8S 部署 yaml 中进行配置。

2. K8S 部署 yaml

2.1 Headless Service

在部署一个 Statefulset 之前,需要创建一个用于在有状态的 pod 之间提供网络标识的 headless Service。Eureka 的 headless Service 部署 yaml 如下:

代码语言:txt
复制
kind: Service
apiVersion: v1
metadata:
  name: eureka
  namespace: qcbm
spec:
  clusterIP: None
  ports:
    - name: http
      port: 8761
      protocol: TCP
      targetPort: 8761
  selector:
    app: eureka

上面指定了 cluster工P 为 None, 这就标记了它是一个 headless Service,它使得 pod 之间可以彼此发现。

2.2 StatefulSet

下面是 StatefulSet Eureka 的部署 yaml:

代码语言:txt
复制
apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: qcbm
  name: eureka
  labels:
    app: eureka
spec:
  serviceName: "eureka"
  replicas: 3
  selector:
    matchLabels:
      app: eureka
  template:
    metadata:
      labels:
        app: eureka
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: eureka
          image: ccr.ccs.tencentyun.com/qcbm/eureka:latest
          ports:
            - containerPort: 8761
          env:
            - name: EUREKA_INSTANCE_HOST_NAME
              value: ${HOSTNAME}.eureka
            - name: EUREKA_INSTANCE_LIST
              value: "http://eureka-0.eureka.qcbm.svc.cluster.local:8761/eureka/,http://eureka-1.eureka.qcbm.svc.cluster.local:8761/eureka/,http://eureka-2.eureka.qcbm.svc.cluster.local:8761/eureka/"
          livenessProbe:
          # 健康检查
          livenessProbe:
            httpGet:
              path: /healthcheck
              port: 8761
            initialDelaySeconds: 30
            timeoutSeconds: 10

几点说明:

  • EUREKA_INSTANCE_HOST_NAME

StatefulSet 创建的 pod name 是按 metadata.name-数字序列 命名的,这里的数字序列为从 0 到 replicas 指定的数字减1。而 EUREKA_INSTANCE_HOST_NAME 需要填写 pod 的短域名,因而这里先通过环境变量 HOSTNAME 和 headless service 的名称组成。

环境变量 HOSTNAME 是由 kubernetes 创建容器时添加的,可以使用 kubectl 命令进行查看,比如:

hostname.png
hostname.png
  • EUREKA_INSTANCE_LIST 有两种写法:
  • 方式1:采用 StatefulSet 创建的 pod 的短域名(该方式本人偶尔遇到过个别 pod 反复处于创建状态的异常情况)
代码语言:txt
复制
http://eureka-0.eureka:8761/eureka/,http://eureka-1.eureka:8761/eureka/,http://eureka-2.eureka:8761/eureka/
  • 方式2:采用 StatefulSet 创建的 pod 的长域名
代码语言:txt
复制
http://eureka-0.eureka.qcbm.svc.cluster.local:8761/eureka/,http://eureka-1.eureka.qcbm.svc.cluster.local:8761/eureka/,http://eureka-2.eureka.qcbm.svc.cluster.local:8761/eureka/

2.3 Eureka 界面的展示

上面介绍的部署完成后,是无法通过浏览器打开 Eureka 界面的,因为使用了 headless service。如要查看,还需要再建个 service 和 ingress。

代码语言:txt
复制
---
# 重新部署个 Service
kind: Service
apiVersion: v1
metadata:
  name: registry-lb
  namespace: qcbm
  annotations:
    # 这里采用腾讯云子网 ID 的方式,生产的 service 不能通过公网访问
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-8vfb3fo2
spec:
  type: LoadBalancer
  ports:
    - name: http
      port: 8761
      protocol: TCP
      targetPort: 8761
  selector:
    app: eureka
    
---
# 部署 qcbm-ingress
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: qcbm-ingress
  namespace: qcbm
  annotations:
    ingress.cloud.tencent.com/direct-access: "false"
    kubernetes.io/ingress.class: qcloud
    kubernetes.io/ingress.extensiveParameters: '{"AddressIPVersion":"IPV4"}'
    kubernetes.io/ingress.http-rules: '[{"host":"qcbm.com","path":"/","backend":{"serviceName":"registry-lb","servicePort":"8761"}}]'
spec:
  rules:
    - host: qcbm.com
      http:
        paths:
          - path: /
            backend:
              serviceName: registry-lb
              servicePort: 8761    

部署完成后,找到 qcbm-ingress 的公网 IP 就能看下图所示的 Eureka 界面了。

eureka-ok.png
eureka-ok.png

3. 关于 unavailable-replicas

配置错误时,会出现下图中的 unavailable-replicas:

unavailable-replicas.png
unavailable-replicas.png

如果出现上图情况,请检查以下几点:

  • eureka.instance.hostname 需要配置为运行 eureka 的 pod 短域名。
  • eureka.instance.prefer-ip-address 是否为 false。

容器部署方式下,POD 的 IP 是随机的,需要使用域名,因此要将该参数置为 false。

  • eureka.client.registerWithEureka 是否为 true。

集群部署下,一个 eureka 实例需要向集群中其它实例进行注册,以便达到实例之间的互相发现,因而需要将该参数设置为 true。

  • eureka.client.fetchRegistry 是否为 true。

打开此参数,是为了eureka 实例之间进行数据同步。比如服务A注册到了 eureka 实例 1 上,服务B注册到了 eureka 实例 2 上,打开此参数后,实例 1 和实例 2之间会同步数据,从而在每个实例上都有服务A和服务B的注册信息。

4. docker-maven-plugin 简介

spotify 出品的 docker-maven-plugin 将常用的 docker 命令集成到了 maven project 的生命周期中,大量的简化了繁琐的命令行操作。这里简单介绍下其使用,详细的使用说明,请参考:https://github.com/spotify/docker-maven-plugin

首先,本人的配置的如下:

代码语言:txt
复制
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>1.2.2</version>
    <configuration>
        <dockerDirectory>./</dockerDirectory>
        <imageName>ccr.ccs.tencentyun.com/qcbm/eureka</imageName>
        <imageTags>
            <imageTag>latest</imageTag>
        </imageTags>
    </configuration>
</plugin>
  • dockerDirectory 指定 Dockerfile 所在的目录,由于本人将其放置于工程目录下,因而使用 ./
  • imageName 镜像名称,可以是 docker registry 的完整名称。本人使用的是腾讯云 TCR 个人版仓库,且使用了命名空间 qcbm,因而填的是:ccr.ccs.tencentyun.com/qcbm/eureka
  • imageTag 顾名思义,就是镜像的 tag 了。

配置好以后,在终端使用下面命令,就会构建 docker 镜像,并推送到远程仓库中。

代码语言:txt
复制
mvn docker:build -DpushImage

附录:qcbm-registry 的 maven pom

代码语言:txt
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>demo.tcloud.triblewood.qcbm</groupId>
    <artifactId>qcbm-registry</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    
    <name>qcbm-registry</name>
    <description>QCBM service registry</description>

    <packaging>jar</packaging>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR11</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </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>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>demo.tcloud.triblewood.qcbm.registry.RegistryApplication</mainClass>
                    <finalName>${project.name}</finalName>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <configuration>
                    <dockerDirectory>./</dockerDirectory>
                    <imageName>ccr.ccs.tencentyun.com/qcbm/eureka</imageName>
                    <imageTags>
                        <imageTag>latest</imageTag>
                    </imageTags>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Spring 工程
    • 1.1 Maven 配置
      • 1.2 健康检查 Controller
        • 1.3 spring 配置
        • 2. K8S 部署 yaml
          • 2.1 Headless Service
            • 2.2 StatefulSet
              • 2.3 Eureka 界面的展示
              • 3. 关于 unavailable-replicas
              • 4. docker-maven-plugin 简介
              • 附录:qcbm-registry 的 maven pom
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档