Эврика и Кубернетес
Я собираю доказательство концепции, чтобы помочь идентифицировать 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
- Эврика-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