spring-cloud / spring-cloud-netflix

Integration with Netflix OSS components
http://cloud.spring.io/spring-cloud-netflix/
Apache License 2.0
4.87k stars 2.44k forks source link

Eureka FreeMarker template error in AMI's column when running in AWS Fargate with private IP #3703

Open lucasobsidiam opened 4 years ago

lucasobsidiam commented 4 years ago

I've successfully connected one of our microservices to Eureka using Fargate. Eureka is currently on an actual EC2 instance and microservices will be running from Fargate (hopefully Eureka too if I manage to get it to work). I have already got this running properly (or it seems as microservices connect to Eureka), with that said, I am getting a FreeMarker template error on the Eureka status page under the AMIs columns in "Instances currently registered with Eureka".

What I have done to achieve this Fargate to EC2 Eureka connection with private IP is the following. This dockerfile loads an entrypoint file which runs a shell script.

Dockerfile:

#############
### build ###
#############

# base image
FROM maven:3.6.2-ibmjava-8-alpine as build

# set working directory
WORKDIR /app

# install and cache app dependencies
COPY . /app
RUN mvn clean package

############
### prod ###
############

# base image
FROM openjdk:8-alpine

RUN apk add jq

# set working directory
WORKDIR /app

# copy entrypoint from the 'build environment'
COPY --from=build /app/entrypoint.sh /app/entrypoint.sh

# copy artifact build from the 'build environment'
COPY --from=build /app/target/user-service-0.0.1-SNAPSHOT.jar /app/user-service-0.0.1-SNAPSHOT.jar

# expose port 8081
EXPOSE 8081

# run entrypoint
ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]

This entrypoint shell script saves the private IP from the Fargate metadata endpoint into the shell session. entrypoint.sh:

#!/bin/sh
export FARGATE_IP=$(wget -q -O - http://169.254.170.2/v2/metadata | jq -r .Containers[0].Networks[0].IPv4Addresses[0])
echo $FARGATE_IP
java -jar user-service-0.0.1-SNAPSHOT.jar

The application property file loads the Fargate private IP so the microservice connects successfully. application-aws.properties

eureka.client.region=us-east-1
eureka.client.use-dns-for-fetching-service-urls=true
eureka.client.eureka-server-u-r-l-context=eureka
eureka.client.eureka-server-d-n-s-name=eureka.domain.com
eureka.client.eureka-server-port=8761
eureka.instance.prefer-ip-address=true
eureka.instance.ip-address=${FARGATE_IP}
eureka.instance.non-secure-port=8081

This is the error I receive on the Eureka page under the AMIs column even though the services seem to work. Any ideas?

FreeMarker template error (DEBUG mode; use RETHROW in production!): 
The following has evaluated to null or missing: ==> amiCount.key [in template "eureka/status.ftl" at line 35, column 26] 
---- Tip: It's the step after the last dot that caused this error, not those before it.
---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? ---- 
---- FTL stack trace ("~" means nesting-related): - Failed at: ${amiCount.key} [in template "eureka/status.ftl" at line 35, column 24] ---- Java stack trace (for programmers): 
---- freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]
 at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134)
 at freemarker.core.EvalUtil.coerceModelToTextualCommon(EvalUtil.java:467)
 at freemarker.core.EvalUtil.coerceModelToStringOrMarkup(EvalUtil.java:389)
 at freemarker.core.EvalUtil.coerceModelToStringOrMarkup(EvalUtil.java:358)
 at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:100)
 at freemarker.core.DollarVariable.accept(DollarVariable.java:63)
 at freemarker.core.Environment.visit(Environment.java:366)
 at freemarker.core.IteratorBlock$IterationContext.executedNestedContentForCollOrSeqListing(IteratorBlock.java:317)
 at freemarker.core.IteratorBlock$IterationContext.executeNestedContent(IteratorBlock.java:271)
 at freemarker.core.IteratorBlock$IterationContext.accept(IteratorBlock.java:242)
 at freemarker.core.Environment.visitIteratorBlock(Environment.java:642)
 at freemarker.core.IteratorBlock.acceptWithResult(IteratorBlock.java:107)
 at freemarker.core.IteratorBlock.accept(IteratorBlock.java:93)
 at freemarker.core.Environment.visit(Environment.java:366)
 at freemarker.core.IteratorBlock$IterationContext.executedNestedContentForCollOrSeqListing(IteratorBlock.java:317)
 at freemarker.core.IteratorBlock$IterationContext.executeNestedContent(IteratorBlock.java:271)
 at freemarker.core.IteratorBlock$IterationContext.accept(IteratorBlock.java:242)
 at freemarker.core.Environment.visitIteratorBlock(Environment.java:642)
 at freemarker.core.IteratorBlock.acceptWithResult(IteratorBlock.java:107)
 at freemarker.core.IteratorBlock.accept(IteratorBlock.java:93)
 at freemarker.core.Environment.visit(Environment.java:330)
 at freemarker.core.Environment.visit(Environment.java:336)
 at freemarker.core.Environment.visit(Environment.java:336)
 at freemarker.core.Environment.process(Environment.java:309)
 at freemarker.template.Template.process(Template.java:384)
 at org.springframework.web.servlet.view.freemarker.FreeMarkerView.processTemplate(FreeMarkerView.java:389)
 at org.springframework.web.servlet.view.freemarker.FreeMarkerView.doRender(FreeMarkerView.java:302)
 at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:253)
 at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:178)
 at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316)
 at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1371)
 at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1117)
 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1056)
 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
 at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
 at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114)
 at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
 at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
 at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
 at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
 at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
 at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
 at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.lang.Thread.run(Thread.java:748)
spencergibb commented 4 years ago

I'm not sure why amiCount isn't populated, but it would probably be as simple as providing a default.

lucasobsidiam commented 4 years ago

Is there a simple way of doing that without modifying source code? To temporarily show the connected micro-services properly.

spencergibb commented 4 years ago

Not that I know of. You could copy the template into your local app's src/main/resources/templates/eureka/status.ftlh and it should find that first.

fwuen commented 3 years ago

Is there any elegant solution for this by now? @lucasobsidiam @spencergibb

amit-github-personal commented 2 years ago

+1 facing same issue when deployed service on kubernetes

rohitkrishna-marneni commented 2 years ago

any update on this?

spencergibb commented 2 years ago

no, there isn't