Spring Boot fails to start up in Docker container - spring

I have a Spring Boot application that I am able to run locally without errors. I am trying to run it in a Docker Container, but I am getting new errors that I don't understand.
Dockerfile:
FROM maven:3.8-jdk-8 AS build
COPY . /usr/app
WORKDIR /usr/app
RUN mvn clean package
FROM openjdk:8-alpine
COPY --from=build /usr/app/target/myapp-*.jar /usr/app/myapp.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/app/myapp.jar"]
Top of the error stack:
WARN 8 --- [ main] com.amazonaws.util.EC2MetadataUtils : Unable to retrieve the requested metadata (/latest/dynamic/instance-identity/document). Failed to connect to service endpoint:
com.amazonaws.SdkClientException: Failed to connect to service endpoint:
at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:100) ~[aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:70) ~[aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.readResource(InstanceMetadataServiceResourceFetcher.java:75) ~[aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.internal.EC2ResourceFetcher.readResource(EC2ResourceFetcher.java:66) ~[aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.util.EC2MetadataUtils.getItems(EC2MetadataUtils.java:402) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.util.EC2MetadataUtils.getData(EC2MetadataUtils.java:371) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.util.EC2MetadataUtils.getData(EC2MetadataUtils.java:367) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.util.EC2MetadataUtils.getEC2InstanceRegion(EC2MetadataUtils.java:282) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.regions.InstanceMetadataRegionProvider.tryDetectRegion(InstanceMetadataRegionProvider.java:59) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.regions.InstanceMetadataRegionProvider.getRegion(InstanceMetadataRegionProvider.java:50) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.regions.AwsRegionProviderChain.getRegion(AwsRegionProviderChain.java:46) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.client.builder.AwsClientBuilder.determineRegionFromRegionProvider(AwsClientBuilder.java:475) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.client.builder.AwsClientBuilder.setRegion(AwsClientBuilder.java:458) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.client.builder.AwsClientBuilder.configureMutableProperties(AwsClientBuilder.java:424) [aws-java-sdk-core-1.11.792.jar!/:na]
at com.amazonaws.client.builder.AwsSyncClientBuilder.build(AwsSyncClientBuilder.java:46) [aws-java-sdk-core-1.11.792.jar!/:na]
at org.springframework.cloud.aws.autoconfigure.secretsmanager.AwsSecretsManagerBootstrapConfiguration.smClient(AwsSecretsManagerBootstrapConfiguration.java:63) [spring-cloud-starter-aws-secrets-manager-config-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
I am not sure if this error matters, as I saw something similar locally (though that is resolved now) and the app still started up.
Error creating bean (I think this is the cause of the crash):
ERROR 23 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration': Unsatisfied dependency expressed through field 'propertySourceLocators'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'awsSecretsManagerPropertySourceLocator' defined in class path resource [org/springframework/cloud/aws/autoconfigure/secretsmanager/AwsSecretsManagerBootstrapConfiguration.class]: Unsatisfied dependency expressed through method 'awsSecretsManagerPropertySourceLocator' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'smClient' defined in class path resource [org/springframework/cloud/aws/autoconfigure/secretsmanager/AwsSecretsManagerBootstrapConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.amazonaws.services.secretsmanager.AWSSecretsManager]: Factory method 'smClient' threw exception; nested exception is com.amazonaws.SdkClientException: Unable to find a region via the region provider chain. Must provide an explicit region in the builder or setup environment to supply a region.
I compared the local maven version against the one in the the first image, and they are the same. My local java version is 1.8.0_275 while I have tried using images with versions 1.8.0_212 and 1.8.0_312 (I haven't found an image with the exact same version). I even tried copying over the working jar into the image instead of building it as part of the Docker build, but I got the exact same errors.
Edit: Here is my bootstrap.yml file that has the aws region
aws:
secretsmanager:
name: myapp-s3-creds
cloud:
aws:
region:
static: eu-west-1

If you have a docker-compose.yml file, you can specify the ff environment vars at the environment tag:
environment:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
Create a .env file in the directory of your docker-compose file with the values of the aws env vars set:
AWS_ACCESS_KEY_ID = your_access_key_id
AWS_SECRET_ACCESS_KEY = your_secret_access_key
On docker-compose build or up, the values will be copied from the .env file into the placeholders.

Related

JHipster Microservice Centralization without using Docker compose or any Docker container, need assistance

Currently the scenario is I am trying to implement
I used Jhipster Registry app directly from git-hub to use it as Eureka registry and Spring-Cloud-Config server(be default feature though).
I need to centralize the configurations of micro-service-apps' configurations files in Jhipster registry.
All these we have to do without using Docker as current project doesn't uses Docker.
To do that I made changes to
bootstrap.yml file as shown below( to run as composite profile though native type with local file system as we don't have access to production git repository. So chose file-system only with dev /composite profile only.
Currently my boostrap.yml looks as below
spring:
application:
name: jhipster-registry
profiles:
active: dev
include: composite
cloud:
config:
server:
bootstrap: true
composite:
- type: native #git
search-locations: file:/C:/Jhipster_Eureka/jhipster-registry-master/central-config/
prefix: /config
fail-fast: true
name: jhipster-registry
profile: composite
I have also created a gateway.yml file under central-config folder( gateway is one of micro-service sample app whose configuration I am trying to centralize, be it eureka client, data-source everything which comes under by default to application-dev.yml in the Jhipster micro-service gateway app I generated.)
by stating all configuration like below
gateway.yml
server:
port: 8888
management:
health:
diskspace:
enabled: false
# ===================================================================
# JHipster Sample Spring Cloud Config.
# ===================================================================
# Property used on app startup to check the config server status
configserver:
name: JHipster Registry config server
status: Connected to the JHipster Registry config server!
# Default JWT secret token (to be changed in production!)
jhipster:
security:
authentication:
jwt:
# It is recommended to encrypt the secret key in Base64, using the `base64-secret` property.
# For compabitibily issues with applications generated with older JHipster releases,
# we use the non Base64-encoded `secret` property here.
# secret: my-secret-key-which-should-be-changed-in-production-and-be-base64-encoded
# The `base64-secret` property is recommended if you use JHipster v5.3.0+
# (you can type `echo 'secret-key'|base64` on your command line)
base64-secret: bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo=
spring:
profiles:
active: dev
include:
- swagger
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://admin:admin#localhost:8761/eureka/
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/conference?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true
username: root
password: root
hikari:
poolName: Hikari
auto-commit: false
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
jpa:
show-sql: true
liquibase:
# Remove 'faker' if you do not want the sample data to be loaded automatically
contexts: dev
Issue#1
If I run my registry it's coming up properly without any issue. If I try to run "gateway" micro-service app without defining data-source definitions mentioned in it's own configuration file(application-dev.yml) it's failing at runtime.
Exception Stack trace during runtime
2020-08-06 21:45:58.301 WARN 28804 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'healthEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Unsatisfied dependency expressed through method 'healthEndpoint' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'healthContributorRegistry' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.health.HealthContributorRegistry]: Factory method 'healthContributorRegistry' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
I am surprised how eureka instance it picked up from that gateway.yml file but not the data source, so what went wrong here?
Issue#2
In the gateway.app yml server.port:8888 is mentioned, but would it be spring-cloud-config-server's port or the micro-service app port e.g., 8083
.
I observed if i try to alter that port from 8888 to 8083 it's giving error at runtime not able to find discovery client, what's the issue or am i still missing something configuration-wise?
Please let me know if the query is detailed enough now to respond.
Docker is absolutely NOT required for JHipster micro services architecture using jhipster-registry, your use case is well supported and the issues you encountered are only due to your configuration errors.
gateway.yml is not indented correctly so property names for datasource do not match and this is why you get this error about being unable to find JDBC driver.
The eureka block in the middle of the spring block completely broke it and anyway eureka config is shared by all apps so it should be placed in application-dev.yml and application-prod.yml.
gateway.yml as any other files that are in environment repository (central-config folder when using native) must be exactly the same format as your local application.yml files.
If you are not comfortable with YAML files you could switch to normal properties.
About file naming in native repository, Spring Cloud Config Server doc says:
If the repository is file-based, the server creates an Environment from application.yml (shared between all clients) and foo.yml (with foo.yml taking precedence). If the YAML files have documents inside them that point to Spring profiles, those are applied with higher precedence (in order of the profiles listed). If there are profile-specific YAML (or properties) files, these are also applied with higher precedence than the defaults.
So basically it means that in your central-config folder you should have these files:
application.yml: all properties common to all apps when no profile is set
application-dev.yml: all properties common to all apps when dev profile is set. This is where you will put the JWT secret for dev, the url for dev Eureka server (often localhost)
application-prod.yml: all properties common to all apps when prod profile is set. This is where you will put the JWT secret for prod, the url for prod Eureka server
gateway.yml: all properties of gateway app when no profile is set
gateway-dev.yml: all properties of gateway app when dev profile is set. This is where you will put dev datasource
gateway-prod.yml: all properties of gateway app when prod profile is set. This is where you will put prod datasource
So when your gateway bootstraps with dev profile, it will gets a combination of application.yml, application-dev.yml, gateway.yml and gateway-dev.yml
This mechanism can work only if you follow the naming convention {app name}-{profile}.yml
So, having named a file application-dev-gateway.yml just meant properties common to all apps with dev-gateway profile which is probably not what you meant.

Spring boot ignores arguments passed after jvmArguments

I'm trying to run one of my microservices in debug mode.
For these I added jvmArguments to a command that starts application.
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" -Dspring.profiles.active="dev" -DAUTH0_CLIENT_ID="somevalue123" -DAUTH0_CLIENT_SECRET="somevalue123" -DACMS_CRYPTO_KEY="somevalue123" -DACMS_NODE_NAME="n/a" -DACMS_POD_IP="n/a" -DACMS_POD_NAMESPACE="n/a" -DACMS_POD_NAME="n/a"
As I'm using .yml file to provide client_id, client_secret and crypto_key I need to pass them also. Here is the config file:
acms:
crypto:
key: ${ACMS_CRYPTO_KEY}
node:
name: ${ACMS_NODE_NAME}
pod:
name: ${ACMS_POD_NAME}
namespace: ${ACMS_POD_NAMESPACE}
ip: ${ACMS_POD_IP}
env:
info:
enabled: false
auth0:
clientId: ${AUTH0_CLIENT_ID}
clientSecret: ${AUTH0_CLIENT_SECRET}
Without debug mode everything works fine. But when I'm adding
-Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"
I receive and error: Application run failed
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'acmsConfig': Injection of autowired
dependencies failed; nested exception is
java.lang.IllegalArgumentException: Could not resolve placeholder
'ACMS_CRYPTO_KEY' in value "${ACMS_CRYPTO_KEY}"
So how can I add debug mode command without breaking other arguments?
SivaKumar answer solved the problem. Working command looks like this:
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -Dspring.profiles.active=dev -DAUTH0_CLIENT_ID=testid -DAUTH0_CLIENT_SECRET=testsecret -DACMS_CRYPTO_KEY=testkey -DACMS_NODE_NAME=n/a -DACMS_POD_IP=n/a -DACMS_POD_NAMESPACE=n/a -DACMS_POD_NAME=n/a"

Unable to disable flyway via spring.flyway.enabled

I use flyway for my local profile to populate a DB for integration tests.
application.yml:
spring:
(...)
flyway.enabled: false
application-local.yml:
spring:
(...)
flyway:
enabled: true
license-key: (...)
locations: classpath:mssql/migrations
Expected:
App doesn't try to autoconfigure flyway during startup with profile dev
Actual:
The following profiles are active: dev
(...)
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException:
(...)
Factory method 'flyway' threw exception; nested exception is org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingException:
Cannot find migration scripts in: [classpath:db/migration] (please add migration scripts or check your Flyway configuration)
Versions:
flyway-core 6.3.1
spring boot 2.2.5
You specified application-local.yml and it means that you specified local profile but you run the application with dev profile. There are two potential issues:
You run the app with the wrong profile: should be local instead of
dev
Or you don't include local profile to dev https://docs.spring.io/spring-boot/docs/1.1.6.RELEASE/reference/html/boot-features-profiles.html

NoSuchBeanDefinitionException when running spring app in docker app in pivotal cloud foundry

I get NoSuchBeanDefinitionException when trying to deploy my spring app in a docker to PCF. The docker image is one that I've built and runs just fine outside of PCF.
I can run the same docker image locally connecting to the same config server. The config server is the only configuration provided when starting the app either locally or in PCF.
The same application runs just fine in PCF also when just deployed as a jar rather than a docker image.
The class with the problem is:
#Component
#EnableRabbit
#Slf4j
class ListenerProblemListener extends Listener {
#Autowired
ListenerProblemListener(ErrorServiceConfiguration errorServiceConfiguration,
MessageQueueLibrary messageQueueLibrary,
CachingConnectionFactory cachingConnectionFactory,
ProblemService problemService,
Sender sender) {
super(cachingConnectionFactory, messageQueueLibrary, problemService, sender)
log.info("Connecting to queues ${errorServiceConfiguration.allProblemQueues}")
}
}
I get the following exception only when attempting this in PCF.
2019-10-14T11:29:49.795-05:00 [APP/PROC/WEB/0] [OUT] [WARN ] 2019-10-14 16:29:49.794 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'listenerProblemListener' defined in URL [jar:file:/app.jar!/BOOT-INF/classes!/com/identifix/crawlererrorservice/listener/ListenerProblemListener.class]:
Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.amqp.rabbit.connection.CachingConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Turns out when running in docker in PCF I needed to set the env var SPRING_RABBITMQ_HOST. I'm not sure why providing it in the config server wasn't enough yet.

Spring Boot Could not autowire field Kubernetes SERVICE_HOST

I am using minikube. I have a service named updatedaddress. I am calling updateaddress service from updatecustomer service using auto injection of kubernetes environment variables .
My Java code looks like this
#Value("${UPDATEADDRESS_SERVICE_HOST}")
private String updateAddressHost;
#Value("${UPDATEADDRESS_SERVICE_PORT}")
private String updateAddressPort;
...
greeting= restTemplate.getForEntity("http://"+updateAddressHost+":"+updateAddressPort+"/updateaddress", Greeting.class).getBody();
When I execute the following command
kubectl --namespace=default-staging exec updatecustomer-4023824433-r5r19 env
I can see the environment variables UPDATEADDRESS_SERVICE_HOST=10.0.0.180 and UPDATEADDRESS_SERVICE_PORT=80 among many other variables.
When I try building the spring boot service I get the error
Error creating bean with name 'updateCustomerInfoResilient': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String com.amwater.UpdateCustomerInfoResilient.updateAddressHost; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'UPDATEADDRESS_SERVICE_HOST' in string value "${UPDATEADDRESS_SERVICE_HOST}"
Any advice would be helpful. Thank you .
Instated of using server IP and port number, try to use the service DNS name and test the application.
It will be something like this my-svc.my-namespace.svc.cluster.local replace your servicename and namespace.
here is the documentation https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

Resources