Docker Community Forums

Share and learn in the Docker community.

Docker volume is not getting created for tomcat webapp, how to fix that?

I have created a dockerfile which copied the war file to tomcat folder.

FROM centos
EXPOSE 80
EXPOSE 443
EXPOSE 8080
RUN mkdir -p /usr/src/app
COPY apache-tomcat-9.0.37 /usr/src/app/apache-tomcat-9.0.37
COPY jdk8u302-b08-jre /usr/src/app/jdk8u302-b08-jre
COPY WAR/productSuite.war /usr/src/app/apache-tomcat-9.0.37/webapps/
ENV JAVA_HOME=/usr/src/app/jdk8u302-b08-jre
ENV CATALINA_HOME=/usr/src/app/apache-tomcat-9.0.37
ENV DOCKER_AUTHOR="Uday Kiran Reddy"
ENV PATH="${JAVA_HOME}/bin:${PATH}"

USER root
CMD ["/usr/src/app/apache-tomcat-9.0.37/bin/catalina.sh","run"]

The database.properties file is there in the subfolder of app: WEB-INF/Database
so I tried to mount it as volume to a sub folder but, the folder is not getting added any contents.
But the folder is not getting synced to it.

Even I tried creating a new Dockerfile with folder already extracted for WAR file.But the properties file in not mapping.

FROM centos
EXPOSE 80
EXPOSE 443
EXPOSE 8080
RUN mkdir -p /usr/src/app
COPY apache-tomcat-9.0.37 /usr/src/app/apache-tomcat-9.0.37
COPY jdk8u302-b08-jre /usr/src/app/jdk8u302-b08-jre
COPY WAR/productSuite /usr/src/app/apache-tomcat-9.0.37/webapps/productSuite
ENV JAVA_HOME=/usr/src/app/jdk8u302-b08-jre
ENV CATALINA_HOME=/usr/src/app/apache-tomcat-9.0.37
ENV DOCKER_AUTHOR="Uday Kiran Reddy"
ENV PATH="${JAVA_HOME}/bin:${PATH}"

USER root
CMD ["/usr/src/app/apache-tomcat-9.0.37/bin/catalina.sh","run"]

The command i tried.

docker run -it -p 80:8080 -v label:/usr/src/app/apache-tomcat-9.0.37/webapps/productSuite/WEB-INF/Database product:latest

So, it’s already in the image? (Like included in the WAR file, and included in WAR/productSuite for the test in which you expanded the WAR file manually?) What’s the problem you’re trying to solve?

How did you verify that?

(Somehow, I’m guessing you’re not using a volume but a bind mount, and want to see or change its contents from the host machine. But given the label in -v label:/usr/src/app/apache-tomcat-9.0.37/webapps/productSuite/WEB-INF/Database I assume it’s a true volume indeed. But I don’t understand what you’re trying to solve by using that volume.)

I am trying bind mount only. The label is the folder name.
In the label folder I kept database.properties file which should be replaced with the one in the image. But it is using the one in image only.

In this example label cannot be a bind mount. A bind mount would look like -v ./label:... or something similar that looks like a folder name and not just a label. With just label you will have created a volume, managed by Docker and not shared with a folder of your choice on the host. See also the result in docker volume inspect label.

(Aside, you can also use a bind mount for a single file.)

using ./label gave below error.

docker: Error response from daemon: create ./tested: “./tested” includes invalid characters for a local volume name, only “[a-zA-Z0-9][a-zA-Z0-9_.-]” are allowed. If you intended to pass a host directory, use absolute path.
See ‘docker run --help’.

So, tried like this.
docker run -it -v /home/ec2-user/testing/tested:/usr/src/app/apache-tomcat-9.0.37/webapps/productSuite/WEB-INF/Database -p 80:8080 product:2.0

Now, the empty folder tested is created on the host machine.
If I create any new file here , that is reflecting in the container immediately.
But, the database.properties is not saved in this folder.I thought it would be copied to the bind mount folder from the image(like in jenkins image) and I can edit that. But those files are not visible here.

Any setting I need to keep in dockerfile?
I already added this line as last 3rd line.

VOLUME /usr/src/app/apache-tomcat-9.0.37/webapps/productSuite/WEB-INF/database

No, that only happens for new empty volumes (which Docker manages), not for bind mounts. A bind mount will just replace the folder (or file) in the container with a folder (or file) from the host, simply ignoring what’s already in the container.

If it’s only about that single database.properties, and assuming you know what to put in there, I’d go with some -v /local/path/to/database.properties:/usr/src/app/apache-tomcat-9.0.37/webapps/productSuite/WEB-INF/Database/database.properties. Alternatively, use docker cp to copy the folder’s contents to your host before starting it with the bind mount?

Aside, I’ve no idea how Docker handles folders that may not exist yet. Like when Tomcat is expanding a WAR file and then creating folders for which a bind mount was defined before Tomcat was even started.

I’d remove that when using the bind mount.

Thank you, but this option available in jenkins image.

When I ran like this, it is copying the contents to the local folder mounted from the container.

Any possibility to implement similar here.?

Also, while creating the image itself, I am not copying the war file, instead I am copying the extract folder to webapps, so the folder will be available with image itself.

docker run -d --name=buildjobs -p 8081:8080 -p 51001:51001 --env JAVA_OPTS="-Djava.awt.headless=true -Dmail.smtp.starttls.enable=true -Dmail.smtp.starttls.enable=true -Dhudson.tasks.MailSender.SEND_TO_UNKNOWN_USERS=true -Djava.util.logging.config.file=/var/jenkins_home/log.properties -Dhudson.model.DirectoryBrowserSupport.CSP='' -Dhudson.model.DownloadService.noSignatureCheck=true" --env JENKINS_OPTS="--requestHeaderSize=16384" --mount type=bind,src=/home/ec2-user/buildjobs/data,dst=/var/jenkins_home jenkins/jenkins:lts

I’m quite sure that is something that the Jenkins image is doing for you, not Docker. For that to work, I guess you will see that /var/jenkins_home is empty in the original image (hence that the Jenkins image is storing its base contents somewhere else in the image, and copying that upon first run).

So, you could change catalina.sh (or define an ENTRYPOINT) to do something similar. For that, when creating the image, you’d also need to “back up” the original contents of /usr/src/app/apache-tomcat-9.0.37/webapps/ into some other location in the image (which is not affected by some runtime bind mount). Next, when starting the container, you could copy from that backup into /usr/src/app/apache-tomcat-9.0.37/webapps/ (maybe only if it’s empty), just in case the user of the container created a bind mount overriding that folder.

Alternatively, when using Linux, you may decide to access the Docker-managed volumes from the host directly. I have never done that (and the documentation says “Non-Docker processes should not modify this part of the filesystem”). But apparently that’s okay:

ok, I thought there would be a simple setting in docker.
Thanks for clearing this.

Also one more doubt, the database.properties contains only key value pairs.Is there anyway to pass them as parameters to the docker run so that it would update the file inside the container. Just want to see if this also supports.

Again not something Docker would do for you. Whether or not the WAR file that is running in Tomcat supports it, we cannot tell. If it can use environment variables then ENV or docker run -e may help.