Mac host doesn't like Docker container port forwarding - java

I am experimenting with Docker for the first time, and am trying to get a Spring Boot web app to run inside a Docker container. I am building the app (which packages up into a self-contained jar) and then adding it to the Docker image (which is what I want).
You can find my SSCCE at this Bootup repo on GitHub, whose README has all the instructions to reproduce what I'm seeing. But basically:
I build the web app into a jar
Run docker build -t bootup . which succeeds
Run docker run -it -p 9200:9200 -d --name bootup bootup and then container seems to start up just fine, as is evidence by the docker ps output below
However, when I point a browser to http://localhost:9200, I get nothing
docker ps output:
CONTAINER ID IMAGE COMMAND CREATED
a8c4ee64a1bc bootup "/bin/sh -c 'java -ja" 2 days ago
STATUS PORTS NAMES
Up 12 seconds 0.0.0.0:9200->9200/tcp bootup
The web app is configured to run on port 9200, not the Java default of 8080. You can see this for yourself by running the app outside of docker (so, just locally on you host machine) by running ./gradlew clean build && java -jar build/libs/bootup.jar.
To my knowledge, there is no Firewall running on my host that would be blocking ports (I am on Mac 10.11.5 and verified that System Preferences >> Security & Privacy >> Firewall is turned off).
Can anyone spot where I'm going awry?
Updates:
I ran a curl, netstat and lsof on the host:
HOST:
curl http://localhost:9200
curl: (52) Empty reply from server
netstat -an | grep 9200
tcp6 0 0 ::1.9200 *.* LISTEN
tcp4 0 0 *.9200 *.* LISTEN
lsof -n -i4TCP:9200 | grep LISTEN
com.docke 2578 myuser 19u IPv4 <someHexNumber> 0t0 TCP *:wap-wsp (LISTEN)
And then docker exec'd into the container and ran another netstat:
CONTAINER:
netstat -an | grep 9200
bash: netstat: command not found
Update w/ photos:
Picture of my browser (Chrome) pointed to http://localhost:9200:
Picture of the source code at http://localhost:9200:
Picture of Chrome Developer Tools inspecting the page at http://localhost:9200:
Picture of the Network tab in Chrome Developer Tools:
What the heck is going on here?!?!? According to the source, the browser should be rendering my Well hello there, from Dockerland! message just fine. According to the actual browser page, it looks like there is a networking error. And according to Chrome Developer Tools, my app is returning all sorts of HTML/CSS/JS content that is not even remotely apart of my app (check out the source code, see for yourself)!!!

The Dockerfile doesn't expose 9200 to the daemon. Add
EXPOSE 9200
to the Dockerfile before ENTRYPOINT

Assuming you are using Docker Toolbox and not the beta ...
There is a 3 step process for exposing a port properly:
use EXPOSE 8080 where 8080 is just a port number in the Dockerfile
use -p 8080:8080 in your docker run command
Make sure that you setup port forwarding in Oracle Virtual Box so that the boot2docker machine is able to receive requests from port 8080.
This applies to both Windows and OSX where Docker Toolbox is being used. Linux doesn't use Oracle VirtualBox to run docker so those hosts do not need to do the third point

I ran your repo as-is on Docker 1.12 on OSX.
If you look carefully at your container startup:
2016-08-29 20:52:31.028 INFO 5 --- [ main] o.eclipse.jetty.server.ServerConnector : Started ServerConnector#47949d1a{HTTP/1.1}{0.0.0.0:8080}
2016-08-29 20:52:31.033 INFO 5 --- [ main] .s.b.c.e.j.JettyEmbeddedServletContainer : Jetty started on port(s) 8080 (http/1.1)
Although application.yml and Dockerfile both contain 9200, the application is starting on 8080

Going to add another answer here because I saw something related to the Github Repo that you posted:
So the repo is a spring boot repo with an application.yml file.
Your Dockerfile looks like this:
FROM openjdk:8
RUN mkdir /opt/bootup
ADD build/libs/bootup.jar /opt/bootup
WORKDIR /opt/bootup
EXPOSE 9200
ENTRYPOINT java -jar bootup.jar
Which is adding the built jar to the image. If my understanding is correct, the jar does not include application.yml because:
It is not part of the build (gradle would package the src/main only). It is sitting on the project root folder
It is not explicitly added to Docker
So therefore one can assume that your app is actually running on 8080 (the default) at the moment?
A couple of options that one could try:
Try exposing 8080 instead of 9200 (or expose both) and see if that makes a difference?
The entrypoint command can append the port --server.port=9200
The application.yml file should be added to the image (you might need to add an argument to reference it properly) [ADD application.yml /opt/bootup, after first ADD command]
Include the application.yml file in src/main/resources so that spring boot can pick it up automatically.
References
Spring Boot reference documentation on the order of loading for external configuration

Good News! (for MacOSx 10.15.7)
I found the same issue as you, and I was able to solve it by directly opening VirutalBox connection
Go here first:
changed to bridged then logged into the virtual machine within VirtualBox
And found the actual machine's adapter labeled:
eth0
after I noted the setting it was originally NAT so I changed to bridged and then
I was able to use its address vs. localhost.
After I used the public address I used:
curl -i [bridged_ip_address_here]:9200
it then worked flawlessly.
However I also noticed some firewalls and accessibility options that needed permission as well.
I pray this helps you.

Related

Install Jenkins manually on docker image

I'm trying to install/run jenkins manually without pulling the Jenkins image from the docker-hub
for this exercise I have used the ubuntu image container and I did the following:
Install jdk-11 on the container
Set up the JAVA_HOME env variable
Install jenkins with apt-get
Run jenkins with the command service jenkins start
then status output is the following
root#42024442b87b:/# service jenkins status
Correct java version found
Jenkins Automation Server is running with the pid 89
Now I don't now how to access the jenkins server running in the container from my host.
thanks in advance
Docker containers are not reachable using the network from the host system by default. You need to expose a container's host, meaning that the port will be opened on the host machine and all traffic forwarded to the container.
Running docker with -p 8080:8080 forwards 8080. Take a look at the syntax here.
You can also specify which port on the host machine is supposed to be mapped to a container's port with something like -p 1234:8080.
You can also use the EXPOSE keyword in your Dockerfile.

Cannot set Debug to work for Java via Dockerized WebLogic, not with intelliJ nor Studio Code

I want to attach the Debugger to my deployed WARs in my dockerized WebLogic 12c.
I use this official image of WebLogic (which is a Linux container)
https://hub.docker.com/_/oracle-weblogic-server-12c
and I start the container using docker command:
docker run -d -p 4002:4002 -p 9002:9002
-v c:/my-path-to-shared-volume:/u01/oracle/properties
-e ADMINISTRATION_PORT_ENABLED=true -e DOMAIN_NAME=docker_domain
-e JAVA_TOOL_OPTIONS=\"-agentlib:jdwp=transport=dt_socket,address=4002,server=y,suspend=n\"
--name weblogic store/oracle/weblogic:12.2.1.3-dev-200109
The weblogic console comes alive at https://localhost:9002/console/ but when trying to run the debugger, my IDE says:
Unable to open debugger port (localhost:4002): java.io.IOException
"handshake failed - connection prematurally closed"
My OS is Windows10. I tried with Visual Studio Code and IntelliJ, and got the same output. The WARs run just fine and they respond when I use portman to hit some service endpoints.
What seems to happen is that weblogic start scripts inside the container tries to apply the Java Options param twice! Please see the relative parts of container output below:
Domain Home is: /u01/oracle/user_projects/domains/docker_domain
Picked up JAVA_TOOL_OPTIONS: "-agentlib:jdwp=transport=dt_socket,address=localhost:4002,server=y,suspend=n"
Listening for transport dt_socket at address: 4002
Initializing WebLogic Scripting Tool (WLST) ...
Welcome to WebLogic Server Administration Scripting Shell
[...](and further down in the logs I get: )
Starting WLS with line:
/usr/java/jdk-8/bin/java -server -Djava.security.egd=file:/dev/./urandom -cp /u01/oracle/wlserver/server/lib/weblogic-launcher.jar -Dlaunch.use.env.classpath=true -Dweblogic.Name=AdminServer -Djava.security.policy=/u01/oracle/wlserver/server/lib/weblogic.policy -Djava.system.class.loader=com.oracle.classloader.weblogic.LaunchClassLoader -javaagent:/u01/oracle/wlserver/server/lib/debugpatch-agent.jar -da -Dwls.home=/u01/oracle/wlserver/server -Dweblogic.home=/u01/oracle/wlserver/server weblogic.Server
Picked up JAVA_TOOL_OPTIONS: "-agentlib:jdwp=transport=dt_socket,address=localhost:4002,server=y,suspend=n"
ERROR: transport error 202: bind failed: Address already in use
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [debugInit.c:750]
Stopping Derby server...
Derby server stopped.
I then tried to work with docker-compose, creating a .yaml file to add my environmental props there, trying to prevent these from running twice. I got the exact same behavior. Whichever port I use, it is found Already in use.
This is my .yaml file
version: '2'
services:
weblogic:
container_name: weblogic_yamled
image: store/oracle/weblogic:12.2.1.3-dev-200109
ports:
- "7001:7001"
- "7002:7002"
- "4002:4002"
- "4003:4003"
- "9002:9002"
volumes:
- c:/my-path-to-shared-volume:/u01/oracle/properties
environment:
- ADMINISTRATION_PORT_ENABLED=true
- DOMAIN_NAME=docker_domain
- JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=localhost:4002"
Finally, I tried transport=dt_shmem but then I got a different error:
ERROR: transport library not found: dt_shmem
Do not know what else I should try!
Try adding address=*:4002 instead of address=4002
JAVA_OPTS is a Tomcat specific environment variable
In Java 8 the JDK supports a JAVA_TOOL_OPTIONS environment variable so to enable the debugger. Try replace JAVA_OPTS with JAVA_TOOL_OPTIONS
You also have to setup the address like this: address=*:8000, address=localhost:4002 or address=0.0.0.0:4002
I had a similar issue with attaching a memory monitoring tool (JVisualVM).
I could telnet to the server but that was not the whole story.
From what I have understood what was blocking me was the RMI connection used under the hoods. What was missing was a "tunnel" between client (where your debugger runs) and host (where your application runs) machine.
In windows you would open a cmd and give:
putty.exe -ssh <username>#<remote-host> -L <port>:<remote-host>:<same_port_again>
This will open a putty window which should remain open after logging in for the tunnel to remain open.
For more information on this, you can check here on the 2nd step of the solution provided by #freedev.
I am not sure if it works for you but I suspect it may be the same case as mine.
The problem is that the WebLogic server in the container is configured to run in production mode (the value of the PRODUCTION_MODE variable in the script setDomainEnv.sh is set to "true").
To disable this You need open the file setDomainEnv.sh, find PRODUCTION_MODE="true" and change it to PRODUCTION_MODE="false".
You also don't need to set JAVA_TOOL_OPTIONS variable, setDomainEnv.sh script already has the possibility to start in debug mode.
To enable the debug mode, the environment variable “debugFlag” needs to be set to true before executing the script.
Docker command:
docker run -d --name weblogic -p 7001:7001 -p 9002:9002 -p 55195:55195
-v c:/my-path:/u01/oracle/properties
-e ADMINISTRATION_PORT_ENABLED=true -e DOMAIN_NAME=base_domain
-e debugFlag=true -e DEBUG_PORT=55195
store/oracle/weblogic:12.2.1.3
Note, I also change the debug port to 55195.
Have you tried using the port number + 3 (4005) instead? That's a common practice to have a separate debug port for containerized applications

How to save docker container logs on the machine instead of in the container

I have some tests that i am running using docker-compose. The problem is that the docker logs are saved within the container (which makes debugging complicated).
I am looking for a way to configure docker-compose to save all logs on the machine where i am running the tests, instead of the container. Preferably some configuration of docker-compose.yml file, but i am open to any suggestion
It is not docker-compose, who saves your logs and has to be reconfigured. It is docker itself or your service, running inside that docker, depending on what logs do you mean.
If you are talking about docker logs, you should refer to docker log driver configuration page:
https://docs.docker.com/config/containers/logging/configure/
If you are talking about logs, produced by your services, just mount writable volume from your host pc into container, and configure your software to log into that folder.
You can achieve this like the following code does:
docker-compose.yml:
...
my-service:
image: xxx
entrypoint: ["sh", "-c", "echo 'Hello World!' > /path/inside/docker/some_log_file" ]
volumes:
- /path/on/host:/path/inside/docker
...
you service now should just log into /path/inside/docker/some_log_file.
On host machine you will see all these files in /path/on/host
I guess the scenario you are looking is you have docker containers scattered accross multiple host machines. so probably you need to make the docker container to the host machine volume and see if you can map the host volume to a share file system.
or write some scripts that are running on the docker host machines to copy the log files from a mapped docker volume on the docker host to a remote location of your choice using scp command etc.
or use some log aggregation frame works https://stackify.com/log-aggregation-101/

Unable to open debugger port through IntelliJ

I've got a server running on DigitalOcean and a JAR file that I want to debug. I first start the JAR on the remote server using
java -jar Server.jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
but on the console I see no output like "listening on port 5005...".
When I press debug in IntelliJ it says
unable to open debugger port (198.xxx.xxx.xx:5005):
java.net.ConnectException "Connection refused"
This is my IntelliJ configuration:
I also tried using -Xdebug but it still didn't work.
If I set suspend=y it should wait until a debugger is connected, but instead, it starts without problems.
The command to start the remote Java process in debug mode looks correct. If you don't see "Listening to Port blah" when you start the server JAR, then it might mean that the debug args are not being picked up. Another way to quickly check this would be to test with a telnet localhost 5005 on the machine where the server JAR is being executed. The telnet will fail if that port is not being used.
I suggest that you try the following, since the order of the parameters might be significant (I'll add some official evidence for this later):
java "agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" -jar Server.jar
this command worked for me:
export JAVA_OPTS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005'
by default idea remote dialog suggest:
'agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'
change it to:
'agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005'
and issues port 5005.
This command worked for me:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar Server.jar
Thanks to suifengpiao14 but I'm going to describe the problem a bit more in detail.
I checked multiple things, and at the end found the reason: actually as like as a restful service we want to be accessible from out of the server we are running it that we should set 0.0.0.0 as the nameserver, here we should do a similar one.
I checked the difference between the server from which I can remotely debug and the one which I can't. using netstat command:
for the server which I was ok with:
tcp 0 0 0.0.0.0:5005 0.0.0.0:* LISTEN 8323/java
for the server which I had problem with:
tcp 0 0 127.0.0.1:5005 0.0.0.0:* LISTEN 8323/java
So, using below jvm options should be helpful:
'agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005'
'agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005'
In my case it was because under settings -> build, execution, deployment -> debugger I had a built in server running on the same port as which I was trying to attach my debugger to for some reason.
For people like me who sometimes forget to read...
Copy and paste the arguments to the command line when JVM is started
says the Run/Debug Configuration in IntelliJ, directly under:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
Means:
Copy this line and go to your docker configuration. Add an environment variable (modify options dropdown). Paste it there with JAVA_OPTS= prepended.
Now when you did every correctly, you will have
Listening for transport dt_socket at address: 5005
and
Command line argument: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
This is who I solved it...
I've reproduced similar issue:
Unable to open debugger port (localhost:5005): java.net.ConnectException "Connection refused (Connection refused)"
I had it while running debugger w/ command line arguments for remote JVM using Run/Debug configurations:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
by attaching IDE with exposed debug agent server.
Since I've used Kubernetes cluster, the reason was:
once the pod has been created and was running as expected, I needed to proceed to set up port forwarding with the kubectl port-forward command, with the port to expose locally for traffic from the application before running debugger.
Based on kubectl port-forward syntax:
kubectl port-forward <resource-type/resource-name> [local_port]:<pod_port>
In format like:
kubectl port-forward <pod-name> -n <namespace> 5005:5005
or in a shorter form:
kubectl port-forward <pod-name> 5005:5005
The client listens on port 5000 locally and forwards to 5000 in the
pod.
Accordingly entrypoint.sh file of the service was configured w/ the following command for Kubernetes cluster:
java -Djava.security.egd.=file:/dev/./urandom -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -Xmx400m -jar /service.jar
As result, running port-forward before debugger solved the issue.
One of the reason is that the port is not enabled. You can try by enabling the port using the below command
firewall-cmd --zone=public --permanent --add-port=8001/tcp
Once the port is up, restart tomcat & try connecting again.
Hope it helps.
This might help someone That port in JVM debug is not your web app port

Spring boot on Aws ec2 instance

Spring boot demo app tried on localhost and successfully run the application. I even installed
gradle,jdk and other dependencies
easily on aws instance . Even though i ran ./gradlew bootRun of sample application successfully .
Like http:// localhost:8080 aws instane isn't working according to my path like http://myip:8080.
Let me know what exactly i am doing wrong with this and also to make sure i added custom tcp rule such as 8080 .
Besides adding custom tcp rule 8080, try to add the following rule into your security group.
Type: Custom ICMP Rule
Protocol: Echo Request
Port Range: N/A
Source: 0.0.0.0/0
And then try to ping YourIP in order to see if your EC2 machine can be reach from internet. If your EC2 ip is pingable, then I guess the reason why you cannot access http://myip:8080 is your spring boot failed to start in EC2.
You can ssh into your ec2 and investigate your jar. I don't know any clever method but my method is:
After ssh into the ec2 machine,
Find your jar name by ps -A -F . In my case I can find java -jar application.jar
Find your jar path by sudo find / -name application.jar . In my case I can find /var/app/current/application.jar
Then you can cd /var/app/current/ and java -jar application.jar . If you are lucky, you can find some hints from the spring boot log.
In order for this call to work there are a couple of prerequisites.I will try to make a short list, other things could arise depending on the environment.
Make sure the public IP address is the same as the one you know. This changes after each reboot. If you do not want this behavior you can use an elastic IP
The 8080 port is accessible from the Internet. Here are some steps to make sure this is the case: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/authorizing-access-to-an-instance.html

Categories