Spring boot admin with docker resolves docker hostnames and IPs - java

My Issue/Setup
I'm trying to build a stand-alone spring boot admin application which all our instances (in a private VPC- behind a network load balancer) can register with.
But my spring boot application itself runs inside a docker container, so hostname and ip-address always defaults to the container hostname and container ip-address.
And spring-boot admin fails with
`Request failed with status code 502`
Connection refused: /1XX.17.0.2:8840
because it cannot find actual hosts with the hostname or the IP addres.
What i tried
I had the set up working with below (one instance),
`spring.boot.admin.client.instance.service-base-url`
But cannot use this for multiple clients as i cannot specify a comma separated value.
Moreover, since there can be n number of instance at any time i do not want to use the below property.
`spring.boot.admin.client.instance.service-base-url`
So i took the suggestion to omit spring.boot.admin.client.instance.service-base-url on spring-boot-admin git hub page and issues section and used below instead
`spring.boot.admin.client.instance.prefer-ip=true`
But Since my applications are running inside a docker container,
spring boot clients register itself with container id/ip-address as the hostname/ip-address.
I also tried the "--net=admin-network","--name client" parameters in my AWS beanstalk file
"containerDefinitions": [
{
"name": "cloudy-email",
"image": "xxx.dkr.ecr.us-east-2.amazonaws.com/sba-admin-repo:xx_2019-04-24_14.36_e9aax8710",
"command": [ "--net=admin-network","--name client"],
"Update": "true",
How can i overcome this issue?
Any pointers/references would be much appreciated.

You can make docker run in the host network using the --network host option to the docker run command. This will make the container assume the same IP address of the host VM. Also, check if you are exposing the admin port through Docker and the host firewall (security groups).
More info: https://docs.docker.com/network/host/

Related

How to set intellij remote debug?

I am trying to debug my app in testing environment, my app is running in pod, I said 'pod' because I am not familiar with Kubernetes, its manage client looks like this:app running schematic diagram. I have learn I should set idea like this idea RUN/Debug Configurations schematic diagram. And should restart and redeploy my app, I changed Dockfile firstly. the origin instruction is FROM xxx/java:alpine VOLUME /tmp ADD recruitment.jar app.jar ENTRYPOINT ["java","-Xmx2048m","-jar","/app.jar"] and I changed this to FROM xxx/java:alpine VOLUME /tmp ADD recruitment.jar app.jar ENTRYPOINT ["java","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005","-jar","/app.jar"] but it always show error like this Error running 'face_remote': Unable to open debugger port (888.88.888.888[not real]:5005): java.io.IOException "handshake timeout". I am not sure with this ip,sicne I use 'ping 888.88.888.888' instruction can not success. I use this ip because Swagger request url's domain name's ip is this.this main enter image description here. and I guess if the app is running in docker or k8s and it will have a different Interactive mode. not same like just running in linux
most of the attached image are not visible.
IP address should be accessible from your local system
[888.88.888.888] note sure this is correct.
debug port also need to be mapped from your local system
-use port forwarding
ex:kubectl port-forward 5005:5005
If you have configure port forwarding then you can use localhost:5005 for debugging
I see three things that you can check:
Check the IP address:
The jar file runs inside a Docker container, which runs inside a pod. To access the pod you usually go through a service and an ingress. The ip you are using is most likely hitting the ingress/service or any other higher layer.
To attach a remote debugger, you will need to connect directly to the PodIP. One way of doing this is to first connect to your kubernetes cluster using the tool kubectl (some configuration required) and make a port forward from your pod: kubectl port-forward my-pod-c93b8b6df-8c4aa 5005:5005 pod (as an example, the pod instance name is my-pod-c93b8b6df-8c4aa).
This will open a connection from your local computer into the pod. Then you will need to identify the PodIP by kubectl describe pods my-pod-c93b8b6df-8c4aa and use that in IntelliJ
Check if the port is exposed:
Make sure you expose the port 5005 from the pod in your test environment (similar to exposing a port when you run the container locally).
How to do this depends a bit on how you are running your Kubernetes cluster. If you use Helm chart, you can just add a configuration like this in the port section of your deployment yaml:
- containerPort: 5005
name: debug
protocol: TCP
Check debug-command address:
Last thing is to make sure you are adding the correct address in the command line option. As IntelliJ suggest in the debug editor: for JDK9+ use …suspend=n,address=*:5005 and for JDK8 and below use …suspend=n,address=5005

URL for webapp Docker Tomcat IntelliJ

I'm using a Tomcat 9 server in a Docker container to deploy locally a webapp for development purposes. I can connect to my Tomcat using http://localhost:8080/ But I can't find my webapp URL anywhere. My Docker container is deployed from IntelliJ, and I have no URL field in the configuration of the Container.
Does anyone know where to find/set the URL ?
There is no URL to be set, at least not explicitly.
Once you have your application started in a container (either started through IntelliJ IDEA, Docker Desktop (for), command line...) with the port binding configuration (the Bind ports config section in your screenshot), you are only left with the application as if it was started on the host on the mapped port (the first section before the colon : in the port binding).
Which means you can simply access your application on:
http://localhost:8080
following the pattern for a URL: (protocol)://(host)(:port) where:
protocol is HTTP since you mentioned using Tomcat as a web server
host being you local station where the docker daemon is running on
port being the port you chose to map to the started container port

Trouble communicating between two docker containers

I’m new to docker and I’m trying to connect my spring boot app running into my boot-example docker container to a mysql server running into my mymysql docker container on port 6603, both running on the same phisical machine.
The fact is: if I connect my spring-boot app to my mymysql docker container in order to communicate with the database, I get no errors and everything works fine.
When I move my spring boot application into my boot-example container and try to communicate (through Hibernate) to my mymysql container, then I get this error:
2018-02-05 09:58:38.912 ERROR 1 --- [ main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_111]
My spring boot application.properties are:
server.port=8083
spring.jpa.hibernate.ddl-auto=create-drop
spring.datasource.url=jdbc:mysql://localhost:6603/mydockerdb
spring.datasource.username=root
spring.datasource.password=mypassword
It works fine until my spring boot app runs in a docker container on port 8082, (after the docker image is correctly built):
docker run -it -p 8082:8083 boot-example
You cannot use localhost inside the container, it's the container itself. Hence, you will always get the connection refused error.
You can do below things -
Add your host machine IP in application.properties file of your spring boot application. (Not recommended since it breaks docker portability logic)
In case you want to use localhost, use --net=host while starting the container. (Not recommended for Production since no logical network layer exists)
Use --links for container communication with a DNS name. (deprecated/legacy)
Create a compose file & call your DB from spring boot app with the service name since they will be in same network & highly integrated with each other. (Recommended)
PS - Whenever you need to integrate multiple containers together, always go for docker-compose version 3+. Use docker run|build to understand the fundamentals & performing dry/test runs.
As #vivekyad4v suggested - the easiest way to achieve your desire, is to use docker-compose which has better container communication integration.
Docker-compose is a tool for managing single or multiple docker container/s. It uses single configuration file called docker-compose.yml.
For better information about docker-compose, please take a look at documentation and compose file reference
In my experience, it is good practice to follow SRP (single responsibility principle), thus - creating one container for your database and one for your application. Both of them are communicating using network you specify in your configuration.
Following example of docker-compose.yml might help you:
version: '2'
networks:
# your network name
somename:
driver: bridge
services:
# PHP server
php:
image: dalten/php5.6-apache
ports:
- 80:80
volumes:
- .application_path:/some/application/path
# your container network name defined at the beggining
networks:
- somename
# Mysql server for backend
mysql:
image: dalten/mysql:dev
ports:
- 3306:3306
# The /var/lib/mysql volume MUST be specified to achieve data persistence over container restart
volumes:
- ./mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: backend
# your container network name defined at the beggining
networks:
- somename
Note: Communication between containers inside network can be achieved by calling the service name from inside container.
The connection parameters to MySQL container from PHP, would in this example be:
hostname: mysql
port: 3306
database: backend
user: root
password: root
As per above suggestion, Docker-compose is a way but if you don't want to go with compose/swarm mode.
Simply create your own network using docker network create myNet
Deploy your containers listening on a created network --network myNet
Change your spring.datasource.url to jdbc:mysql://mymysql:6603/mydockerdb
By using DNS resolution of docker demon, containers can discover each other and hence can communicate.
[DNS is not supported by default bridge. A user-defined network using bridge does.]
For more information: https://docs.docker.com/engine/userguide/networking/

Register multiple Instances of a Spring Boot Eureka Client from a single host

UPDATE
The README in this repo has been updated to demonstrate the solution in the accepted answer.
I'm working with a simple example of a Spring Boot Eureka service registration and discovery based on this guide.
If I start up one client instance, it registers properly, and it can see itself through the DiscoveryClient. If I start up a second instance with a different name, it works as well.
But if I start up two instances with the same name, the dashboard only shows 1 instance running, and the DiscoveryClient only shows the second instance.
When I kill the 2nd instance, the 1st one is visible again through the dashboard and the discovery client.
Here are some more details about the steps I'm taking and what I'm seeing:
Eureka Server
Start the server
cd eureka-server
mvn spring-boot:run
Visit the Eureka dashboard at http://localhost:8761
Note that there are no 'Instances' yet registered
Eureka Client
Start up a client
cd eureka-client
mvn spring-boot:run
Visit the client directly at http://localhost:8080/
The /whoami endpoint will show the client's self-knowledge of its application name and port
{
"springApplicationName":"eureka-client",
"serverPort":"8080"
}
The /instances endpoint will take up to a minute to update, but should eventually show all the instances of eureka-client that have been registered with the Eureka Discovery Client.
[
{
"host":"hostname",
"port":8080,
"serviceId":"EUREKA-CLIENT",
"uri":"http://hostname:8080",
"secure":false
}
]
You can also visit the Eureka dashoboard again now and see it listed there.
Spin up another client with a different name
You can see that another client will be registred by doing the following:
cd eureka-client
mvn spring-boot:run -Dspring.application.name=foo -Dserver.port=8081
The /whoami endpoint will show the name foo and the port 8081.
In a minute or so, the /instances endpoint will show the information about this foo instance too.
On the Eureka dashboard, two clients will now be registered.
Spin up another client with the same name
Now try spinning up another instance of eureka-client by only over-riding the port parameter:
cd eureka-client
mvn spring-boot:run -Dserver.port=8082
The /whoami endpoint for http://localhost:8082 shows what we expect.
In a minute or so, the /instances endpoint now shows the instance running on port 8082 also, but for some reason, it doesn't show the instance running on port 8080.
And if we check the /instances endpoint on http://localhost:8080 we also now only see the instance running on 8082 (even though clearly, the one on 8080 is running since that's what we're asking for.
The Eureka dashboard only shows 1 instance of eureka-client running.
What's going on here?
Let's try killing the instance running on 8082 and see what happens.
When we query /instances on 8080, it still only shows the instance on 8082.
But a minute later, that goes away and we just see the instance on 8080 again.
The question is, why don't we see both instances of eureka-client when they are both running?
For local deployments, try to configure {namespace}.instanceId property in eureka-client.properties (or eureka.instance.metadataMap.instanceId for proper yaml file in case of Spring Cloud based setup). It's deeply rooted in the way Eureka server calculates application lists and compares InstanceInfo for the PeerAwareInstanceRegistryImpl - when no more concrete data (e.g.: instance metadata is available) they try to get the id from the hostname..
I wouldn't recommend it for AWS deployment though, cause messing around with instanceId will bring you trouble figuring out which machine hosts a particular service - on the other hand I doubt that you'll hosts two identical services on one machine, right?
In order to get all instances show up in the admin portal by setting unique euraka.instance.hostname in your Eureka configuration file.
The hostname is used as key for storing the InstanceInfo in com.netflix.discovery.shared.Application (since no UniqueIdentifier is set). So you have to use unique hostnames. When you test ribbon in this scenario you would see that the load won't be balanced.
Following application.yml is example:
server:
port: ${PORT:0}
info:
component: example.server
logging:
level:
com.netflix.discovery: 'OFF'
org.springframework.cloud: 'DEBUG'
eureka:
instance:
leaseRenewalIntervalInSeconds: 1
leaseExpirationDurationInSeconds: 1
metadataMap:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
It's a bug before in Eureka, you can check further information in https://github.com/codecentric/spring-boot-admin/issues/134

Communication between spring boot dockerized apps

I new using spring boot and docker and I faced a problem running the docker containers.
On debug mode, there is no problem on applications boot, but when I run them as a container, there is something wrong.
For example, I have my server config with all the yml files, also eureka properties.
The config server boot perfectly, but not the eureka server, it must look for it`s configuration to the config server becouse of these:
uri: ${vcap.services.config-service.credentials.uri:http://127.0.0.1:8888}
In the eureka`s log I can found:
Could not locate PropertySource: I/O error on GET request for
"http://127.0.0.1:8888/server-eureka/default":Connection refused;
nested exception is java.net.ConnectException: Connection refused
So I see that eureka cant connect to the config server for a reason I cant understund.
Maybe I miss something in my docker file.
If you are not using docker linked containers you'll have to use only the public ip addresses. Docker will assign every running container an own ip address which is per default not accessible. Only when you start to expose ports there will be an entry to iptables that is linking the hosts public ip address and given port to the internal used port and (dynamically assigned) ip address of the docker container. This is also why 127.0.0.1 does not work cause it would look into the containers local context but tgere the service is not running.

Categories

Resources