Skip to content
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

Common properties shared to all clients with multiple git config server #286

Open
andreasevers opened this issue Nov 27, 2015 · 17 comments
Open

Comments

@andreasevers
Copy link

Hey,

We have a quite complex setup of our configuration server. We have one repository per microservice to be able to manage access rights separately for each microservice.

We would like to _share configuration_ to all clients. We used to be able to do this using the native profile (as described here), but with changing to git as configuration storage, we seem to have lost that option.

I have tried using a combination of native and git, but that is not supported.
Next I tried to use the spring.cloud.config.server.git.uri property as a common repo, but that only acts as a fallback if spring.cloud.config.server.git.repos.* are not successfully matching configuration for a specific call to the config server.

My last option seemed using spring.cloud.config.server.git.overrides, which was working great, until I wanted to use variables such as this:

overrides:
          eureka.instance.statusPageUrlPath: ${server.contextPath}/info
          eureka.instance.healthCheckUrlPath: ${server.contextPath}/health
          info.configuration.uri: ${spring.cloud.config.uri}

Note: There seems to have been a lot of refactors in the org.springframework.cloud.config.server package, so I'm not sure the overrides property is still there.

The config server already fills in the variables before exposing them as json on the REST endpoints.
The result is that all clients receive the following:

  "propertySources": [
    {
      "name": "overrides",
      "source": {
        "info.configuration.uri": "${spring.cloud.config.uri}",
        "eureka.instance.statusPageUrlPath": "/configuration/info",
        "eureka.instance.healthCheckUrlPath": "/configuration/health"
      }
    }

So long story short, we are stuck. Either we continue to use the overrides configuration, and find a solution to passing the variables without being filled in by the config server itself, or we have to find another solution which allows us to share configuration to all clients while using a repository per microservice.

Cheers,
Andreas

@andreasevers
Copy link
Author

Could escaping the placeholders be an option?
It's not really explained in the docs afaik, but seems to be tested here.

When I try it like this:

overrides:
          eureka.instance.statusPageUrlPath: $\\{server.contextPath}/info
          eureka.instance.healthCheckUrlPath: $\\{server.contextPath}/health
          info.configuration.uri: $\\{spring.cloud.config.uri}

The resulting json exposed on the endpoint looks like this:

  "propertySources": [
    {
      "name": "overrides",
      "source": {
        "info.configuration.uri": "$\\\\{spring.cloud.config.uri}",
        "eureka.instance.statusPageUrlPath": "$\\\\{server.contextPath}/info",
        "eureka.instance.healthCheckUrlPath": "$\\\\{server.contextPath}/health"
      }
    }

Is this supposed to be like this?

@dsyer
Copy link
Contributor

dsyer commented Nov 27, 2015

I don't think you need to escape the "" in YAML. So $\{server.contextPath}/info would work.

Overrides aren't really a great solution if you want to change the properties locally in the apps. If it works for you for now that's great though.

@andreasevers
Copy link
Author

That did the trick! Thanks!

Overrides are indeed a solution we wouldn't use if there was another way to do this.
Could this be a separate feature?

@marcellodesales
Copy link
Contributor

@andreasevers I think I submitted a similar request at #383...

  • Do you feel this is the same?
  • Could we collaborate on this one?

This is a requirement we need to get done, since we have multiple teams reusing a global configuration that is shared across all teams... But each of them should have control on their own repos...

thanks
Marcello

@andreasevers
Copy link
Author

I'll look into it tomorrow @marcellodesales , stay tuned :)

@marcellodesales
Copy link
Contributor

@andreasevers 👍 Let me know of any development...

@marcellodesales
Copy link
Contributor

@andreasevers Any news❔

@andreasevers
Copy link
Author

andreasevers commented May 13, 2016

Sorry for the radio silence @marcellodesales , had a very busy week.

I love your structured explanation in #383 , and I agree it's overlapping with this issue.
Aside from your remarks I would like to add the "flexible overrides" as an extra requirement.

This would mean the eventual solution would have the following effect on any given application with a profile active:

  1. Global overrides
  2. Application-specific profile-specific properties
  3. Application-specific general properties
  4. Global profile-specific properties
  5. Global general properties

1 being top priority and 5 being lowest priority

I also believe global properties should come from a separate repository. Right now the overrides are defined in the config server itself, which means to change them we need to change the properties, build the config server, release it and deploy it (unless we externalize it but it would be a shame not to use git for this).
It could also a global repository which is always fetched and can be refreshed by POST-ing to the /refresh endpoint of the config-server. A bit like the fallback repository under spring.cloud.config.server.git.uri, but not as a fallback in case the application doesn't have its own repository, but as a global repository that acts as a base for all.

It would be great to have the possibility to define properties that can be overwritten by the application repositories, but also to define properties that will overwrite any property found in application repositories (like the current spring.cloud.config.server.git.overrides does but then inside a git repository). Global properties and global overrides could be in the same repository or in separate repositories. And ideally for these global properties the profiles should also be distinguishable.

@dsyer does that sound reasonable? If so, maybe me and @marcellodesales can work together on a PR.

@dsyer
Copy link
Contributor

dsyer commented May 13, 2016

Some of that makes sense. What I can't get straight in my head (and why I haven't done this myself) is that as soon as you have 2 repositories contributing to the same configuration Environment there's a chance they don't have the same labels. In fact I'd say it is necessary that individual teams can push new labels for their apps without having to change the global defaults. I think it means there is some tricky processing to do in the EnvironmentRepository, and I wouldn't want to do that in the existing repository implementation. The best way to implement it is probably to keep the existing repository and fold it into a composite, which takes the output as it is now and prepends stuff from a default git repository (of which there is only one).

@marcellodesales
Copy link
Contributor

@andreasevers Thanks for your notes as well... So far I'm in need of 2..5, but I can see teams requesting 1.

@dsyer I'm looking in the same angle: global repos would be missing labels, but we could default to master when that happens...

The intent is that this global repo can serve the global properties in all levels:

  • app: defaults to application.(properties|yml) as usual
  • profile: when defined
  • label: defaults to master in any request to profiles that does not exist

Since the core team communicates with the capability teams, we can always start with the defaults as usual. The resolution for requests of inexistent labels would resolve in loading the default `master. This could also be an option provided in the bootstrap.yml.

@Blacktiger
Copy link

I don't think you want the global repos to not use labels. As an example, say you use labels for environments DEV and PROD and your global configuration is for a common service like RabbitMQ. You'd still want the global config to load the DEV rabbit uri in the DEV environment and the PROD rabbit uri in the PROD environment.

Personally, I'd rather the "global" area of the config be assumed to only hold "application.yml" or "application.properties" files but I don't see why you could also allow application-specific configuration files there. I'd expect the config server to pull the configuration in this order in that case (bottom config wins):

  • global application.yml/properties
  • global applicationName.yml/properties
  • app-specific application.yml/properties
  • app-specific applicationName.yml/properties

I can see how this could easily be confusing though. I think it's important to spell out exactly what happens when you include a "global" config repository.

Since it would change the behavior in the presence of multiple repositories, I'd propose configuring this look like this:

spring:
  cloud:
    config:
      server:
        git:
          uri: ssh://git@<falback-git-uri>
          globalRepos:
            applicationA:
              pattern: applicationA/*
              uri: ssh://git@<global-git-uri>
            applicationB:
              pattern: applicationB/*
              uri: ssh://git@<global-git-uri>
          repos:
            applicationName:
              pattern: applicationA/*
              uri: ssh://git@<applicationA-git-uri>
            applicationName:
              pattern: applicationB/*
              uri: ssh://git@<applicationA-git-uri>

This specific example is a bit non-sensical since you wouldn't want shared configuration to be stored per-application. But you might want to be able to have multiple global configurations on a per-team basis or something like that.

@naraenraju
Copy link

Now I am also facing the same issue to keep global properties should keep in separate repository. Do we have any workaround or solution ?? @andreasevers

@dsyer
Copy link
Contributor

dsyer commented Dec 14, 2017

Did you try using a composite repository?

@naraenraju
Copy link

Yeah, I tried composite repository but its not working in my case, where both global properties and application properties should use different labels.

@dsyer
Copy link
Contributor

dsyer commented Dec 14, 2017

If you could create a sample app and post a link that would be super

@landonia
Copy link

landonia commented Jul 3, 2018

Does anybody know if there is any solution for this as I have a similar problem.

I have the scenario where a team manages the global-repository level configuration that includes host information, authentication keys etc and they will update this as these properties change. These are common to most services. So basically this repository will contain application.properties.

We then have a service-repository that has the specific service level properties. This contains the {app}.properties files.

Let's say that I have a service named service-a. When the service makes a request for its configuration I need it to return service-a.properties from the service-repository and application.properties from the global-repository. Is this at all possible? Or is the composite repository suggested by @dsyer the only possible solution?

@spencergibb
Copy link
Member

so far just the composite.

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

No branches or pull requests

8 participants