Get debug informations from docker container which runs a tomcat server - spring

First of all, sorry for my english :-)
Second, I want to run and debug my Spring application in a docker container. The container with the application starts up without any problem, I can reach the app from a browser.
I'm developing it in IntelliJ IDEA on Linux Mint and I would like to retrieve the debug informations from my container. But when I started the app in debug mode the IDEA tells me:
Cannot retrieve debug connection: java.net.MalformedURLException: unknown protocol: unix
Here's my Dockerfile:
FROM tomcat:8-jre8
RUN apt-get update -y && apt-get install -y \
curl \
vim
RUN rm -rfd /usr/local/tomcat/webapps/ROOT
RUN mkdir -p /usr/local/tomcat/conf/Catalina/localhost
RUN echo "<Context docBase=\"/usr/local/tomcat/webapps/ROOT\" path=\"\" reloadable=\"true\" />" >> /usr/local/tomcat/conf/Catalina/localhost/ROOT.xml
ENV JPDA_ADDRESS=8000
ENV JPDA_TRANSPORT=dt_socket
ENV JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,address=8000,suspend=n,server=y
EXPOSE 8000 8080
In the run configurations the port bindigs are correct, the app deploys successfully. Could someone help me? :-)

Related

Can't deploy spring application using WSL

The software I'm trying to deploy is https://github.com/gitbitex/gitbitex-new
To sum up, it works. But only on linux machines.
Here is the script I used (from github).
# start zookeeper
docker run -d --name zookeeper-server \
--network host \
-e ALLOW_ANONYMOUS_LOGIN=yes \
bitnami/zookeeper:latest
# start kafka
docker run -d --name kafka-server \
--network host \
-e ALLOW_PLAINTEXT_LISTENER=yes \
-e KAFKA_CFG_ZOOKEEPER_CONNECT=127.0.0.1:2181 \
bitnami/kafka:latest
# start redis
docker run -d --name redis-server \
--network=host \
redis
# start mysql
docker run -d --name mysql \
--network=host \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
# Please wait for MySQL to start before executing the following command
docker exec -it mysql mysql -uroot -p123456 -e "create database gitbitex;"
# start gitbitex
# open the browser and visit http://127.0.0.1/trade/BTC-USDT
docker run -d --name gitbitex \
--network=host \
greensheng/gitbitex
Firstly, I've tried to deploy it on vds using guide on github. And it worked without any problem.
Then I've tried to deploy it on my local machine which uses wsl with docker(integration is enabled) and it didn't work. Just can't load the webpage in browser. Curl from wsl also doesn't work, it says: connection refused.
Tried to deploy on a different linux machine, it worked again.
Tried different configuration using docker compose(cause this is what I'll need to do next). I've almost figured out how to setup it without network_mode: host but spring app itself throws exceptions anyway. With network_mode: host it doesn't work even on remote machine(but maybe it's my bad), but all containers are running properly, without errors.
It works on linux machine, but doesn't on Windows. As David Maze told in comments, it's because --network=host doesn't work on docker desktop.
I'll try instead to setup networking put everything into compose and make it work.
UPD: spent a lot of time trying to setup it without --network=host using docker compose and.. it still doesn't work on Windows. Docker destop is weird..

Spring Container on App Service takes a long time to start

I am trying to deploy a spring boot docker container on OpenJDK image into APP service on Azure. What baffles me is the time the web app takes on initial run (only during the initial run). I also see on the KUDU console that the container started up in less than 6 seconds but the APP service ran for more than 200 seconds and fails. Please see the attached screenshot. Has some one faced this issue before?
Edit 1: Adding the Docker File
FROM openjdk:11-jre-slim
LABEL Maintainer="Aravind"
VOLUME /tmp
ENV SSH_PASSWD "root:Docker!"
RUN echo "root:Docker!" | chpasswd
RUN apt-get update && apt-get install -y curl && apt-get install -y --no-install-recommends dialog && apt-get install -y --no-install-recommends openssh-server && apt install sudo
RUN useradd -m -d /home/spring spring && usermod -a -G spring spring
COPY sshd_config /etc/ssh/
RUN mkdir -p /tmp
COPY ssh_setup.sh /tmp
RUN chmod +x /tmp/ssh_setup.sh \
&& (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null)
COPY init.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/init.sh
EXPOSE 8000 2222
CMD ["/usr/sbin/sshd", "-D"]
USER spring:spring
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
EXPOSE 8080:8080
USER root:root
ENTRYPOINT ["init.sh"]
So after long research and help from MS support, Finally figured out the issue. As I said before, it is not related to how the container starts up as the container was starting up in less than 6 seconds.
The issue we noticed is that when the start up fails due to HTTP health-check timeout, the app is starting up with port 80 as the listening port. When it is successful, it starts up with port 8080.
Spring-Boot default listening port is 8080. The fix is to manually add the configuration for the APP service
App Setting Name: WEBSITES_PORT
Value: 8080
The above configuration seems to have fixed the issue and now the time to start is the time taken by the docker container within the app service.

Securing a localhost port for a Flask/Celery app running locally on 0.0.0.0 in Docker on MacOS

My app has a Flask backend and an Angular/Electron frontend. The app runs locally on Mac Catalina. Flask, Celery and Redis are in separate docker containers, while the frontend is outside Docker. The Flask container is listening on port 0.0.0.0:5078. I've set CORS policy to allow messages from "127.0.0.1:4200" only, sent by the frontend. There's no need for internet connections. The backend containers will be launched by the frontend by emulating a terminal command. I'll install the app remotely on non-technical users' Catalina MacBooks.
Question: According to Docker might be exposing ports to the world, Beware of exposing ports in Docker and Docker not blocked by macOS firewall, this use of 0.0.0.0:5078 is a security threat. How can I resolve this threat, eg by block ing any external connections to this port?
Here's some python 3.8 code
# imports: waitress, flask_cors, blueprint
cors = CORS(blueprint, resources={r"/*": {"origins":["http://127.0.0.1:4200"]}})
if __name__ == "__main__":
serve(flask_app, host= '0.0.0.0', port=5078, threads=8)
Here's the Dockerfile:
FROM python:3.8.3-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
ENV BUILD_DEPS="build-essential" \
APP_DEPS="curl libpq-dev"
RUN apt-get update \
&& apt-get install -y ${BUILD_DEPS} ${APP_DEPS} --no-install-recommends \
&& pip install --default-timeout=10000 -r requirements.txt
ARG FLASK_ENV="development"
ENV FLASK_ENV="${FLASK_ENV}" \
FLASK_APP="back5x.api.app" \
PYTHONUNBUFFERED="true"\
FLASK_DEBUG=1
COPY . .
RUN ["chmod", "+x", "/app/docker-entrypoint.sh"]
ENTRYPOINT ["/app/docker-entrypoint.sh"]
EXPOSE 5078
CMD ["python", "main.py"]
and the docker-compose:
version: "3.8"
services:
redis:
# ...
web:
build:
context: "."
args:
- "FLASK_ENV=development"
depends_on:
- "redis"
- "worker"
env_file:
- ".env"
environment:
FLASK_DEBUG: 1
FLASK_APP: back5x.api.app.py
healthcheck:
test: "${DOCKER_HEALTHCHECK_TEST:-curl localhost:5078/healthy}"
...
ports:
- "5078:5078"
restart: "unless-stopped"
volumes:
- ".:/app"
worker: #celery worker
...
volumes:
redis: {}
Tried:
The Docker-based solutions I've found use Linux iptables, eg Disallow egress from Docker containers on Docker for Mac and the above references. So I've added these to the Dockerfile:
RUN apt-get install -y iptables --no-install-recommends #after pip install
RUN iptables -N DOCKER-USER #after COPY . .
RUN iptables -I FORWARD -j DOCKER-USER
RUN iptables -A DOCKER-USER -j RETURN
RUN iptables -I DOCKER-USER -i eth0 ! -s 0.0.0.0 -j DROP
Without the middle three lines, I got an error that DOCKER-USER couldn't be found; with them, that I must run as a root. I've tried a privileged mode and app_cap, but as I'm new to Docker, I haven't got this to work.
I've also looked into defining a rule in Mac's PF firewall to block external connections to the port in question. However, this is not ideal for people who'll be using my app. A similar situation is with installing the paid-for "Little Snitch" app.
Before going this route, could there be a code or Docker-based solution? (Or perhaps there is an appropriate command for launching the backend?)
A working solution is based on the David Maze and Matt's comments and on this question. These are the steps:
Open Docker for Mac, Preferences and Docker Engine. Add "ip": "127.0.0.1" to the json config file.
In the docker-compose, set ports to "127.0.0.1:5078:5078" for the web service.
Leave the Dockerfile and the python code as before: ie, the flask host is still 0.0.0.0
As I checked, messages from Electron's localhost 4201 went through. Also, running netstat -anvp tcp | awk 'NR<3 || /LISTEN/ shows that the insecure port 0.0.0.0.5078 is no longer exposed to the outside.
`

Debugging Tomcat in Docker container

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"]

Not able to access Kibana running in a Docker container on port 5601

I have built a docker image with the following Docker file.
# gunicorn-flask
FROM devdb/kibana
MAINTAINER John Doe <user.name#gmail.com>
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get install -y python python-pip python-virtualenv gunicorn
# Setup flask application
RUN mkdir -p /deploy/app
COPY gunicorn_config.py /deploy/gunicorn_config.py
COPY app /deploy/app
RUN pip install -r /deploy/app/requirements.txt
WORKDIR /deploy/app
EXPOSE 5000 5601 9200
# Start gunicorn
CMD ["/usr/bin/gunicorn", "--config", "/deploy/gunicorn_config.py", "listener:app"]
I am running the container from the image created from this Docker file as follows.
sudo docker run -p 5601:5601 -p 9200:9200 -p 5000:5000 -v /home/Workspace/xits/config/elasticsearch.yml:/opt/elasticsearch/config/elasticsearch.yml -v /home/Workspace/xits/config/kibana.yml:/opt/kibana/config/kibana.yml es-kibana-gunicorn:latest
The issue I am facing is that I cannot access Kibana port 5601 on my host machine. My browser page says ERR_CONNECTION_REFUSED
I am able to access port 5000 though.
I can't figure out why this is.Any help would be greatly appreciated.
The parent Dockerfile devdb/kibana is using a script to start kibana and elasticsearch when the docker container is started. See CMD ["/sbin/my_init"] and the script itself.
When in your own Dockerfile you use the CMD instruction, you override the one from the parents Dockerfiles.
Since your CMD only starts gunicorn, elasticsearch and kibana won't ever be started. That's why there is no response on their respective network ports.
The Docker image you inherits from inherits itself from phusion/baseimage which has its own way of making multiple processes run in Docker containers. I recommend you follow the instructions on their README file to learn how to add your gunicorn to the list of services to start. Basically you would have to define a script named run and add it to your docker image within the /etc/service/<service name>/ directory.
In your Dockerfile, add:
COPY run /etc/service/gunicorn/
and the run script should be something similar to:
#!/bin/bash
cd /deploy/app
/usr/bin/gunicorn --config /deploy/gunicorn_config.py listener:app

Resources