I have a very simple sidecar application - just the required annotations and the main method, like this:
#SpringBootApplication
#EnableSidecar
public class SidecarApplication {
...
}
I also have a service sitting behind it, on the same host, which has a GET /joke endpoint.
The sidecar configuration:
server.port=5678
spring.application.name=joker
sidecar.port=8083
sidecar.home-page-uri=http://localhost:8083/
sidecar.health-uri=http://localhost:8083/health.json
management.security.enabled=false
logging.level.root=DEBUG
However, when calling GET http://localhost:5678/joke, I get 404. If I call GET http://localhost:8083/joke, I do get a valid response.
Now, If I add this to the sidecar configuration:
zuul.routes.joker.url=http://localhost:8083/
then calling GET http://localhost:5678/joker/joke works as expected.
Am I missing something, or is this expected behavior? I would have expected no additional configuration to be necessary for the sidecar to route all incoming requests to the wrapped service, and I'd want the url to be used for accessing the service behind the sidecar not to need to contain a service name.
I think you need more notations like these in application.properties:
spring.application.name = joke
server.port = 5678
eureka.client.serviceUrl.defaultZone = http: // localhost: 9000 / eureka
eureka.client.register-with-eureka = true
eureka.client.fetch-registry = true
sidecar.port = 8083
sidecar.health-uri = http: // localhost: 8083 / health
management.security.enabled = false
/ * example * /
zuul.routes.wstore.path = / wstore / **
zuul.routes.wstore.url = http: // localhost: 8083
In the application should have these 3 notations
#SpringBootApplication
#EnableSidecar
#EnableDiscoveryClient
public class SidecarApplication {...}
note this configuration was useful for spring-boot 1.5.6.RELEASE
If you are using Eureka yes, the routing is transparent. The sidecar app registers itself with Eureka BUT sets homePageUrl value of Eureka InstanceInfo object to the actual host and port of your microservice. And this is the value your clients will use to make calls to your microservice.
Related
I have Spring gateway: localhost:7856 and microservice - "my-service", for example localhost:8081. I can get access to endpoint localhost:8081/actuator/health -> {"status": "UP"}. But I need to access such endpoint through gateway like localhost:7856/my-service/actuator/health
My gateway config:
zuul:
ignoredServices: '*'
routes:
my-service:
path: /my-service/**
serviceId: my-service
stripPrefix: false
Here, crucial moment, I can't change stripPrefix to true. I know, that I can add
management:
endpoints:
web:
base-path: /my-service/actuator
but it wouldn't be good solution, because in that case also need to change eureka config (for eureka default endpoint is service-name/actuator/health) for check health status for microservices. Or I can create additional endpoint that would redirect to what I need. But I'm trying to find the best decision, may be its a special property for zuul or overriding zuul classes ?
Finally, I found a solution.
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
public class CustomRouteLocator extends SimpleRouteLocator {
public CustomRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
}
#Override
protected Route getRoute(ZuulRoute route, String path) {
boolean oldPrefix = route.isStripPrefix();
if (path.matches(".*/actuator/.*")) {
route.setStripPrefix(true);
}
Route resultRoute = super.getRoute(route, path);
route.setStripPrefix(oldPrefix);
return resultRoute;
}
}
I turn on/off stripPrefix property. That works well.
I am running a couple of services in GAP and I have to assign each service a specific subdomain, which is done from the dispatch.yaml file. So far so good, my query is: Is it enough to define the dispatch.yaml file in a single service or do I have to do it for each one?
You can assign all services to specific subdomains using a single dispatch.yaml file:
- url: "subdomain1.domain.com/*"
service: service1
- url: "subdomain2.domain.com/*"
service: service2
- url: "subdomain3.domain.com/*"
service: service3
#And so on
We are using server configuration in yml file which looks like as below
server:
type: simple
connector:
type: http
port: 8061
applicationContextPath: /administration
adminContextPath: /admin
#disable the registration of default Jersey ExceptionMappers
registerDefaultExceptionMappers: false
I want to get "applicationContextPath" when I start my dropwizard service.
I am trying to get it using
environment.getApplicationContext().getContextPath();
but I am getting "/" i.e. default value. Is there anyway to get this.
In order get applicationContextPath we need to get ServerFactory from Configuration and parse it to SimpleServerFactory as below:
((SimpleServerFactory) getConfiguration().getServerFactory()).getApplicationContextPath()
This works for me:
#Override
public void run(CustomAppConfiguration customAppConfiguration , Environment environment) throws Exception {
DefaultServerFactory factory = (DefaultServerFactory) customAppConfiguration .getServerFactory();
System.out.println("CONTEXT PATH: "+factory.getApplicationContextPath());
...
}
If it's in your config file and you want to just read the value in as it exist in your config.yml, then I'd suggest making it part of your Configuration class. Values in your config can always be accessed this way regardless of whether dropwizard uses and treats those key/values in special manner internally.
The following worked for me in dropwizard 1.0.0:
MyApp.java:
public class MyApp extends Application<MyConfig> {
//...
#Override
public void run(MyConfig configuration, Environment environment) throws Exception {
System.out.println(configuration.contextPath);
//...
MyConfig.java
public class MyConfig extends Configuration {
//...
#JsonProperty("applicationContextPath")
public String contextPath;
//...
If I understood your question correctly what you can do in Dropwizard version 1.3.8 if you are using simple server (without https) you can get applicationContextPath in following way:
server:
type: simple
rootPath: /*
applicationContextPath: /administration
adminContextPath: /admin
connector:
type: http
port: 8080
More info about rootPath can be found in Dropwizard Configuration Reference. So if you want to access:
Application REST endpoint /books (which is value of GET,
POST or similar annotation in one of your Resource class methods) you can
type URL like this http://localhost:8080/administration/books
Metrics (only accessible via admin context path) of your Dropwizard application then you create URL like this: http://localhost:8080/admin/metrics
Hope that helps. Cheers!
There's a difference in implementation between two versions of Spring Boot Actuator (1.2.5 and 1.3.0) in HealthMvcEndpoint, isUnrestricted() method ( && and || ). I understand that this is to preserve these restrictions
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready-health-access-restrictions
But is there any solution now to enable only one endpoint (e.g. Health) unrestricted with full content, without exposing all the others?
Disabling management.security.enabled is just making all the endpoints accessible without authentication (?) - it doesn't look like it's taking endpoint sensitivity with it.
I managed to partially solve this by making all the endpoints disabled in the first place by endpoints.enabled = false with disabling their security management.security.enabled = false
and enabled the ones I wanted without security - like the Health endpoint
endpoints.health.enabled = true and endpoints.health.sensitive = false.
With actuator 2 these properties have been changed
To disable all the actuator endpoints use
management.endpoints.enabled-by-default=false
To enable specific endpoint use management.endpoint.<id>.enabled property. The following example enables the shutdown endpoint:
management.endpoint.shutdown.enabled=true
Official Documentation
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html
In my DropWizard (v0.7.0) app, I have a DummyHealthCheck like so:
public class DummyHealthCheck extends HealthCheck {
#Override
protected Result check() throws Exception {
return Result.healthy();
}
}
Then in my main Application impl:
public class MyApplication extends Application<MyConfiguration> {
#Override
public void run(MyConfiguration configuration, Environment environment)
throws Exception {
environment.jersey().register(new DummyHealthCheck());
}
}
When I start up the server, it starts successfuly (no exceptions/errors), however I get the following message:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! THIS APPLICATION HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW !
! IF IT DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE !
! LETTING YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH OF YOUR !
! APPLICATION'S DEPENDENCIES WHICH FULLY (BUT LIGHTLY) TESTS IT. !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
But when I go to http://localhost:8081/healthcheck I see:
{"deadlocks":{"healthy":true}}
What is going on here? How do I register my health check?
Also, I have configured DropWizard to use SSL (self-signed) on port 8443; I have verified this works with my normal endpoints. I am surprised, however, to see that my admin app is still exposed on 8081 over HTTP. How do I configure it for HTTPS as well?
Question 1:
You don't register it with Jersey, as Health Checks are DropWizard specific. They should be registered as follows
environment.healthChecks().register("dummy", new DummyHealthCheck());
as explained here. If it was registered as above, you would see
{"deadlocks":{"healthy":true}, "dummy":{"healthy":true}}
Question 2:
I assume you already have done something similar to
server:
applicationConnectors:
- type: https
port: 8443
keyStorePath: example.keystore
keyStorePassword: example
validateCerts: false
in your yaml, as seen here. That is just for the application. You will also need to configure the admin
server:
applicationConnectors:
- ...
adminConnectors:
- type: https
port: 8444 // should a different port from the application
keyStorePath: example.keystore
keyStorePassword: example
validateCerts: false