Docker tomcat7 container cannot connect to host activemq - tomcat7

I am admittedly relatively new to using Docker for environment isolation, but I've run into a problem I am yet to solve, and I'm looking for some advice on how to proceed. Apologies if this is dirt simple.
I have an image built with this Dockerfile:
FROM java:7-jre
MAINTAINER me <email redacted>
ENV CATALINA_HOME="/usr/local/tomcat"
ENV PATH=$CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
#Add tomcat tarball with configs
#need to figure out if war files should be auto-deploy or manual-deploy via manager
ADD ./ $CATALINA_HOME
WORKDIR $CATALINA_HOME
RUN tar -xmvf tomcat.tar.gz --strip-components=1 \
&& rm bin/*.bat \
&& rm tomcat.tar.gz*
EXPOSE 8080
#quite possibly unnecessary to expose 61616
EXPOSE 61616
CMD catalina.sh run
Because my host is Mac OSX, I'm using the boot2docker package. The port forwarding is a real PITA, but for now I'm just binding host 8080 to container 8080 when I run the container (-p 8080:8080) and I have 8080 forwarded in the boot2docker networking setup.
This image runs a container just fine, and I am able to manually upload and deploy .war files to this container while it's running.
On my local machine, I am running ActiveMQ. Eventually I'll put this in a container but I need to get past this hurdle first. ActiveMQ is running with the default port 61616 listening, as shown in this netstat output:
14:14 $ netstat -a | grep 6161
tcp46 0 0 *.61616 *.* LISTEN
The problem I'm having is that deployed war files in my tomcat container are unable to talk to the physical host on 61616. Here is the actual error from the catalina.out log on the container (I added some line breaks to make it easier to read):
Could not refresh JMS Connection for destination 'request' - retrying in 5000 ms.
Cause: Error while attempting to add new Connection to the pool; nested exception is javax.jms.JMSException:
Could not connect to broker URL: tcp://localhost:61616.
Reason: java.net.ConnectException: Connection refused
Admittedly, I think it's because the war file is configured to use localhost:61616 to connect to AMQ -- it doesn't feel right for localhost inside the container to "work" reaching back to the host. I'm not sure what variable value I should set that to, or if that's even the actual issue. I would think that if it's a dynamically-allocated black-magic IP address, it'd be relatively painful to keep reconfiguring inside war files.
Corollary: are there other considerations I would need to make beyond this configuration if I wanted to link this tomcat container with an AMQ one?
Thanks in advance for your attention. ~P

First, you shouldn't need to EXPOSE 61616 on the container. (That would allow the container to listen on port 61616, which is not what you want.)
What you do need though is to access docker's localhost (your boot2docker VM) from within the docker container. The best way I've found to do this, so far, from this answer, is to run inside your docker container:
export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')
That is going to give you the IP address of your boot2docker VM, as seen from within the current docker container. I'll leave it up to you to figure out how to configure your JMS client to connect to that IP address, but one idea that comes to mind is something like:
echo $DOCKER_HOST_IP my-jms-hostname >> /etc/hosts
And then you can hardcode your JMS configuration to hit my-jms-hostname:61616
I recommend that you put the above two commands into a start script that you use to startup your application server in the container.
Next, you will need to find a way to tunnel that port on your boot2docker VM to your local host OS. For example, on your local host OS, run
boot2docker ssh -R61616:localhost:61616
That will listen on the remote (boot2docker VM's) port 61616 and forward it to your local host OS's localhost:61616, which is where ActiveMQ is hopefully listening happily for an incoming connection from your application server's JMS client.

Related

Connect to a MariaDB Docker Container in a own Docker network remotly

Hi what I am actually trying is to connect remotly from a MySQL Client in Windows Subsystem for Linux mysql -h 172.18.0.2 -P 3306 -u root -p and before that I started the Docker Container as follows: docker container run --name testdb --network testnetwork -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mysqlRootPassword -e MYSQL_DATABASE=localtestdb -d mariadb/server.
The purpose why I put the container in a own network, is because I also have a dockerized Spring Boot Application (GraphQL-Server) which shall communicated with this db. But always when I try to connect from my built-in mysql client, in my Windows Subsystem for Linux, with the above shown command. I got the error message: ERROR 2002 (HY000): Can't connect to MySQL server on '172.18.0.2' (115).
What I already tried, to solve the problem on my own is, look up whether the configuration file line (bind-address) is commented out. But it wont work. Interestingly it already worked to set up a docker container with MariaDB and connect from the outside, but now when I try exactly the same, only with the difference that I now put the container in a own existing network, it wont work.
Hopefully there some one out there which is able to help me with this annonying problem.
Thanks!
So far,
Daniel
//edit:
Now I tried the solution advice from a guy from this topic: How to configure containers in one network to connect to each other (server -> mysql)?. Futhermore I linked my Spring Boot (server) application with the "--link databaseContainerName" parameter to the MariaDB container.
Now I am able to start both containers without any error, but I am still not able to connect remotly to the MariaDB container. Which is now running in a virtual docker network with his own subnet.
I explored this recently - this is by design - container isolation. Usually only main (service httpd) host is accessible externally, hiding internal connections (hosts it communicates to deliver response).
Container created in own network is not accessible from external adresses, even from containers in the same bridge but other network (172.19.0.0/16).
Your container should be accessible on docker host address (127.0.0.1 if run locally) and mapped ("-p 3306:3306") port - 3306. But of course it won't work if many running db containers have the same mapping to the same host port.
Isolation is done using firewall - iptables. You can list rules (iptables -L) to see that - from docker host level.
You can modify firewall to allow external access to internal networks. I used this rule:
iptables -A DOCKER -d 172.16.0.0/12 -j ACCEPT
After that your MySQL containerized engine should be accessible using internal address 172.18.0.2 and source (not mapped) port 3306.
Warnings
it disables all isolation, dont't use it on production;
you have to run this after every docker start - rules created/modified by docker on the fly
not every docker container will respond on ping, check it from docker host (linux subsystem in this case) first, from windows cmd later
I used this option (in docker.service) to make rule permanent:
ExecStartPost=/bin/sh -c '/etc/iptables/accept172_16.sh'
For docker on external(shared in lan) host you should use route add (or hosts file on your machine or router) to forward 172.x.x.x addresses into lan docker host.
Hint: use portainer project (with restart policy - always) to manage docker containers. It's easier to see config errors, too.

Cannot connect to Container-optimized-os (running a spring-boot application using docker) using external ip

I have created a Google compute instance with Container-optimized-OS image.
I have configured the firewall to allow http and https.
I am using the docker image with spring boot application which connects to cloudsql. When I use run command on compute engine instance ssh, i.e. (docker run --rm name), the spring boot app is started successfully.
When I try to access the webservices through compute engine instance external ip, it is not working.
I went through a different question, and found that I should try using the sudo wget http://localhost command on the instance cli first and if it is good then everything should be good. But I am getting a connection refused message on 127.0.0.1:80.
I also tried the command to open port from Container optimized OS, I.E.
sudo iptables -w -A INPUT -p tcp --dport 80 -j ACCEPT , nothing is working.
The default port for Spring Boot is 8080 and not 80.
Run this command inside the instance container to see what ports are in LISTENING state:
sudo netstat -tulpn | grep LISTEN
You can redirect port 80 to port 8080 with this command:
sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
Note: This iptables command only redirects port 80 to 8080 on network interfaces. This has no effect for localhost or 127.0.0.1.
For Google Compute Engine instances you do not need to enable ports using iptables. This is done via Google VPC firewall rules. You can use both but make sure you understand exactly what you are configuring and the side effects.
Note: Your Spring Boot application needs to listen on 0.0.0.0 and not 127.0.0.1 nor localhost. The last two are internal only addresses. 0.0.0.0 means listen on all network interfaces.
Note: Do not use sudo in front of wget. This is not necessary.
First, confirm what port your springboot application uses - if it's 8080 or 80. This depends on what you have configured inside application.properties file. This port is referred to as ContainerPort in below steps.
Execute docker run <image-name>:<tag>. This will run the image and show container logs on the console. If there is something wrong with your spring-boot app, the logs will show that and the container will shutdown. Press Ctrl+C to stop the container and return to shell.
If there is no error in step 1 run docker run -d -p<HostPort>:<ContainerPort> <image-name>:<tag>. Here HostPort is any free port in your GCP host VM and ContainerPort is the port used by your spring boot application within the container. Option d starts your container in detached mode.
Run docker ps and make sure that the container started in step 2 is running. It may not run if there is an error - for example if the HostPort you specified is already in use.
If step 3 shows that the container is running, execute curl http://localhost:<HostPort>/<End-Point-Path>. Here End-Point-Path is a valid path to a working endpoint within the container. If the endpoint is correct you should see expected result from the spring-boot app in the console.
Navigate to Google Cloud Console -> VPC network -> Firewall rules and add a firewall rule to open HostPort on your GCP VM.
Access your endpoint via the VM's external IP with URL - http://<VM-External-IP>:<HostPort>/<End-Point-Path>
Unless there is an application issue with your spring-boot app these steps should get you going.
I was able to build the correct solution by your help (John Hanley and Cyac).
I am combining both solutions in order to help the next person facing this.
As told by John, by default Spring boot uses port 8080, not 80 and as specified by Cyac you need to specify the port as 80 explicitly in application.properties file using
server.port=80
Make sure you expose the port 80 in docker image
On GCP Contaier optimized OS make sure you have allowed traffic for HTTP and HTTPs
Run command:
sudo iptables -w -A INPUT -p tcp --dport 80 -j ACCEPT
Run docker using:
docker run -p 80:80 SPRING_IMAGE.
Where SPRING_IMAGE is the name of the docker image with spring boot build.
Test by using curl http://localhost/ENDPOINT_NAME , e.g. http://localhost/shops/all

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.

Can't access docker container on port 80 on OSX

In my current job we have development environment made with docker-compose.
One container is nginx, which provide routing to other containers.
Everything seems fine and work to my colleague on windows and osx. But on my system (osx El Capitan), there is problem with accessing nginx container on port 80.
There is setup of container from docker-compose.yml
nginx:
build: ./dockerbuild/nginx
ports:
- 80:80
links:
- php
volumes_from:
- app
... and more
In ./dockerbuild/nginx there is nothing special, just nginx config as we know it from everywhere.
When I run everyting with docker-compose create and docker-compose start. Then docker ps give me
3b296c1e4775 docker_nginx "nginx -g 'daemon off" About an hour ago Up 47 minutes 0.0.0.0:80->80/tcp, 443/tcp docker_nginx_1
But when I try to access it for example via curl I get error. curl: (7) Failed to connect to localhost port 80: Connection refused
I try to run container with port 81 and everything works fine.
Port is really binded to docker
22:47 $ sudo lsof -i -n -P | grep TCP
...
com.docke 14718 schovi 38u IPv4 0x6e9c93c51ec4b617 0t0 TCP *:80 (LISTEN)
...
Firewall in osx is turned off and I have no other security.
if you are using docker-for-mac:
Accessing by localhost:80 is correct, though you still have to ensure you do not have a local apache/nginx service running. Often leftovers from boxen/homebrew exist binding that port, because thats what developers did back then :)
if you are using dockertoolbox/virtualbox/whatever hypervisor
You will not be able to access it by localhost, by by the docker-machine ip, so write docker-machine ip default and the use http://$ip:80 in your browser
if that does not help
Ensure your nginx container actually does work, so connect to the container: docker exec -i -t <containerid> bash
and then run ps aux nginx or if telnet is installed try to connect to localhost
Solved!
Problem was, that long long time ago I installed pow (super simple automated rails server which run application on app_name.local domain). And this beast left LaunchAgent script which update pf to forward port 80 to pow port.
In my current job we have development environment made with docker-compose.
A privilege to use.
[W]hen I try to access [nginx on port 80] for example via curl I get error.
Given there's nothing from causing you from accessing docker on your host os you should look at the app running inside the container to ensure it's binding to the correct host, e.g. 0.0.0.0 and not localhost.
For example, if you're running Nuxt inside a container with nuxt-ts observe Nuxt will default to localhost thereby causing the container not to connect to the docker network whereas npx nuxt-ts -H 0.0.0.0 gets things squared away with the container's internal server connecting to the ip of the docker network used (verify ip like docker container inspect d8af01990363).

Docker: MacOSX Expose Container ports to host machine

In my job I working with docker and the option --net=host working like a charm forwarding the docker container ports to the machine. This allows me to adding grunt tasks that use certain ports by example:
A taks for serving my coverage report in a port 9001
A local deployed version of my app served in the port 9000
A watch live reload the port 35729
For Unit testing runner use the 9876 port
When I begin to use Docker in Mac, the first problem that i had was: The option --net=host don't work anymore.
I researched and I understand why this is not possible (Docker in Mac runs in a own virtual machine) and my momentary solution it's use the -p option for expose the ports, but this limit to me to add more and more task that use ports because i need run the explicit -p command for each port that i need expose.
Anyone with this same problem? How to dealing with this ?
Your issue is most probably that you are using dockertoolbox or dhingy/dlite or anything else providing a full-fledged linux VM, which then hosts docker to run your container inside this VM. This VM has, of course, its own network stack and own IP on the host, and thats were your tools will have issues with. The exposed ports of the container are not exposed to OSX host localhost, but rather OSX Docker-VM-ip.
To solve those issues elegantly
Expose ports to OSX localhost from the container
First, use/install docker-for-mac https://docs.docker.com/engine/installation/mac/ instead of dockertoolbox or others. Its based on a special xhyve stack which reuses your hosts network stack
when you now do docker run -p 3306:3306 percona it will bind 3306 on the osx-host-localhost, thus every other osx-tool trying to attach to localhost:3306 will work ( very useful ) just as you have been used to it when you installed mysql using brew install mysql or likewise
If you experience performance issues with code shares on OSX with docker containers, check http://docker-sync.io - it is compatible with docker-for-mac ( hint: i am biased on this one )
Export ports from the OSX-host to a containter
You do not really export anything in particular, you rather make them accessable as a whole from all containers ( all ports of the OSX-host-localhost)
If you want to attach to a port you offered on the OSX host, from within a container, e.g. during a xdebug session were your IDE listens on port 9000 on the OSX-host-localhost and the container running FPM/PHP should attach to this osx-localhost:9000 on the mac, you need to do this: https://gist.github.com/EugenMayer/3019516e5a3b3a01b6eac88190327e7c
So you create a dummy loopback ip, so you can access your OSX-host ports from without containers using 10.254.254.254:9000 - this is portable and basically gives you all you need to develop like you have used to
So one gives you the connectivity to container-exposed ports to apps running on the mac and trying to connect to localhost:port
And the second the inverse, if something in the container wants to attach to a port on the host.
One workaround, mentioned in "Bind container ports to the host" would be to use -P:
(or --publish-all=true|false) to docker run which is a blanket operation that identifies every port with an EXPOSE line in the image’s Dockerfile or --expose <port> commandline flag and maps it to a host port somewhere within an ephemeral port range.
The docker port command then needs to be used to inspect created mapping.
So if your app can use docker port <CONTAINER> to retrieve the mapped port, you can add as many containers as you want and get the mapped ports that way (without needed an "explicit -p command for each port").
Not sure if docker for mac can support bi-directional connection later https://forums.docker.com/t/will-docker-for-mac-support-bi-directional-connection-between-host-and-container-in-the-future/19871
I have two solution:
you can write a simple wrapper script and pass the port you want to expose to the script
use vagrant to start a virtual machine with network under control.

Resources