【问题标题】:Eureka and Kubernetes尤里卡和 Kubernetes
【发布时间】:2017-03-26 19:58:16
【问题描述】:

我正在整理一个概念证明,以帮助识别同时使用 Spring Boot/Netflix OSS 和 Kubernetes 的问题。这也是为了证明Prometheus、Graphana等相关技术。

我有一个 Eureka 服务设置,它在我的 Kubernetes 集群中启动时没有问题。这被命名为发现,并在使用

添加到 K8 时被命名为“discovery-1551420162-iyz2c”

对于我的配置服务器,我正在尝试使用基于逻辑 URL 的 Eureka,所以在我的 bootstrap.yml 中有

server:
  port: 8889

eureka:
  instance:
    hostname: configserver
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://discovery:8761/eureka/

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xyz/microservice-config

我开始使用

kubectl run configserver --image=xyz/config-microservice --replicas=1 --port=8889

此服务最终运行命名为 configserver-3481062421-tmv4d。然后我在配置服务器日志中看到异常,因为它试图找到 eureka 实例但无法找到。

我在本地使用带有链接的 docker-compose 对此进行了相同的设置,它可以毫无问题地启动各种容器。

discovery:
  image: xyz/discovery-microservice
  ports:
   - "8761:8761"
configserver:
  image: xyz/config-microservice
  ports:
   - "8888:8888"
  links:
   - discovery

如何设置像 eureka.client.serviceUri 这样的东西,以便我的微服务可以在不知道 K8 集群中的固定 IP 地址的情况下定位它们的对等点?

【问题讨论】:

  • Eureka 使用服务名定位实例。如果您检查 eureka 服务器,您将列出在 eureka 服务器上注册的服务。当服务 A 尝试与服务 B 通信时,服务 A 将使用服务 B 名称从 eureka 服务器获取与服务 B 相关的所有信息。所以eureka设置中不会有固定的IP地址。
  • 我不太明白您要做什么,但是为什么当您在 kubernates 上部署时需要 eurika,kubernates 不能完成 eurika 的工作?
  • @Adelin 没错。 Kubernetes 已经有指向 pod 的服务。我找不到任何解释服务发现和 Kubernetes 的资源。

标签: spring-boot kubernetes microservices netflix-eureka spring-cloud-netflix


【解决方案1】:

我怎样才能设置像 eureka.client.serviceUri 这样的东西?

您必须在 eureka pod/deployments 之上拥有一个 Kubernetes service,然后它将为您提供可参考的 IP 地址和端口号。然后使用该可引用地址来查找 Eureka 服务,而不是“8761”。

解决有关 Eureka 的 HA 配置的进一步问题

每个 k8s 服务不应拥有多个 Eureka 的 Pod/副本(请记住,Pod 是短暂的,您需要一个可引用的 IP 地址/域名用于 eureka 服务注册)。要实现高可用性 (HA),请启动更多 k8s 服务,每个服务都有一个 pod。

  • Eureka 服务 1 --> 单个 pod
  • Eureka Service 2 --> 另一个单独的 pod
  • ..
  • ..
  • Eureka Service n --> 另一个单独的 pod

所以,现在您的每个 Eureka 都有可参考的 IP/域名(k8s 服务的 IP)。现在它可以相互注册了。

感觉有点矫枉过正? 如果您的所有服务都在同一个 kubernetes 命名空间中,您可以通过 k8s 服务 + KubeDNS 附加组件实现 eureka 提供的所有内容(嗯,几乎所有内容,客户端负载均衡除外)。阅读Christian Posta 的article

编辑

正如Stefan Ocke 指出的那样,您可以使用StatefulSets,而不是每个服务都有一个pod。

与 Deployment 一样,StatefulSet 管理基于 相同的容器规格。与 Deployment 不同,StatefulSet 维护 每个 Pod 的粘性标识。这些 pod 是从 相同的规范,但不可互换:每个都有一个持久的 它在任何重新安排期间维护的标识符。

【讨论】:

    【解决方案2】:

    关于Eureka的HA配置在Kubernetes: 您可以(同时)为此使用StatefulSet,而不是为每个实例创建服务。 StatefulSet 为您创建的每个实例保证稳定的网络身份。 例如,部署可能类似于以下 yaml(StatefulSet + headless Service)。 这里有两个 Eureka 实例,根据 StatefulSets 的DNS naming rules(假设命名空间是“默认”):

    • eureka-0.eureka.default.svc.cluster.local 和

    • eureka-1.eureka.default.svc.cluster.local

    只要您的 pod 在同一个命名空间中,它们也可以通过以下方式访问 Eureka:

    • eureka-0.eureka
    • eureka-1.eureka

    注意:示例中使用的 docker 镜像来自https://github.com/stefanocke/eureka。您可能想选择或构建自己的。

    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: eureka
      labels:
        app: eureka
    spec:
      ports:
      - port: 8761
        name: eureka
      clusterIP: None
      selector:
        app: eureka
    ---    
    apiVersion: apps/v1beta2
    kind: StatefulSet
    metadata:
      name: eureka
    spec:
      serviceName: "eureka"
      replicas: 2 
      selector:
        matchLabels:
          app: eureka
      template:
        metadata:
          labels:
            app: eureka
        spec:
          containers:
          - name: eureka
            image: stoc/eureka
            ports:
            - containerPort: 8761
            env:
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
              # Due to camelcase issues with "defaultZone" and "preferIpAddress", _JAVA_OPTIONS is used here
            - name: _JAVA_OPTIONS
              value: -Deureka.instance.preferIpAddress=false -Deureka.client.serviceUrl.defaultZone=http://eureka-0.eureka:8761/eureka/,http://eureka-1.eureka:8761/eureka/
            - name: EUREKA_CLIENT_REGISTERWITHEUREKA
              value: "true"
            - name: EUREKA_CLIENT_FETCHREGISTRY
              value: "true"
            # The hostnames must match with the the eureka serviceUrls, otherwise the replicas are reported as unavailable in the eureka dashboard      
            - name: EUREKA_INSTANCE_HOSTNAME
              value: ${MY_POD_NAME}.eureka
      # No need to start the pods in order. We just need the stable network identity
    podManagementPolicy: "Parallel"
    

    【讨论】:

    • 这行得通吗? -Deureka.client.serviceUrl.defaultZone=http://eureka-0.eureka.${CURRENT_NAME_SPACE}.svc.cluster.local:8761/eureka/,http://eureka-1.eureka.${CURRENT_NAME_SPACE}.svc.cluster.local:8761/eureka/ 是否有任何默认变量可用于获取当前命名空间?
    • 好问题。我认为最好的方法是省略命名空间:-Deureka.client.serviceUrl.defaultZone=http://eureka-0.eureka:8761/eureka/,http://eureka-1.eureka:8761/eureka/。但是,我记得这对我不起作用。但我并没有真正寻找原因。也许你可以试一试。
    • @GovindKailas ,我更新并测试了该示例。我现在使用主机名的简短版本。诀窍不仅是更改 defaultZone,还相应地更改 EUREKA_INSTANCE_HOSTNAME 以匹配默认区域中的值。否则,Eureka 会报告“不可用的副本”。请注意,我还更改了 docker 镜像,因为我之前使用的镜像已经不存在并且已经过时了。
    • 这是一个很好的改进,也很整洁。我刚试过这个,我能想到的唯一问题是人们可能会对 Eureka 的服务 URL 感到困惑。感谢您的帮助。
    • 感谢您提供此解决方案。我有一个问题:如何公开这个 statefulset,以便检查这些 pod 是否正确注册?
    【解决方案3】:

    @Stefan Ocke 我正在尝试相同的设置,但使用我自己的尤里卡服务器图像。但我不断收到此错误

    Request execution failed with message: java.net.ConnectException: Connection refused (Connection refused)
    2019-09-27 06:27:03.363 ERROR 1 --- [           main] c.n.d.s.t.d.RedirectingEurekaHttpClient  : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://eureka-1.eureka:8761/eureka/}
    

    以下是配置:

    尤里卡弹簧属性:

    server.port=${EUREKA_PORT}
    spring.security.user.name=${EUREKA_USERNAME}
    spring.security.user.password=${EUREKA_PASSWORD}
    eureka.client.register-with-eureka=true
    eureka.client.fetch-registry=true
    eureka.instance.prefer-ip-address=false
    eureka.server.wait-time-in-ms-when-sync-empty=0
    eureka.server.eviction-interval-timer-in-ms=15000
    eureka.instance.leaseRenewalIntervalInSeconds=30
    eureka.instance.leaseExpirationDurationInSeconds=30
    eureka.instance.hostname=${EUREKA_INSTANCE_HOSTNAME}
    eureka.client.serviceUrl.defaultZone=http://eureka-0.eureka:8761/eureka/,http://eureka-1.eureka:8761/eureka/
    

    StatefulSet 配置:

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: eureka
    spec:
      serviceName: "eureka"
      podManagementPolicy: "Parallel" 
      replicas: 2
      selector:
        matchLabels:
          app: eureka
      template:
        metadata:
          labels:
            app: eureka    
        spec:
          containers:
          - name: eureka
            image: "my-image"
            command: ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar","/app/eureka-service.jar"]
            ports:
            - containerPort: 8761
            env: 
            - name: EUREKA_PORT
              value: "8761"
            - name: EUREKA_USERNAME
              value: "theusername"
            - name: EUREKA_PASSWORD
              value: "thepassword"
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: EUREKA_INSTANCE_HOSTNAME
              value: ${MY_POD_NAME}.eureka   
    

    服务配置:

    apiVersion: v1
    kind: Service
    metadata:
      name: eureka
      labels:
        app: eureka
    spec:
      clusterIP: None
      selector:
        app: eureka
      ports:
      - port: 8761
        targetPort: 8761
    

    入口控制器:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-service
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      rules:
        - http:
            paths:
              - path: /
                backend:
                  serviceName: eureka
                  servicePort: 8761
    

    【讨论】:

    • 我自己想通了,我在 eureka 服务器上使用身份验证,在注册时忘记传递凭据。
    【解决方案4】:

    您必须安装一个 kubernetes kube-dns 服务器以使用其 IP 解析名称,然后将您的 eureka pod 作为服务公开。 (参见 kubernetes docs)了解更多关于如何创建 dns 和服务的信息。 @random_dude,如果我曾经创建 2 或 3 个 eureka 副本会怎样?事实证明,当我挂载一个微服务“X”时,我将在所有 eureka 副本中注册,但是当它关​​闭时,只有一个副本得到更新!其他人仍然认为微服务实例正在运行

    【讨论】:

    • 我知道我回答这个问题有点晚了,我错过了通知每个 k8s 服务不应该有多个 Eureka 的 Pod/副本(请记住,Pod 是短暂的,你需要一个可参考的eureka 服务注册的 IP 地址/域名)。为了实现高可用性(HA),启动更多的 k8s 服务,每个服务一个 pod。
    【解决方案5】:

    我确实遇到了这个问题,并通过为 pod 添加环境变量来解决它。 This 有答案。我的 pod 的示例环境变量如下所示,

    【讨论】:

    • 谢谢,下次把 env 添加为代码(这样可以复制/粘贴)
    猜你喜欢
    • 2016-08-02
    • 2017-04-15
    • 1970-01-01
    • 2018-10-28
    • 2018-04-15
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    相关资源
    最近更新 更多