Eureka and Kubernetes
Asked Answered
G

6

39

I am putting together a proof of concept to help identify gotchas using Spring Boot/Netflix OSS and Kubernetes together. This is also to prove out related technologies such as Prometheus and Grafana.

I have a Eureka service setup which is starting with no trouble within my Kubernetes cluster. This is named discovery and has been given the name "discovery-1551420162-iyz2c" when added to K8 using

kubectl run discovery --image=xyz/discovery-microservice --replicas=1 --port=8761

For my config server, I am trying to use Eureka based on a logical URL so in my bootstrap.yml I have

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

and I am starting this using

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

This service ends up running named as configserver-3481062421-tmv4d. I then see exceptions in the config server logs as it tries to locate the eureka instance and cannot.

I have the same setup for this using docker-compose locally with links and it starts the various containers with no trouble.

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

How can I setup something like eureka.client.serviceUri so my microservices can locate their peers without knowing fixed IP addresses within the K8 cluster?

Gerlac answered 12/11, 2016 at 20:40 Comment(3)
Eureka use service name to locate instance. If you check the eureka server you'll list of services registered with eureka server. When service A try to communicate with service B , service A will fetch all the information related to service B from eureka server using service B name. So there will be no fixed IP address in the eureka setup.Patsy
I didn't quite understand what you are trying to do, but why do you need eurika when you deploy on kubernates doesn't kubernates do the job of eurika ?Lachesis
@Lachesis yep exactly. Kubernetes already has services which point to pods. I couldn't find any resources explaining service discovery and Kubernetes together.Swayne
B
29

How can I setup something like eureka.client.serviceUri?

You have to have a Kubernetes service on top of the eureka pods/deployments which then will provide you a referable IP address and port number. And then use that referable address to look up the Eureka service, instead of "8761".

To address further question about HA configuration of Eureka

You shouldn't have more than one pod/replica of Eureka per k8s service (remember, pods are ephemeral, you need a referable IP address/domain name for eureka service registry). To achieve high availability (HA), spin up more k8s services with one pod in each.

  • Eureka service 1 --> a single pod
  • Eureka Service 2 --> another single pod
  • ..
  • ..
  • Eureka Service n --> another single pod

So, now you have referable IP/Domain name (IP of the k8s service) for each of your Eureka.. now it can register each other.

Feeling like it's an overkill? If all your services are in same kubernetes namespace you can achieve everything (well, almost everything, except client side load balancing) that eureka offers though k8s service + KubeDNS add-On. Read this article by Christian Posta

Edit

Instead of Services with one pod each, you can make use of StatefulSets as Stefan Ocke pointed out.

Like a Deployment, a StatefulSet manages Pods that are based on an identical container spec. Unlike a Deployment, a StatefulSet maintains a sticky identity for each of their Pods. These pods are created from the same spec, but are not interchangeable: each has a persistent identifier that it maintains across any rescheduling.

Belie answered 12/11, 2016 at 22:30 Comment(0)
M
19

Regarding HA configuration of Eureka in Kubernetes: You can (meanwhile) use a StatefulSet for this instead of creating a service for each instance. The StatefulSet guarantees stable network identity for each instance you create. For example, the deployment could look like the following yaml (StatefulSet + headless Service). There are two Eureka instances here, according to the DNS naming rules for StatefulSets (assuming namespace is "default"):

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

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

As long as your pods are in the same namespace, they can reach Eureka also as:

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

Note: The docker image used in the example is from https://github.com/stefanocke/eureka. You might want to chose or build your own one.

---
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"
Melinamelinda answered 25/11, 2017 at 20:52 Comment(9)
Would this work? -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/ Is there any default variables available for getting the current namespace?Ashtray
Good question. I think the best way would be to omit the namespace: -Deureka.client.serviceUrl.defaultZone=http://eureka-0.eureka:8761/eureka/,http://eureka-1.eureka:8761/eureka/. However, I can remember that did not work for me. But I did not really search for the reason. Maybe you can give it a try.Melinamelinda
@GovindKailas , I updated and tested the example. I now uses the short versions of the hostnames. The trick is not only to change defaultZone, but also change EUREKA_INSTANCE_HOSTNAME accordingly to match the values in default zone. Otherwise, Eureka will report "unavailable replicas". Note that I also changed the docker image, since the one I used before does not exist anymore and was quite outdated, too.Melinamelinda
This is a very good improvement and neat too. I just tried this and the only problem I could think is people may get confused about the service URL of Eureka. Thanks for the help.Ashtray
Thank you for this solution. I have a question: How can I expose this statefulset so that I can check whether those pods a registered correctly?Autobahn
You can create a second service with clusterIp that also points to your eureka pods. This service can then be exposed by loadbalancer, ingress or other means.Melinamelinda
@StefanOcke can you help me out with my current setup mentioned below ?Phlebitis
How to add an entry to JAVA_OPTIONS and -Deureka.client.serviceUrl.defaultZone above whenever HPA adds one more eureka instance? Will it always have to be manual? Is it possible to add an entry to the default zone list automatically with HPAKarlotta
@SRK, I don't know how to do this. But if you even have to autoscale your service discovery, you have likely reached the point to finally get rid of Eureka and use Kubernetes services and DNS instead. I have always considered Eureka in Kubernetes as some valid approach during migration of Spring Cloud applications but not as a permanent solution.Melinamelinda
P
3

@Stefan Ocke i'm trying to the same setup the same, but with my own image of eureka server. but i keep getting this error

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/}

Here are configurations:

Eureka Spring Properties:

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 Config:

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   

Service Config:

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

Ingress Controller:

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
Phlebitis answered 27/9, 2019 at 6:48 Comment(1)
figured it out myself, I was using authentication on the eureka server and forgot to pass the credentials when registering with it.Phlebitis
C
2

You have to install a kubernetes kube-dns server to resolve names with their IPs, and then expose your eureka pods as a service. (see kubernetes docs) for more infos to how to create dns and services. @random_dude, what will be the case if i used to create 2 or 3 replicas of eureka? it turned out that when i mount a micro-service 'X' i will be registred in all eureka replicas, but when it becomes down, only one replicas gets the update ! the others still consider the micro-service instance as running

Crescen answered 1/12, 2016 at 7:30 Comment(1)
I know I am a bit late to answer this, I missed the notification You shouldn't have more than one pod/replica of Eureka per k8s service (remember, pods are ephemeral, you need a referable IP address/domain name for eureka service registry).. To achieve high availability (HA), spin up more k8s services with one pod in each.Belie
H
1

I got exactly this problem and it got resoled by adding an environment variable for pod. This has the answer. Sample env variable for my pod is shown below,

enter image description here

Homiletic answered 8/3, 2021 at 18:15 Comment(1)
Thanks, next time add the env as a code (so it can be copied/pasted)Rodgers
J
0

I'm wondering where you put that config, is that on service-registry which is on the eureka, or in the client-side (where we want to connect to eureka)?

my current case is, that all configuration is placed on a repo, the eureka config as well. which makes the config static.

Jerry answered 26/5, 2022 at 10:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.