Debugging Tomcat in Docker container - debugging

I have a CoreOS running in Vagrant. Vagrant private network IP is 192.168.111.1. Inside a CoreOS is a docker container with Tomcat 8.0.32. Pretty much everything works ok (app deployment etc.) just debugging does not. Tomcat is mapped to 8080 port and the JPDA port should be 8000.
Facts
Tomcat JPDA is configured with:
JDPA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
It starts with catalina.sh jpda start command. The output in the console when running it with docker-compose is:
tomcat | Listening for transport dt_socket at address: 8000
From the container info I assume that ports are mapped as they should:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dcae1e0148f8 tomcat "/run.sh" 8 minutes ago Up 8 minutes 0.0.0.0:8000->8000/tcp, 0.0.0.0:8080->8080/tcp tomcat
My docker image is based on this Dockerfile.
Problem
When trying to run Remote debug configuration (screenshot below) I get the error Error running Debug: Unable to open debugger port (192.168.111.1:8000): java.net.ConnectException "Connection refused". I've tried everything from changing various configuration but no luck. Am I missing something?

This is the command I use for this:
docker run -it --rm \
-e JPDA_ADDRESS=8000 \
-e JPDA_TRANSPORT=dt_socket \
-p 8888:8080 \
-p 9000:8000 \
-v D:/tc/conf/tomcat-users.xml:/usr/local/tomcat/conf/tomcat-users.xml \
tomcat:8.0 \
/usr/local/tomcat/bin/catalina.sh jpda run
Explanation
-e JPDA_ADDRESS=8000debugging port in container, passed as environment variable
-e JPDA_TRANSPORT=dt_sockettransport type for debugging as socket, passed as environment variable
-p 8888:8080 expose tomcat port 8080 on host as port 8888
-p 9000:8000 expose java debugging port 8000 on host as port 9000
-v {host-file}:{container-file}overwrite tomcat-user.xml with my local on, since I need access to the manager apiomit this line if this isn't necessary for your use case
tomcat:8.0see https://hub.docker.com/_/tomcat/
/usr/local/tomcat/bin/catalina.sh jpda runcommand to run in the container

The accepted answer didn't work for me, apparently because I was using Java 11. It seems that if you're using Java 9 or newer, you need to specify the JPDA address like this:
JPDA_ADDRESS=*:8100

You can always update the Dockerfile to something like the following: -
FROM tomcat:8-jre8
MAINTAINER me
ADD target/app.war /usr/local/tomcat/webapps/app.war
ENV JPDA_ADDRESS="8000"
ENV JPDA_TRANSPORT="dt_socket"
EXPOSE 8080 8000
ENTRYPOINT ["catalina.sh", "jpda", "run"]
This does mean though that your docker file has debug on by default which is probably not suited to a production environment.

Try add to your Dockerfile
ENV JPDA_ADDRESS=8000
ENV JPDA_TRANSPORT=dt_socket
It works for me

You need to make sure that port 8080 is exposed to IntelliJ for connection. That is while running docker you shall require something like docker run -p 8080:8080
For example, I am able to achieve the similar requirement like this by doing below mentioned steps/checks.
This is what my docker run command looks like:
sudo docker run --privileged=true -d -p 63375:63375 -p 63372:8080 -v /tmp/:/usr/local/tomcat/webapps/config <container name>:<tag>
NOTE: I am exposing an extra port 63375 on container and on my host both. The same port I am using in CATALINA_OPTS below.
This is what my entry point (for the image that I am building) looks like. NOTE: I am using CATALINA_OPTS. Also, I am using maven to create image so below is excrept from pom.xml.
<entryPoint>
<shell>cd /usr/local/tomcat/bin; CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,address=63375,server=y,suspend=n" catalina.sh run</shell>
</entryPoint>

I resolved a similar, if not the same, issue when using docker-compose.
It involved the environment variables not being passed properly from the docker-compose.yml file.
See my stack overflow issue:

For me is cleaner this way:
docker run -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n" -p 8000:8000 tomcat:8.5-jdk8
This way you don't have to modify your container Dockerfile.
Explanation: all java version check the JAVA_TOOL_OPTIONS environment variable: https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html

I have similar setup in my local environment. I included JPDA_ADDRESS as environment variable in the Dockerfile and recreated the containers.
ENV JPDA_ADDRESS 8000
#Expose port 8080, JMX port 13333 & Debug port 8000
EXPOSE 8080 13333 8000
CMD ["tail", "-f", "/dev/null"]

Related

Access Tomcat debug port outside container

I have a container running java backend on a tomcat server. I would like to configure it so that I can attach my eclipse to debug my code.
There is a lot of documentation but with so many different and contradictory answers, I can't find a way to do it.
here is my current configuration :
DockerFile :
From tomcat:9.0-jdk8-openjdk
ADD ./application.war /usr/local/tomcat/webapps/
ADD tomcat-users.xml /usr/local/tomcat/conf/tomcat-users.xml
ADD server.xml /usr/local/tomcat/conf/server.xml
EXPOSE 9090
CMD ["catalina.sh","run"]
And the command to run the docker :
docker run -d -p 9090:8080 myApp
What should I add to make my application accessible to remote debugging ?
the solution I found was :
DockerFile
From tomcat:9.0-jdk8-openjdk
ADD ./application.war /usr/local/tomcat/webapps/
ADD tomcat-users.xml /usr/local/tomcat/conf/tomcat-users.xml
ADD server.xml /usr/local/tomcat/conf/server.xml
EXPOSE 9090
EXPOSE 9000
ENV JPDA_ADDRESS=8000
ENV JPDA_TRANSPORT=dt_socket
CMD ["catalina.sh", "jpda", "run"]
and then :
docker run -d -p 9090:8080 -p 9000:8000 myApp after building the image.
Warning : this makes the application debuggable only from the server where the docker is running (in localhost:9000 in that example)! I read there is something to do with *:JPDA_ADDRESS but I could not make it work.

Docker map port is invalid

I followed the tutorial to compile the project's image file with gradle and type it into docker. At the same time, the image is run and the virtual port is mapped to port 8761. However, my host accesses port 8761 and cannot connect. At the same time, I start the project locally and the host 8761 can be used.
I modified the dependent jdk8 image and added EXPOSE to the dockerfile.
Below are the configuration files and the docker run command:
FROM gmaslowski/jdk
VOLUME /tmp
ADD his-eureka-server-one-0.0.1-SNAPSHOT.jar app.jar
#RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-
jar","/app.jar"]
EXPOSE 8760
docker run -d -t -p 127.0.0.1:8760:8760 com.anhuishangjue/his-eureka-
server-one:0.0.1-SNAPSHOT
I want the host's 127.0.0.1:8760 to be able to access the eureka registry, but he told me to deny access

docker ports not available

I have a spring-config-sever project that I am trying to run via Docker. I can run it from the command line and my other services and browser successfully connect via:
http://localhost:8980/aservice/dev
However, if I run it via Docker, the call fails.
My config-server has a Dockerfile:
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=build/libs/my-config-server-0.1.0.jar
ADD ${JAR_FILE} my-config-server-0.1.0.jar
EXPOSE 8980
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/my-config-server-0.1.0.jar"]
I build via:
docker build -t my-config-server .
I am running it via:
docker run my-config-server -p 8980:8980
And then I confirm it is running via
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cecafdf99fe my-config-server "java -Djava.securit…" 14 seconds ago Up 13 seconds 8980/tcp suspicious_brahmagupta
When I run it via Docker, the browse fails with a "ERR_CONNECTION_REFUSED" and my calling services fails with:
Could not locate PropertySource: I/O error on GET request for
"http://localhost:8980/aservice/dev": Connection refused (Connection
refused);
Adding full answer based on comments.
First, you have to specify -p before image name.
docker run -p 8980:8980 my-config-server.
Second, just configuring localhost with host port won't make your my-service container to talk to other container. locahost in container is within itself(not host). You will need to use appropriate docker networking model so both containers can talk to each other.
If you are on Linux, the default is Bridge so you can configure my-config-server container ip docker inspect {containerIp-of-config-server} as your config server endpoint.
Example if your my-config-server ip is 172.17.0.2 then endpoint is - http://172.17.0.2:8980/
spring:
cloud:
config:
uri: http://172.17.0.2:8980
Just follow the docker documentation for little bit more understanding on how networking works.
https://docs.docker.com/network/network-tutorial-standalone/
https://docs.docker.com/v17.09/engine/userguide/networking/
If you want to spin up both containers using docker-compose, then you can link both containers using service name. Just follow Networking in Compose.
I could imagine that the application only listens on localhost, ie 127.0.0.1.
You might want to try setting the property server.address to 0.0.0.0.
Then port 8980 should also be available externally.

Docker on Mac is running but refusing to expose port

Mac here, running Docker Community Edition Version 17.12.0-ce-mac49 (21995).
I have Dockerized a web app with a Dockerfile like so:
FROM openjdk:8
RUN mkdir /opt/myapp
ADD build/libs/myapp.jar /opt/myapp
ADD application.yml /opt/myapp
ADD logback.groovy /opt/myapp
WORKDIR /opt/myapp
EXPOSE 9200
ENTRYPOINT ["java", "-Dspring.config=.", "-jar", "myapp.jar"]
I then build that image like so:
docker build -t myapp .
I then run a container of that image like so:
docker run -it -p 9200:9200 --net="host" --env-file ~/myapp-local.env --name myapp myapp
In the console I see the app start up without any errors, and all seems to be well. Even my metrics publishes (which publish heartbeat and other health metrics every 20 seconds) are printing to the console as I would expect them to. Everything seems to be fine.
Except when I go to run a curl against my app from another terminal/session:
curl -i -H "Content-Type: application/json" -X POST -d '{"username":"heyitsme","password":"12345"}' http://localhost:9200/v1/auth/signIn
curl: (7) Failed to connect to localhost port 9200: Connection refused
Now, if this were a situation where the /v1/auth/signIn path wasn't valid, or if there was something wrong with my request entity/payload, the server would pick up on it and send an error (I assure you; as I can confirm this exact same curl works when I run the server outside of Docker as just a standalone service).
So this is definitely a situation where the curl command can't connect to localhost:9200. Again, when I run my app outside of Docker, that same curl command works perfectly, so I know my app is trying to standup on port 9200.
Any ideas as to what could be going wrong here, or how I could begin troubleshooting?
The way you run your container has 2 conflicting parts:
-p 9200:9200 says: "publish (bind) port 9200 of the container to port 9200 of the host"
--net="host" says: "use the host's networking stack"
According to Docker for Mac - Networking docs / Known limitations, use cases, and workarounds, you should only publish a port:
I want to connect to a container from the Mac
Port forwarding works for localhost; --publish, -p, or -P all work. Ports exposed from Linux are forwarded to the Mac.
Our current recommendation is to publish a port, or to connect from another container. This is what you need to do even on Linux if the container is on an overlay network, not a bridge network, as these are not routed.
The command to run the nginx webserver shown in Getting Started is an example of this.
$ docker run -d -p 80:80 --name webserver nginx
Check that your app bind to 0.0.0.0:9200 and not localhost:9200 or something similar
Problem seems to be in the network mode you are running the container.
Quick test: Login to your container and run the curl cmd there, hopefully it works. That would isolate the problem to request not being forwarded from host to container.
Try running your container on the default bridge network and test.
Refer to this blog for details on the network modes in docker
TLDR; You will need to add an IPtables entry to allow the traffic to enter your container.

Failed to communicate a dockerized process with elastic search with "None of the configured nodes are available"

I have spring boot application which communicate with ElasticSearch 5.0.0 alpha 2.
My application successfully communicate with elastic and preform several queries.
When I try to dockerize my application, it fails to communicate with ElasticSearch, and I get the following error:
None of the configured nodes are available: [{#transport#-1}{127.0.0.1}{127.0.0.1:9300}]
I have spent a lot of time on the internet, but I have found problems when the ElasticSearch is dockerized, but in my case, the client is dockerized, and it is working fine without the docker.
The command I used to create the docker image is: docker build -t my-service .
The DockerFile is:
FROM java:8
VOLUME /tmp
ADD ./build/libs/myjarfile-2.0.0.jar app.jar
EXPOSE 8090
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
To execute the image i use: docker run --name myname -d -p 8090:8090 -t my-service
Can someone share his/her experience with this issue?
Thanks
Guy Hudara
The problem is that your elasticsearch is not available on your dockerized host. When you put something in a docker container it also gets isolated on a network layer and localhost is localhost of the docker container but not the host itself. Therefore if you have elasticsearch also in a docker container use container linking and environment variable injection or reference your host machines address of your main network interface – not loopback – to your app.
Option 1
assuming that elasticsearch exposes 9200 try to run the following
$ docker run -d --name=elasticsearch elasticsearch
$ docker run -d --name=my-app --link elasticsearch:elasticsearch -p 8090:8090 my-app
Then you can define elasticsearch address in your app using env variable ${ELASTICSEARCH_PORT_9200_TCP_ADDR}.
Option 2
assuming your host machine runs on 192.168.1.10 you can also do the following:
$ docker run -d -p 9200:9200 elasticsearch
$ docker run -d -p 8090:8090 my-app
note that the name for the easticsearch container is optional here but the exposing of elasticsearch port mandatory. In this case you'll have to configure your elasticsearch host in your app given address of 192.168.1.10.

Resources