Skip to content

Add Eureka Service Discovery #3369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Aug 26, 2020
Merged

Add Eureka Service Discovery #3369

merged 21 commits into from
Aug 26, 2020

Conversation

kangwoo
Copy link
Contributor

@kangwoo kangwoo commented Oct 30, 2017

Added Eureka Service Discovery.
The Eureka client used a 'https://github.com/kangwoo/go-eureka-client' library

@mdlayher
Copy link
Contributor

Relevant issue: #1506.

Doesn't look like it was officially accepted or rejected. Ping @juliusv?

@juliusv
Copy link
Member

juliusv commented Oct 30, 2017

Thanks! Unless something has changed, we still have a moratorium (instated a couple of months ago) for accepting any new SD mechanisms into Prometheus itself at the moment. The reason was that we have too many mechanisms already that are not well-tested, not well-understood, and have too few maintainers for them. We started efforts to introduce integration testing and more documentation (parts of the docs have already happened at least). But I think we still are not accepting new mechanisms into Prometheus proper at this moment. Instead, we would recommend running this outside via the File SD for now and consider it for integration into Prometheus later.

@brian-brazil @cstyan @gouthamve @fabxc Am I correct that this is still the current state?

@brian-brazil
Copy link
Contributor

Yes, that's the current state.

From a very brief look, I believe this PR is also hardcoding organisation-specific assumptions.

@td83
Copy link

td83 commented Nov 9, 2017

@juliusv - running for example Eureka via SD file is usually not possible in cloud environment where all services are stateless and you cannot mount a file system and share files between Prometheus and bridge application.

@godoylucase
Copy link

godoylucase commented Feb 22, 2018

is there any chance to have anyone to take care of this? Would like to have it since we are using netflix oss for our microservices stack

@krasi-georgiev
Copy link
Contributor

there is also a discussion for http vs sd to it would be useful get some input regarding this use-case
https://groups.google.com/forum/#!topic/prometheus-developers/JcE5nSbCe4k

@ghost
Copy link

ghost commented Mar 12, 2018

Until this is merged and released, there is another option to integrate Prometheus with Eureka. I have written an adapter that you can deploy with your Eureka instance. This adapter provides several HTTP endpoints that return information of the registered services and are compatible with the Prometheus' Consul discovery client (consul_sd_config). I have tested it for a couple of month now and it works great. I have put it up on Github: https://github.com/twinformatics/eureka-consul-adapter Feel free to give it a try (and feedback).

@krasi-georgiev
Copy link
Contributor

due to lack of man power to review and maintain new SD we are on permanent hold for adding new SD.

As a replacement we have now added an example how to implement a custom SD adapter that converts any SD to json file that can be used by the file SD
https://github.com/prometheus/prometheus/tree/master/documentation/examples/custom-sd

@roidelapluie
Copy link
Member

@kangwoo are you still interested in this?

I would like to investigate and see how we can integrate this work in Prometheus.

@kangwoo
Copy link
Contributor Author

kangwoo commented Jul 28, 2020

@kangwoo are you still interested in this?

I would like to investigate and see how we can integrate this work in Prometheus.

yes. How can I help you?

@cstyan
Copy link
Member

cstyan commented Jul 28, 2020

@kangwoo rebasing off master, dealing with any merge conflicts, and ensuring that all tests still pass would be a good place to start :)

@roidelapluie
Copy link
Member

roidelapluie commented Jul 28, 2020

Maybe also see if we can move back to your forked client to upstream.

@kangwoo kangwoo changed the title Add Eureka Service Discovery [WIP] Add Eureka Service Discovery Jul 29, 2020
@kangwoo
Copy link
Contributor Author

kangwoo commented Jul 29, 2020

Ok. I'll start working.

@kangwoo kangwoo force-pushed the master branch 3 times, most recently from 0fe0dcb to a2ad803 Compare July 31, 2020 10:35
Copy link
Member

@cstyan cstyan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating this. Unfortunately I don't know enough about Eureka to do a full review.

@@ -0,0 +1,112 @@
// Copyright 2016 The Prometheus Authors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, the copyright year for files you're adding should be 2020

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it.

defer ts.Close()

apps, err := fetchApps(context.TODO(), []string{ts.URL}, &http.Client{})
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use testutil.Ok(t, err) to fail if an error was returned

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change it to testutil.

}
)
tgs, err := testUpdateServices(client)
if err != errTesting {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use testutil package in this file

[ refresh_interval: <duration> | default = 30s ]
```

By default every app listed in Marathon will be scraped by Prometheus. If not all
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

marathon -> eureka?

@roidelapluie
Copy link
Member

Could you squash all the commits into one, so we start fresh?

Copy link
Member

@roidelapluie roidelapluie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added some initial comments.

appInstanceStatusLabel = metaLabelPrefix + "app_instance_status"
appInstanceIDLabel = metaLabelPrefix + "app_instance_id"
appInstanceMetadataPrefix = metaLabelPrefix + "app_instance_metadata_"
appInstanceMetadataPresentPrefix = metaLabelPrefix + "app_instance_metadatapresent_"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can metadata be present and empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I need it. I will delete it.

const appListPath string = "/apps"

func fetchApps(ctx context.Context, servers []string, client *http.Client) (*Applications, error) {
url := randomAppsURL(servers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems a very strange pattern. I would just limit that to ONE server and let the user put load balancing in front if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but generally Eureka customers implement and use client load balancing devices. I'll think about a better way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really how the java client works?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really how the java client works?

If the request fails, change the server address and try again.

https://github.com/Netflix/eureka/blob/master/eureka-client/src/main/java/com/netflix/discovery/shared/transport/decorator/RetryableEurekaHttpClient.java#L98

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that the users who would want that in prometheus could just have multiple eureka_sd_configs in the same job, with one server each,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it to limit it to ONE server.

resp.Body.Close()
}()

if (resp.StatusCode < 200) || (resp.StatusCode >= 300) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resp.StatusCode / 100 == 2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

}()

if (resp.StatusCode < 200) || (resp.StatusCode >= 300) {
return nil, errors.Errorf("non 2xx status '%v' response during eureka service discovery", resp.StatusCode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be more specific that %v, e.g. %d.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

// Remove services which did disappear.
for source := range d.lastRefresh {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the application restarts, it may get out of Discovery.
To avoid immediate removal from the monitoring target if removed from the Discovery.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a correct behavior from the Prometheus perspective. Can you remove this, + lastRefresh?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I will remove it

Class string `xml:"class,attr" json:"@class"`
}

func (s *MetaData) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we need to marshal to xml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a marshal. I will delete it

return nil
}

func (s *MetaData) MarshalJSON() ([]byte, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need XML or json, not both,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will delete json.

@kangwoo
Copy link
Contributor Author

kangwoo commented Jul 31, 2020

Add Eureka Service Discovery

A example scrape configuration for running Prometheus on a Eureka

scrape_configs:

  # Discover Eureka services to scrape.
  - job_name: 'eureka'

    # Scrape Eureka itself to discover new services every minute.
    eureka_sd_configs:
      - servers:
          - http://localhost:8761/eureka
        refresh_interval: 60s

Metdata

You can use Eureka's application instance metadata.

If you are using SpringBoot, you can add metadata using eureka.instance.metadataMap like this:

  • application.yaml (spring-boot)
eureka:
instance:
  metadataMap:
    "prometheus.scrape": "true"
    "prometheus.path": "/actuator/prometheus"
    "prometheus.port": "8080"

Example relabel to scrape only application that have "prometheus.scrape = true" metadata.

  • prometheus.xml
- source_labels: [__meta_eureka_app_instance_metadata_prometheus_scrape]
  action: keep
  regex: true
  • application.yaml (spring-boot)
eureka:
instance:
  metadataMap:
    "prometheus.scrape": "true"

Example relabel to customize metric path based on application "prometheus.path = " annotation.

  • prometheus.yaml
- source_labels: [__meta_eureka_app_instance_metadata_prometheus_path]
  action: replace
  target_label: __metrics_path__
  regex: (.+)
  • application.yaml (spring-boot)
eureka:
instance:
  metadataMap:
    "prometheus.path": "/actuator/prometheus"

Example relabel to scrape only single, desired port for the application based on application "prometheus.port = " metadata.

  • prometheus.xml
- source_labels: [__address__, __meta_eureka_app_instance_metadata_prometheus_port]
  action: replace
  regex: ([^:]+)(?::\d+)?;(\d+)
  replacement: $1:$2
  target_label: __address__
  • application.yaml (spring-boot)
eureka:
instance:
  metadataMap:
    "prometheus.port": "8080"

@kangwoo kangwoo changed the title [WIP] Add Eureka Service Discovery Add Eureka Service Discovery Jul 31, 2020
@kangwoo kangwoo closed this Jul 31, 2020
@kangwoo kangwoo deleted the master branch July 31, 2020 22:06
@kangwoo kangwoo restored the master branch July 31, 2020 22:06
@roidelapluie
Copy link
Member

Why did you close this?

kangwoo added 14 commits August 22, 2020 15:27
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
Signed-off-by: kangwoo <kangwoo@gmail.com>
appInstanceVipAddressLabel: lv(t.VipAddress),
appInstanceSecureVipAddressLabel: lv(t.SecureVipAddress),
appInstanceStatusLabel: lv(t.Status),
appInstancePortLabel: lv(strconv.Itoa(t.Port.Port)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Port and SecurePort are pointers, what happens if they're nil?

Copy link
Contributor Author

@kangwoo kangwoo Aug 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add a nil check.

Signed-off-by: kangwoo <kangwoo@gmail.com>
@@ -162,21 +162,27 @@ func targetsForApp(app *Application) []model.LabelSet {
model.AddressLabel: model.LabelValue(targetAddress),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetAddress := net.JoinHostPort(t.HostName, strconv.Itoa(t.Port.Port))

This should also check for nil.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I will check nil.

Signed-off-by: kangwoo <kangwoo@gmail.com>
@@ -157,10 +157,14 @@ func targetsForApp(app *Application) []model.LabelSet {

// Gather info about the app's 'instances'. Each instance is considered a task.
for _, t := range app.Instances {
targetAddress := net.JoinHostPort(t.HostName, strconv.Itoa(t.Port.Port))
var targetAddress string
if t.Port != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we then use 80 as port? or not add the port to the address? @brian-brazil

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There has to be an address label. This hasn't come up before, I'd suggest just hardcoding to 80 for now.

Signed-off-by: kangwoo <kangwoo@gmail.com>
```yaml
# The URL to connect to the Eureka server.
server: <string>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you miss the http client documentation (token file etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add http client options to documentation

Signed-off-by: kangwoo <kangwoo@gmail.com>
@brian-brazil
Copy link
Contributor

👍

@roidelapluie roidelapluie merged commit 7c0d5ae into prometheus:master Aug 26, 2020
@roidelapluie
Copy link
Member

Thanks @kangwoo !!

@kangwoo
Copy link
Contributor Author

kangwoo commented Aug 26, 2020

Thank you everyone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants