Эврика и Кубернетес

Я собираю доказательство концепции, чтобы помочь идентифицировать gotchas, используя Spring Boot/Netflix OSS и Kubernetes вместе. Это также должно выработать связанные технологии, такие как Prometheus и Graphana.

У меня есть сервис Eureka, который начинается без каких-либо проблем в моем кластере Kubernetes. Это называется обнаружением и ему было присвоено имя "discovery-1551420162-iyz2c" при добавлении в K8 с использованием

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

Для моего сервера конфигурации я пытаюсь использовать Eureka на основе логического URL-адреса, поэтому в моем 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, чтобы мои микросервисы могли находить своих сверстников, не зная фиксированных IP-адресов в кластере K8?

Ответ 1

  Как я могу настроить что-то вроде eureka.client.serviceUri?

Вам необходимо иметь сервис Kubernetes поверх модулей/развертываний eureka, который затем предоставит вам референтный IP-адрес и номер порта. А затем используйте этот адрес для поиска службы Eureka вместо "8761".

Для решения дальнейшего вопроса о конфигурации HA Eureka

У вас не должно быть более одного pod/реплики Eureka на службу k8s (помните, что pods эфемерны, вам нужен референтный IP-адрес/доменное имя для реестра службы eureka). Чтобы обеспечить высокую доступность (HA), увеличьте количество сервисов K8S по одному модулю в каждом.

  • Эврика сервис 1 → один контейнер
  • Eureka Service 2 → еще один контейнер
  • ..
  • ..
  • Eureka Service n → еще один модуль

Итак, теперь у вас есть референсный IP/доменное имя (IP-адрес службы k8s) для каждой вашей Eureka... теперь она может регистрировать друг друга.

Чувствуете себя излишним? Если все ваши сервисы находятся в одном и том же пространстве имен kubernetes, вы можете достичь всего (ну, почти все, кроме балансировки нагрузки на стороне клиента), которое eureka предлагает через услугу k8s + дополнение KubeDNS. Прочитайте эту статью Кристиана Поста

Изменить

Вместо Служб с одним модулем вы можете использовать StatefulSets, как указал Стефан Оке.

Подобно развертыванию, StatefulSet управляет модулями, основанными на идентичные спецификации контейнера В отличие от развертывания, StatefulSet поддерживает липкая личность для каждого из их стручков. Эти стручки созданы из те же характеристики, но не являются взаимозаменяемыми: каждый имеет постоянный идентификатор, который он поддерживает при любом перепланировании.

Ответ 2

Что касается конфигурации HA Eureka в Kubernetes: вы можете (тем временем) использовать StatefulSet для этого вместо создания службы для каждого экземпляра. StatefulSet гарантирует стабильную идентификацию сети для каждого создаваемого вами экземпляра. Например, развертывание может выглядеть как следующий yaml (StatefulSet + безглавная служба). Здесь есть два экземпляра Eureka, в соответствии с правилами DNS-имен для StatefulSets (при условии, что пространство имен "по умолчанию"):

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

  • Эврика-1.eureka.default.svc.cluster.local

Пока ваши стручки находятся в одном и том же пространстве имен, они могут достичь Eureka также как:

  • Эврика-0.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"

Ответ 3

Вам необходимо установить kub-dns-сервер kubernetes для разрешения имен с их IP-адресами, а затем выставить свои eureka-модули в качестве службы. (см. kubernetes docs) для получения дополнительной информации о том, как создавать dns и сервисы. @random_dude, что будет, если я использовал для создания 2 или 3 реплики эврики? оказалось, что когда я монтирую микросервис "X", я буду зарегистрирован во всех репликах eureka, но когда он опустится, только одна реплика получит обновление! другие все еще считают экземпляр микросервиса запущенным

Ответ 4

@Stefan Ок, я пытаюсь сделать то же самое, но с моим собственным изображением сервера eureka. но я продолжаю получать эту ошибку

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

Вот конфигурации:

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   

Настройка службы:

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